Compare commits

..

3 Commits

Author SHA1 Message Date
Anders Fugmann
e50e0b58f2 Kotlin: address PR review feedback
Align Kotlin 2.4 registrar plugin id with command-line processor, drop unused registrar state, fix the function-reference explanatory comment, and remove 1.x extractor targets from VERSIONS.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-11 13:35:05 +02:00
Anders Fugmann
a5d9f6e914 Kotlin: add extractor support for Kotlin 2.4.0
Add 2.4.0 compiler artifacts and API compatibility shims, including updated plugin registration and version-agnostic IR accessors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-11 09:27:45 +02:00
Anders Fugmann
eb843c5827 Kotlin: drop 1.x language support and move tests to 2.0
Kotlin 2.4.0 removes -language-version 1.9, so tests and support bounds move to 2.0.\n\nExpected output updates include pre-existing K2 differences in mixed Java/Kotlin scenarios, tracked in github/codeql-kotlin-team#196.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-11 09:27:21 +02:00
107 changed files with 959 additions and 1645 deletions

View File

@@ -1,208 +0,0 @@
name: Update Go version
on:
workflow_dispatch:
schedule:
- cron: "0 3 * * 1" # Run weekly on Mondays at 3 AM UTC (1 = Monday)
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')
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
# 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 | sed -E 's/^([0-9]+\.[0-9]+).*/\1/')
echo "major_minor=$LATEST_MAJOR_MINOR" >> $GITHUB_OUTPUT
- name: Check current Go version
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
# Extract major.minor version
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
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"
# Escape dots in current version strings for use in sed patterns
CURRENT_VERSION_ESCAPED=$(echo "$CURRENT_VERSION" | sed 's/\./\\./g')
CURRENT_MAJOR_MINOR_ESCAPED=$(echo "$CURRENT_MAJOR_MINOR" | sed 's/\./\\./g')
# 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
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
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
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
- 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_VERSION_NUM"
# Push changes
git push --force-with-lease 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_VERSION_NUM="${{ steps.fetch-version.outputs.version_num }}"
CURRENT_VERSION="${{ steps.current-version.outputs.version }}"
PR_TITLE="Go: Update to $LATEST_VERSION_NUM"
PR_BODY=$(cat <<EOF
This PR updates Go from $CURRENT_VERSION to $LATEST_VERSION_NUM.
Updated files:
- \`MODULE.bazel\` - go_sdk.download version
- \`go/extractor/go.mod\` - go directive and toolchain
- \`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).
EOF
)
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

View File

@@ -237,9 +237,6 @@ use_repo(
kotlin_extractor_deps, kotlin_extractor_deps,
"codeql_kotlin_defaults", "codeql_kotlin_defaults",
"codeql_kotlin_embeddable", "codeql_kotlin_embeddable",
"kotlin-compiler-1.8.0",
"kotlin-compiler-1.9.0-Beta",
"kotlin-compiler-1.9.20-Beta",
"kotlin-compiler-2.0.0-RC1", "kotlin-compiler-2.0.0-RC1",
"kotlin-compiler-2.0.20-Beta2", "kotlin-compiler-2.0.20-Beta2",
"kotlin-compiler-2.1.0-Beta1", "kotlin-compiler-2.1.0-Beta1",
@@ -248,9 +245,7 @@ use_repo(
"kotlin-compiler-2.2.20-Beta2", "kotlin-compiler-2.2.20-Beta2",
"kotlin-compiler-2.3.0", "kotlin-compiler-2.3.0",
"kotlin-compiler-2.3.20", "kotlin-compiler-2.3.20",
"kotlin-compiler-embeddable-1.8.0", "kotlin-compiler-2.4.0",
"kotlin-compiler-embeddable-1.9.0-Beta",
"kotlin-compiler-embeddable-1.9.20-Beta",
"kotlin-compiler-embeddable-2.0.0-RC1", "kotlin-compiler-embeddable-2.0.0-RC1",
"kotlin-compiler-embeddable-2.0.20-Beta2", "kotlin-compiler-embeddable-2.0.20-Beta2",
"kotlin-compiler-embeddable-2.1.0-Beta1", "kotlin-compiler-embeddable-2.1.0-Beta1",
@@ -259,9 +254,7 @@ use_repo(
"kotlin-compiler-embeddable-2.2.20-Beta2", "kotlin-compiler-embeddable-2.2.20-Beta2",
"kotlin-compiler-embeddable-2.3.0", "kotlin-compiler-embeddable-2.3.0",
"kotlin-compiler-embeddable-2.3.20", "kotlin-compiler-embeddable-2.3.20",
"kotlin-stdlib-1.8.0", "kotlin-compiler-embeddable-2.4.0",
"kotlin-stdlib-1.9.0-Beta",
"kotlin-stdlib-1.9.20-Beta",
"kotlin-stdlib-2.0.0-RC1", "kotlin-stdlib-2.0.0-RC1",
"kotlin-stdlib-2.0.20-Beta2", "kotlin-stdlib-2.0.20-Beta2",
"kotlin-stdlib-2.1.0-Beta1", "kotlin-stdlib-2.1.0-Beta1",
@@ -270,10 +263,11 @@ use_repo(
"kotlin-stdlib-2.2.20-Beta2", "kotlin-stdlib-2.2.20-Beta2",
"kotlin-stdlib-2.3.0", "kotlin-stdlib-2.3.0",
"kotlin-stdlib-2.3.20", "kotlin-stdlib-2.3.20",
"kotlin-stdlib-2.4.0",
) )
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
go_sdk.download(version = "1.26.4") go_sdk.download(version = "1.26.0")
go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
go_deps.from_file(go_mod = "//go/extractor:go.mod") go_deps.from_file(go_mod = "//go/extractor:go.mod")

View File

@@ -11,6 +11,10 @@
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll", "java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll" "csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll"
], ],
"Bound Java/C#": [
"java/ql/lib/semmle/code/java/dataflow/Bound.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/Bound.qll"
],
"ModulusAnalysis Java/C#": [ "ModulusAnalysis Java/C#": [
"java/ql/lib/semmle/code/java/dataflow/ModulusAnalysis.qll", "java/ql/lib/semmle/code/java/dataflow/ModulusAnalysis.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/ModulusAnalysis.qll" "csharp/ql/lib/semmle/code/csharp/dataflow/ModulusAnalysis.qll"

View File

@@ -9,7 +9,6 @@ dependencies:
codeql/controlflow: ${workspace} codeql/controlflow: ${workspace}
codeql/dataflow: ${workspace} codeql/dataflow: ${workspace}
codeql/mad: ${workspace} codeql/mad: ${workspace}
codeql/rangeanalysis: ${workspace}
codeql/ssa: ${workspace} codeql/ssa: ${workspace}
codeql/threat-models: ${workspace} codeql/threat-models: ${workspace}
codeql/tutorial: ${workspace} codeql/tutorial: ${workspace}

View File

@@ -4,31 +4,67 @@
overlay[local?] overlay[local?]
module; module;
private import csharp as CS private import internal.rangeanalysis.BoundSpecific
private import semmle.code.csharp.dataflow.SSA::Ssa
private import semmle.code.csharp.dataflow.internal.rangeanalysis.ConstantUtils as CU
private import semmle.code.csharp.dataflow.internal.rangeanalysis.RangeUtils as RU
private import semmle.code.csharp.dataflow.internal.rangeanalysis.SsaUtils as SU
private import codeql.rangeanalysis.Bound as SharedBound
/** Provides C#-specific definitions for bounds. */ private newtype TBound =
private module BoundDefs implements SharedBound::BoundDefinitions<CS::Location> { TBoundZero() or
class Type = CS::Type; TBoundSsa(SsaVariable v) { v.getSourceVariable().getType() instanceof IntegralType } or
TBoundExpr(Expr e) {
interestingExprBound(e) and
not exists(SsaVariable v | e = v.getAUse())
}
class SsaVariable = SU::SsaVariable; /**
* A bound that may be inferred for an expression plus/minus an integer delta.
*/
abstract class Bound extends TBound {
/** Gets a textual representation of this bound. */
abstract string toString();
class SsaSourceVariable = SourceVariable; /** Gets an expression that equals this bound plus `delta`. */
abstract Expr getExpr(int delta);
class Expr = CS::ControlFlowNodes::ExprNode; /** Gets an expression that equals this bound. */
Expr getExpr() { result = this.getExpr(0) }
class IntegralType = CS::IntegralType; /** Gets the location of this bound. */
abstract Location getLocation();
class ConstantIntegerExpr = CU::ConstantIntegerExpr;
/** Holds if `e` is a bound expression and it is not an SSA variable read. */
predicate interestingExprBound(Expr e) { CU::systemArrayLengthAccess(e.getExpr()) }
} }
module BoundImpl = SharedBound::Bound<CS::Location, BoundDefs>; /**
* The bound that corresponds to the integer 0. This is used to represent all
* integer bounds as bounds are always accompanied by an added integer delta.
*/
class ZeroBound extends Bound, TBoundZero {
override string toString() { result = "0" }
import BoundImpl override Expr getExpr(int delta) { result.(ConstantIntegerExpr).getIntValue() = delta }
override Location getLocation() { result.hasLocationInfo("", 0, 0, 0, 0) }
}
/**
* A bound corresponding to the value of an SSA variable.
*/
class SsaBound extends Bound, TBoundSsa {
/** Gets the SSA variable that equals this bound. */
SsaVariable getSsa() { this = TBoundSsa(result) }
override string toString() { result = this.getSsa().toString() }
override Expr getExpr(int delta) { result = this.getSsa().getAUse() and delta = 0 }
override Location getLocation() { result = this.getSsa().getLocation() }
}
/**
* A bound that corresponds to the value of a specific expression that might be
* interesting, but isn't otherwise represented by the value of an SSA variable.
*/
class ExprBound extends Bound, TBoundExpr {
override string toString() { result = this.getExpr().toString() }
override Expr getExpr(int delta) { this = TBoundExpr(result) and delta = 0 }
override Location getLocation() { result = this.getExpr().getLocation() }
}

View File

@@ -0,0 +1,22 @@
/**
* Provides C#-specific definitions for bounds.
*/
private import csharp as CS
private import semmle.code.csharp.dataflow.SSA::Ssa as Ssa
private import semmle.code.csharp.dataflow.internal.rangeanalysis.ConstantUtils as CU
private import semmle.code.csharp.dataflow.internal.rangeanalysis.RangeUtils as RU
private import semmle.code.csharp.dataflow.internal.rangeanalysis.SsaUtils as SU
class SsaVariable = SU::SsaVariable;
class Expr = CS::ControlFlowNodes::ExprNode;
class Location = CS::Location;
class IntegralType = CS::IntegralType;
class ConstantIntegerExpr = CU::ConstantIntegerExpr;
/** Holds if `e` is a bound expression and it is not an SSA variable read. */
predicate interestingExprBound(Expr e) { CU::systemArrayLengthAccess(e.getExpr()) }

View File

@@ -1,139 +0,0 @@
.. _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 <https://github.blog/tag/code-scanning/>`__, `relevant GitHub Changelog updates <https://github.blog/changelog/label/application-security/>`__, `changes in the CodeQL extension for Visual Studio Code <https://marketplace.visualstudio.com/items/GitHub.vscode-codeql/changelog>`__, and the `CodeQL Action changelog <https://github.com/github/codeql-action/blob/main/CHANGELOG.md>`__.
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 a 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 fewer false 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, 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
""""
* 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.

View File

@@ -11,7 +11,6 @@ A list of queries for each suite and language `is available here <https://docs.g
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
codeql-cli-2.25.6
codeql-cli-2.25.5 codeql-cli-2.25.5
codeql-cli-2.25.4 codeql-cli-2.25.4
codeql-cli-2.25.3 codeql-cli-2.25.3

View File

@@ -21,7 +21,7 @@
Java,"Java 7 to 26 [6]_","javac (OpenJDK and Oracle JDK), Java,"Java 7 to 26 [6]_","javac (OpenJDK and Oracle JDK),
Eclipse compiler for Java (ECJ) [7]_",``.java`` Eclipse compiler for Java (ECJ) [7]_",``.java``
Kotlin,"Kotlin 1.8.0 to 2.3.2\ *x*","kotlinc",``.kt`` Kotlin,"Kotlin 2.0.0 to 2.4.\ *x*","kotlinc",``.kt``
JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [8]_" JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [8]_"
Python [9]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13",Not applicable,``.py`` Python [9]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13",Not applicable,``.py``
Ruby [10]_,"up to 3.3",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``" Ruby [10]_,"up to 3.3",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``"

View File

@@ -4,7 +4,7 @@ inputs:
go-test-version: go-test-version:
description: Which Go version to use for running the tests description: Which Go version to use for running the tests
required: false required: false
default: "~1.26.4" default: "~1.26.0"
run-code-checks: run-code-checks:
description: Whether to run formatting, code and qhelp generation checks description: Whether to run formatting, code and qhelp generation checks
required: false required: false

View File

@@ -2,14 +2,14 @@ module github.com/github/codeql-go/extractor
go 1.26 go 1.26
toolchain go1.26.4 toolchain go1.26.0
// when updating this, run // when updating this, run
// bazel run @rules_go//go -- mod tidy // bazel run @rules_go//go -- mod tidy
// when adding or removing dependencies, run // when adding or removing dependencies, run
// bazel mod tidy // bazel mod tidy
require ( require (
golang.org/x/mod v0.37.0 golang.org/x/mod v0.36.0
golang.org/x/tools v0.45.0 golang.org/x/tools v0.45.0
) )

View File

@@ -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/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 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 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.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= 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/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 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=

View File

@@ -194,7 +194,7 @@ org.apache.hc.core5.http,73,2,45,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,72,,,,,,,,,,,
org.apache.hc.core5.net,,,18,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18, org.apache.hc.core5.net,,,18,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,
org.apache.hc.core5.util,,,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,6 org.apache.hc.core5.util,,,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,6
org.apache.hive.hcatalog.templeton,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,, org.apache.hive.hcatalog.templeton,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,
org.apache.http,53,3,117,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,51,,,,,,,,,,,,,,,,3,108,9 org.apache.http,48,3,95,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,46,,,,,,,,,,,,,,,,3,86,9
org.apache.ibatis.jdbc,6,,57,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,57, org.apache.ibatis.jdbc,6,,57,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,57,
org.apache.ibatis.mapping,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, org.apache.ibatis.mapping,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,
org.apache.log4j,11,,,,,,,,,,,,,,,,,,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, org.apache.log4j,11,,,,,,,,,,,,,,,,,,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
1 package sink source summary sink:bean-validation sink:command-injection sink:credentials-key sink:credentials-password sink:credentials-username sink:encryption-iv sink:encryption-salt sink:environment-injection sink:file-content-store sink:fragment-injection sink:groovy-injection sink:hostname-verification sink:html-injection sink:information-leak sink:intent-redirection sink:jexl-injection sink:jndi-injection sink:js-injection sink:ldap-injection sink:log-injection sink:mvel-injection sink:notification sink:ognl-injection sink:path-injection sink:path-injection[read] sink:pending-intents sink:regex-use sink:regex-use[-1] sink:regex-use[0] sink:regex-use[] sink:regex-use[f-1] sink:regex-use[f1] sink:regex-use[f] sink:request-forgery sink:response-splitting sink:sql-injection sink:template-injection sink:trust-boundary-violation sink:unsafe-deserialization sink:url-forward sink:url-redirection sink:xpath-injection sink:xslt-injection source:android-external-storage-dir source:commandargs source:contentprovider source:database source:environment source:file source:remote summary:taint summary:value
194 org.apache.hc.core5.net 18 18
195 org.apache.hc.core5.util 24 18 6
196 org.apache.hive.hcatalog.templeton 1 1
197 org.apache.http 53 48 3 117 95 2 51 46 3 108 86 9
198 org.apache.ibatis.jdbc 6 57 6 57
199 org.apache.ibatis.mapping 1 1
200 org.apache.log4j 11 11

View File

@@ -13,7 +13,7 @@ Java framework & library support
`Apache Commons IO <https://commons.apache.org/proper/commons-io/>`_,``org.apache.commons.io``,,570,124,105,,,,,15 `Apache Commons IO <https://commons.apache.org/proper/commons-io/>`_,``org.apache.commons.io``,,570,124,105,,,,,15
`Apache Commons Lang <https://commons.apache.org/proper/commons-lang/>`_,``org.apache.commons.lang3``,,425,7,,,,,, `Apache Commons Lang <https://commons.apache.org/proper/commons-lang/>`_,``org.apache.commons.lang3``,,425,7,,,,,,
`Apache Commons Text <https://commons.apache.org/proper/commons-text/>`_,``org.apache.commons.text``,,272,,,,,,, `Apache Commons Text <https://commons.apache.org/proper/commons-text/>`_,``org.apache.commons.text``,,272,,,,,,,
`Apache HttpComponents <https://hc.apache.org/>`_,"``org.apache.hc.core5.*``, ``org.apache.http``",5,205,127,,3,,,,124 `Apache HttpComponents <https://hc.apache.org/>`_,"``org.apache.hc.core5.*``, ``org.apache.http``",5,183,122,,3,,,,119
`Apache Log4j 2 <https://logging.apache.org/log4j/2.0/>`_,``org.apache.logging.log4j``,,8,359,,,,,, `Apache Log4j 2 <https://logging.apache.org/log4j/2.0/>`_,``org.apache.logging.log4j``,,8,359,,,,,,
`Apache Struts <https://struts.apache.org/>`_,"``org.apache.struts2``, ``org.apache.struts.beanvalidation.validation.interceptor``",,3877,14,,,,,, `Apache Struts <https://struts.apache.org/>`_,"``org.apache.struts2``, ``org.apache.struts.beanvalidation.validation.interceptor``",,3877,14,,,,,,
`Apache Velocity <https://velocity.apache.org/>`_,"``org.apache.velocity.app``, ``org.apache.velocity.runtime``",,,8,,,,,, `Apache Velocity <https://velocity.apache.org/>`_,"``org.apache.velocity.app``, ``org.apache.velocity.runtime``",,,8,,,,,,
@@ -41,5 +41,5 @@ Java framework & library support
`Thymeleaf <https://www.thymeleaf.org/>`_,``org.thymeleaf``,,2,2,,,,,, `Thymeleaf <https://www.thymeleaf.org/>`_,``org.thymeleaf``,,2,2,,,,,,
`jOOQ <https://www.jooq.org/>`_,``org.jooq``,,,1,,,1,,, `jOOQ <https://www.jooq.org/>`_,``org.jooq``,,,1,,,1,,,
Others,"``actions.osgi``, ``antlr``, ``ch.ethz.ssh2``, ``cn.hutool.core.codec``, ``com.alibaba.com.caucho.hessian.io``, ``com.alibaba.druid.sql``, ``com.alibaba.fastjson2``, ``com.amazonaws.auth``, ``com.auth0.jwt.algorithms``, ``com.azure.identity``, ``com.caucho.burlap.io``, ``com.caucho.hessian.io``, ``com.cedarsoftware.util.io``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.esotericsoftware.yamlbeans``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.microsoft.sqlserver.jdbc``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2``, ``com.sshtools.j2ssh.authentication``, ``com.sun.crypto.provider``, ``com.sun.jndi.ldap``, ``com.sun.net.httpserver``, ``com.sun.net.ssl``, ``com.sun.rowset``, ``com.sun.security.auth.module``, ``com.sun.security.ntlm``, ``com.sun.security.sasl.digest``, ``com.thoughtworks.xstream``, ``com.trilead.ssh2``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``hudson``, ``io.jsonwebtoken``, ``io.undertow.server.handlers.resource``, ``javafx.scene.web``, ``jenkins``, ``jodd.json``, ``liquibase.database.jvm``, ``liquibase.statement.core``, ``net.lingala.zip4j``, ``net.schmizz.sshj``, ``net.sf.json``, ``net.sf.saxon.s9api``, ``ognl``, ``org.acegisecurity``, ``org.antlr.runtime``, ``org.apache.avro``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.exec``, ``org.apache.commons.fileupload``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.lang``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.cxf.catalog``, ``org.apache.cxf.common.classloader``, ``org.apache.cxf.common.jaxb``, ``org.apache.cxf.common.logging``, ``org.apache.cxf.configuration.jsse``, ``org.apache.cxf.helpers``, ``org.apache.cxf.resource``, ``org.apache.cxf.staxutils``, ``org.apache.cxf.tools.corba.utils``, ``org.apache.cxf.tools.util``, ``org.apache.cxf.transform``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hadoop.hive.ql.exec``, ``org.apache.hadoop.hive.ql.metadata``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.ibatis.mapping``, ``org.apache.log4j``, ``org.apache.shiro.authc``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.shiro.mgt``, ``org.apache.sshd.client.session``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.codehaus.cargo.container.installer``, ``org.dom4j``, ``org.exolab.castor.xml``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.gradle.api.file``, ``org.ho.yaml``, ``org.influxdb``, ``org.jabsorb``, ``org.jboss.vfs``, ``org.jdbi.v3.core``, ``org.jenkins.ui.icon``, ``org.jenkins.ui.symbol``, ``org.keycloak.models.map.storage``, ``org.kohsuke.stapler``, ``org.lastaflute.web``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.owasp.esapi``, ``org.pac4j.jwt.config.encryption``, ``org.pac4j.jwt.config.signature``, ``org.scijava.log``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``software.amazon.awssdk.transfer.s3.model``, ``sun.jvmstat.perfdata.monitor.protocol.local``, ``sun.jvmstat.perfdata.monitor.protocol.rmi``, ``sun.misc``, ``sun.net.ftp``, ``sun.net.www.protocol.http``, ``sun.security.acl``, ``sun.security.jgss.krb5``, ``sun.security.krb5``, ``sun.security.pkcs``, ``sun.security.pkcs11``, ``sun.security.provider``, ``sun.security.ssl``, ``sun.security.x509``, ``sun.tools.jconsole``",127,6034,775,148,6,14,18,,186 Others,"``actions.osgi``, ``antlr``, ``ch.ethz.ssh2``, ``cn.hutool.core.codec``, ``com.alibaba.com.caucho.hessian.io``, ``com.alibaba.druid.sql``, ``com.alibaba.fastjson2``, ``com.amazonaws.auth``, ``com.auth0.jwt.algorithms``, ``com.azure.identity``, ``com.caucho.burlap.io``, ``com.caucho.hessian.io``, ``com.cedarsoftware.util.io``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.esotericsoftware.yamlbeans``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.microsoft.sqlserver.jdbc``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2``, ``com.sshtools.j2ssh.authentication``, ``com.sun.crypto.provider``, ``com.sun.jndi.ldap``, ``com.sun.net.httpserver``, ``com.sun.net.ssl``, ``com.sun.rowset``, ``com.sun.security.auth.module``, ``com.sun.security.ntlm``, ``com.sun.security.sasl.digest``, ``com.thoughtworks.xstream``, ``com.trilead.ssh2``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``hudson``, ``io.jsonwebtoken``, ``io.undertow.server.handlers.resource``, ``javafx.scene.web``, ``jenkins``, ``jodd.json``, ``liquibase.database.jvm``, ``liquibase.statement.core``, ``net.lingala.zip4j``, ``net.schmizz.sshj``, ``net.sf.json``, ``net.sf.saxon.s9api``, ``ognl``, ``org.acegisecurity``, ``org.antlr.runtime``, ``org.apache.avro``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.exec``, ``org.apache.commons.fileupload``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.lang``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.cxf.catalog``, ``org.apache.cxf.common.classloader``, ``org.apache.cxf.common.jaxb``, ``org.apache.cxf.common.logging``, ``org.apache.cxf.configuration.jsse``, ``org.apache.cxf.helpers``, ``org.apache.cxf.resource``, ``org.apache.cxf.staxutils``, ``org.apache.cxf.tools.corba.utils``, ``org.apache.cxf.tools.util``, ``org.apache.cxf.transform``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hadoop.hive.ql.exec``, ``org.apache.hadoop.hive.ql.metadata``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.ibatis.mapping``, ``org.apache.log4j``, ``org.apache.shiro.authc``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.shiro.mgt``, ``org.apache.sshd.client.session``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.codehaus.cargo.container.installer``, ``org.dom4j``, ``org.exolab.castor.xml``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.gradle.api.file``, ``org.ho.yaml``, ``org.influxdb``, ``org.jabsorb``, ``org.jboss.vfs``, ``org.jdbi.v3.core``, ``org.jenkins.ui.icon``, ``org.jenkins.ui.symbol``, ``org.keycloak.models.map.storage``, ``org.kohsuke.stapler``, ``org.lastaflute.web``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.owasp.esapi``, ``org.pac4j.jwt.config.encryption``, ``org.pac4j.jwt.config.signature``, ``org.scijava.log``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``software.amazon.awssdk.transfer.s3.model``, ``sun.jvmstat.perfdata.monitor.protocol.local``, ``sun.jvmstat.perfdata.monitor.protocol.rmi``, ``sun.misc``, ``sun.net.ftp``, ``sun.net.www.protocol.http``, ``sun.security.acl``, ``sun.security.jgss.krb5``, ``sun.security.krb5``, ``sun.security.pkcs``, ``sun.security.pkcs11``, ``sun.security.provider``, ``sun.security.ssl``, ``sun.security.x509``, ``sun.tools.jconsole``",127,6034,775,148,6,14,18,,186
Totals,,382,26403,2707,421,16,137,33,1,415 Totals,,382,26381,2702,421,16,137,33,1,410

View File

@@ -64,8 +64,14 @@ _resources = [
r[len("src/main/resources/"):], r[len("src/main/resources/"):],
) )
for r in glob(["src/main/resources/**"]) for r in glob(["src/main/resources/**"])
if r != "src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar"
] ]
_compiler_plugin_registrar_service = (
"src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar",
"META-INF/services/org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar",
)
kt_javac_options( kt_javac_options(
name = "javac-options", name = "javac-options",
release = "8", release = "8",
@@ -91,19 +97,32 @@ kt_javac_options(
# * `resource_strip_prefix` is unique per jar, so we must also put other resources under the same version prefix # * `resource_strip_prefix` is unique per jar, so we must also put other resources under the same version prefix
genrule( genrule(
name = "resources-%s" % v, name = "resources-%s" % v,
srcs = [src for src, _ in _resources], srcs = [src for src, _ in _resources] + (
[_compiler_plugin_registrar_service[0]] if not version_less(v, "2.4.0") else []
),
outs = [ outs = [
"%s/com/github/codeql/extractor.name" % v, "%s/com/github/codeql/extractor.name" % v,
] + [ ] + [
"%s/%s" % (v, target) "%s/%s" % (v, target)
for _, target in _resources for _, target in _resources
], ] + (
["%s/%s" % (
v,
_compiler_plugin_registrar_service[1],
)] if not version_less(v, "2.4.0") else []
),
cmd = "\n".join([ cmd = "\n".join([
"echo %s-%s > $(RULEDIR)/%s/com/github/codeql/extractor.name" % (_extractor_name_prefix, v, v), "echo %s-%s > $(RULEDIR)/%s/com/github/codeql/extractor.name" % (_extractor_name_prefix, v, v),
] + [ ] + [
"cp $(execpath %s) $(RULEDIR)/%s/%s" % (source, v, target) "cp $(execpath %s) $(RULEDIR)/%s/%s" % (source, v, target)
for source, target in _resources for source, target in _resources
]), ] + (
["cp $(execpath %s) $(RULEDIR)/%s/%s" % (
_compiler_plugin_registrar_service[0],
v,
_compiler_plugin_registrar_service[1],
)] if not version_less(v, "2.4.0") else []
)),
), ),
kt_jvm_library( kt_jvm_library(
name = "%s-%s" % (_extractor_name_prefix, v), name = "%s-%s" % (_extractor_name_prefix, v),

BIN
java/kotlin-extractor/deps/kotlin-compiler-2.4.0.jar (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

BIN
java/kotlin-extractor/deps/kotlin-stdlib-2.4.0.jar (Stored with Git LFS) Normal file

Binary file not shown.

View File

@@ -27,7 +27,7 @@ import shutil
import io import io
import os import os
DEFAULT_VERSION = "2.3.20" DEFAULT_VERSION = "2.4.0"
def options(): def options():

View File

@@ -3,32 +3,21 @@
package com.github.codeql package com.github.codeql
import com.intellij.mock.MockProject
import com.intellij.openapi.extensions.LoadingOrder
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
class KotlinExtractorComponentRegistrar : Kotlin2ComponentRegistrar() { class KotlinExtractorComponentRegistrar : Kotlin2ComponentRegistrar() {
override fun registerProjectComponents( override fun doRegisterExtensions(configuration: CompilerConfiguration) {
project: MockProject,
configuration: CompilerConfiguration
) {
val invocationTrapFile = configuration[KEY_INVOCATION_TRAP_FILE] val invocationTrapFile = configuration[KEY_INVOCATION_TRAP_FILE]
if (invocationTrapFile == null) { if (invocationTrapFile == null) {
throw Exception("Required argument for TRAP invocation file not given") throw Exception("Required argument for TRAP invocation file not given")
} }
// Register with LoadingOrder.LAST to ensure the extractor runs after other registerExtractorExtension(
// IR generation plugins (like kotlinx.serialization) have generated their code.
val extensionPoint = project.extensionArea.getExtensionPoint(IrGenerationExtension.extensionPointName)
extensionPoint.registerExtension(
KotlinExtractorExtension( KotlinExtractorExtension(
invocationTrapFile, invocationTrapFile,
configuration[KEY_CHECK_TRAP_IDENTICAL] ?: false, configuration[KEY_CHECK_TRAP_IDENTICAL] ?: false,
configuration[KEY_COMPILATION_STARTTIME], configuration[KEY_COMPILATION_STARTTIME],
configuration[KEY_EXIT_AFTER_EXTRACTION] ?: false configuration[KEY_EXIT_AFTER_EXTRACTION] ?: false
), )
LoadingOrder.LAST,
project
) )
} }
} }

View File

@@ -173,9 +173,9 @@ open class KotlinFileExtractor(
when (d) { when (d) {
is IrFunction -> is IrFunction ->
when (d.name.asString()) { when (d.name.asString()) {
"toString" -> d.valueParameters.isEmpty() "toString" -> d.codeQlValueParameters.isEmpty()
"hashCode" -> d.valueParameters.isEmpty() "hashCode" -> d.codeQlValueParameters.isEmpty()
"equals" -> d.valueParameters.singleOrNull()?.type?.isNullableAny() ?: false "equals" -> d.codeQlValueParameters.singleOrNull()?.type?.isNullableAny() ?: false
else -> false else -> false
} && isJavaBinaryDeclaration(d) } && isJavaBinaryDeclaration(d)
else -> false else -> false
@@ -721,7 +721,7 @@ open class KotlinFileExtractor(
(it.type as? IrSimpleType)?.classFqName?.asString() != "kotlin.Deprecated" (it.type as? IrSimpleType)?.classFqName?.asString() != "kotlin.Deprecated"
} + } +
// Note we lose any arguments to @java.lang.Deprecated that were written in source. // Note we lose any arguments to @java.lang.Deprecated that were written in source.
IrConstructorCallImpl.fromSymbolOwner( codeQlAnnotationFromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
jldConstructor.returnType, jldConstructor.returnType,
@@ -781,13 +781,13 @@ open class KotlinFileExtractor(
val locId = tw.getLocation(constructorCall) val locId = tw.getLocation(constructorCall)
tw.writeHasLocation(id, locId) tw.writeHasLocation(id, locId)
for (i in 0 until constructorCall.valueArgumentsCount) { for (i in 0 until constructorCall.codeQlValueArgumentsCount) {
val param = constructorCall.symbol.owner.valueParameters[i] val param = constructorCall.symbol.owner.codeQlValueParameters[i]
val prop = val prop =
constructorCall.symbol.owner.parentAsClass.declarations constructorCall.symbol.owner.parentAsClass.declarations
.filterIsInstance<IrProperty>() .filterIsInstance<IrProperty>()
.first { it.name == param.name } .first { it.name == param.name }
val v = constructorCall.getValueArgument(i) ?: param.defaultValue?.expression val v = constructorCall.codeQlGetValueArgument(i) ?: param.defaultValue?.expression
val getter = prop.getter val getter = prop.getter
if (getter == null) { if (getter == null) {
logger.warnElement("Expected annotation property to define a getter", prop) logger.warnElement("Expected annotation property to define a getter", prop)
@@ -1115,9 +1115,9 @@ open class KotlinFileExtractor(
returnId, returnId,
0, 0,
returnId, returnId,
f.valueParameters.size, f.codeQlValueParameters.size,
{ argParent, idxOffset -> { argParent, idxOffset ->
f.valueParameters.forEachIndexed { idx, param -> f.codeQlValueParameters.forEachIndexed { idx, param ->
val syntheticParamId = useValueParameter(param, proxyFunctionId) val syntheticParamId = useValueParameter(param, proxyFunctionId)
extractVariableAccess( extractVariableAccess(
syntheticParamId, syntheticParamId,
@@ -1695,9 +1695,9 @@ open class KotlinFileExtractor(
returnId, returnId,
0, 0,
returnId, returnId,
f.valueParameters.size, f.codeQlValueParameters.size,
{ argParentId, idxOffset -> { argParentId, idxOffset ->
f.valueParameters.mapIndexed { idx, param -> f.codeQlValueParameters.mapIndexed { idx, param ->
val syntheticParamId = useValueParameter(param, functionId) val syntheticParamId = useValueParameter(param, functionId)
extractVariableAccess( extractVariableAccess(
syntheticParamId, syntheticParamId,
@@ -1792,7 +1792,7 @@ open class KotlinFileExtractor(
extractBody: Boolean, extractBody: Boolean,
extractMethodAndParameterTypeAccesses: Boolean extractMethodAndParameterTypeAccesses: Boolean
) { ) {
if (f.valueParameters.none { it.defaultValue != null }) return if (f.codeQlValueParameters.none { it.defaultValue != null }) return
val id = getDefaultsMethodLabel(f) val id = getDefaultsMethodLabel(f)
if (id == null) { if (id == null) {
@@ -1800,7 +1800,7 @@ open class KotlinFileExtractor(
return return
} }
val locId = getLocation(f, null) val locId = getLocation(f, null)
val extReceiver = f.extensionReceiverParameter val extReceiver = f.codeQlExtensionReceiverParameter
val dispatchReceiver = if (f.shouldExtractAsStatic) null else f.dispatchReceiverParameter val dispatchReceiver = if (f.shouldExtractAsStatic) null else f.dispatchReceiverParameter
val parameterTypes = getDefaultsMethodArgTypes(f) val parameterTypes = getDefaultsMethodArgTypes(f)
val allParamTypeResults = val allParamTypeResults =
@@ -1869,7 +1869,7 @@ open class KotlinFileExtractor(
tw.writeCompiler_generated(id, CompilerGeneratedKinds.DEFAULT_ARGUMENTS_METHOD.kind) tw.writeCompiler_generated(id, CompilerGeneratedKinds.DEFAULT_ARGUMENTS_METHOD.kind)
if (extractBody) { if (extractBody) {
val nonSyntheticParams = listOfNotNull(dispatchReceiver) + f.valueParameters val nonSyntheticParams = listOfNotNull(dispatchReceiver) + f.codeQlValueParameters
// This stack entry represents as if we're extracting the 'real' function `f`, giving // This stack entry represents as if we're extracting the 'real' function `f`, giving
// the indices of its non-synthetic parameters // the indices of its non-synthetic parameters
// such that when we extract the default expressions below, any reference to f's nth // such that when we extract the default expressions below, any reference to f's nth
@@ -1895,12 +1895,12 @@ open class KotlinFileExtractor(
val realParamsVarId = getValueParameterLabel(id, parameterTypes.size - 2) val realParamsVarId = getValueParameterLabel(id, parameterTypes.size - 2)
val intType = pluginContext.irBuiltIns.intType val intType = pluginContext.irBuiltIns.intType
val paramIdxOffset = val paramIdxOffset =
listOf(dispatchReceiver, f.extensionReceiverParameter).count { it != null } listOf(dispatchReceiver, f.codeQlExtensionReceiverParameter).count { it != null }
extractBlockBody(id, locId).also { blockId -> extractBlockBody(id, locId).also { blockId ->
var nextStmt = 0 var nextStmt = 0
// For each parameter with a default, sub in the default value if the caller // For each parameter with a default, sub in the default value if the caller
// hasn't supplied a value: // hasn't supplied a value:
f.valueParameters.forEachIndexed { paramIdx, param -> f.codeQlValueParameters.forEachIndexed { paramIdx, param ->
val defaultVal = param.defaultValue val defaultVal = param.defaultValue
if (defaultVal != null) { if (defaultVal != null) {
extractIfStmt(locId, blockId, nextStmt++, id).also { ifId -> extractIfStmt(locId, blockId, nextStmt++, id).also { ifId ->
@@ -1975,7 +1975,7 @@ open class KotlinFileExtractor(
id id
) )
tw.writeHasLocation(thisCallId, locId) tw.writeHasLocation(thisCallId, locId)
f.valueParameters.forEachIndexed { idx, param -> f.codeQlValueParameters.forEachIndexed { idx, param ->
extractVariableAccess( extractVariableAccess(
tw.getLabelFor<DbParam>(getValueParameterLabel(id, idx)), tw.getLabelFor<DbParam>(getValueParameterLabel(id, idx)),
param.type, param.type,
@@ -2003,9 +2003,9 @@ open class KotlinFileExtractor(
) )
.also { thisCallId -> .also { thisCallId ->
val realFnIdxOffset = val realFnIdxOffset =
if (f.extensionReceiverParameter != null) 1 else 0 if (f.codeQlExtensionReceiverParameter != null) 1 else 0
val paramMappings = val paramMappings =
f.valueParameters.mapIndexed { idx, param -> f.codeQlValueParameters.mapIndexed { idx, param ->
Triple( Triple(
param.type, param.type,
idx + paramIdxOffset, idx + paramIdxOffset,
@@ -2156,7 +2156,7 @@ open class KotlinFileExtractor(
val dispatchReceiver = val dispatchReceiver =
f.dispatchReceiverParameter?.let { IrGetValueImpl(-1, -1, it.symbol) } f.dispatchReceiverParameter?.let { IrGetValueImpl(-1, -1, it.symbol) }
val extensionReceiver = val extensionReceiver =
f.extensionReceiverParameter?.let { IrGetValueImpl(-1, -1, it.symbol) } f.codeQlExtensionReceiverParameter?.let { IrGetValueImpl(-1, -1, it.symbol) }
extractExpressionBody(overloadId, realFunctionLocId).also { returnId -> extractExpressionBody(overloadId, realFunctionLocId).also { returnId ->
extractsDefaultsCall( extractsDefaultsCall(
@@ -2180,28 +2180,28 @@ open class KotlinFileExtractor(
if (!f.hasAnnotation(jvmOverloadsFqName)) { if (!f.hasAnnotation(jvmOverloadsFqName)) {
if ( if (
f is IrConstructor && f is IrConstructor &&
f.valueParameters.isNotEmpty() && f.codeQlValueParameters.isNotEmpty() &&
f.valueParameters.all { it.defaultValue != null } && f.codeQlValueParameters.all { it.defaultValue != null } &&
f.parentClassOrNull?.let { f.parentClassOrNull?.let {
// Don't create a default constructor for an annotation class, or a class // Don't create a default constructor for an annotation class, or a class
// that explicitly declares a no-arg constructor. // that explicitly declares a no-arg constructor.
!it.isAnnotationClass && !it.isAnnotationClass &&
it.declarations.none { d -> it.declarations.none { d ->
d is IrConstructor && d.valueParameters.isEmpty() d is IrConstructor && d.codeQlValueParameters.isEmpty()
} }
} == true } == true
) { ) {
// Per https://kotlinlang.org/docs/classes.html#creating-instances-of-classes, a // Per https://kotlinlang.org/docs/classes.html#creating-instances-of-classes, a
// single default overload gets created specifically // single default overload gets created specifically
// when we have all default parameters, regardless of `@JvmOverloads`. // when we have all default parameters, regardless of `@JvmOverloads`.
extractGeneratedOverload(f.valueParameters.map { _ -> null }) extractGeneratedOverload(f.codeQlValueParameters.map { _ -> null })
} }
return return
} }
val paramList: MutableList<IrValueParameter?> = f.valueParameters.toMutableList() val paramList: MutableList<IrValueParameter?> = f.codeQlValueParameters.toMutableList()
for (n in (f.valueParameters.size - 1) downTo 0) { for (n in (f.codeQlValueParameters.size - 1) downTo 0) {
if (f.valueParameters[n].defaultValue != null) { if (f.codeQlValueParameters[n].defaultValue != null) {
paramList[n] = null // Remove this parameter, to be replaced by a default value paramList[n] = null // Remove this parameter, to be replaced by a default value
extractGeneratedOverload(paramList) extractGeneratedOverload(paramList)
} }
@@ -2327,7 +2327,7 @@ open class KotlinFileExtractor(
getClassByFqName(pluginContext, it)?.let { annotationClass -> getClassByFqName(pluginContext, it)?.let { annotationClass ->
annotationClass.owner.declarations.firstIsInstanceOrNull<IrConstructor>()?.let { annotationClass.owner.declarations.firstIsInstanceOrNull<IrConstructor>()?.let {
annotationConstructor -> annotationConstructor ->
IrConstructorCallImpl.fromSymbolOwner( codeQlAnnotationFromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
annotationConstructor.returnType, annotationConstructor.returnType,
@@ -2388,13 +2388,13 @@ open class KotlinFileExtractor(
id id
} }
val extReceiver = f.extensionReceiverParameter val extReceiver = f.codeQlExtensionReceiverParameter
// The following parameter order is correct, because member $default methods (where // The following parameter order is correct, because member $default methods (where
// the order would be [dispatchParam], [extensionParam], normalParams) are not // the order would be [dispatchParam], [extensionParam], normalParams) are not
// extracted here // extracted here
val fParameters = val fParameters =
listOfNotNull(extReceiver) + listOfNotNull(extReceiver) +
(overriddenAttributes?.valueParameters ?: f.valueParameters) (overriddenAttributes?.valueParameters ?: f.codeQlValueParameters)
val paramTypes = val paramTypes =
fParameters.mapIndexed { i, vp -> fParameters.mapIndexed { i, vp ->
extractValueParameter( extractValueParameter(
@@ -3069,14 +3069,14 @@ open class KotlinFileExtractor(
logger.errorElement("Unexpected dispatch receiver found", c) logger.errorElement("Unexpected dispatch receiver found", c)
} }
if (c.valueArgumentsCount < 1) { if (c.codeQlValueArgumentsCount < 1) {
logger.errorElement("No arguments found", c) logger.errorElement("No arguments found", c)
return return
} }
extractArgument(id, c, callable, enclosingStmt, 0, "Operand null") extractArgument(id, c, callable, enclosingStmt, 0, "Operand null")
if (c.valueArgumentsCount > 1) { if (c.codeQlValueArgumentsCount > 1) {
logger.errorElement("Extra arguments found", c) logger.errorElement("Extra arguments found", c)
} }
} }
@@ -3095,21 +3095,21 @@ open class KotlinFileExtractor(
logger.errorElement("Unexpected dispatch receiver found", c) logger.errorElement("Unexpected dispatch receiver found", c)
} }
if (c.valueArgumentsCount < 1) { if (c.codeQlValueArgumentsCount < 1) {
logger.errorElement("No arguments found", c) logger.errorElement("No arguments found", c)
return return
} }
extractArgument(id, c, callable, enclosingStmt, 0, "LHS null") extractArgument(id, c, callable, enclosingStmt, 0, "LHS null")
if (c.valueArgumentsCount < 2) { if (c.codeQlValueArgumentsCount < 2) {
logger.errorElement("No RHS found", c) logger.errorElement("No RHS found", c)
return return
} }
extractArgument(id, c, callable, enclosingStmt, 1, "RHS null") extractArgument(id, c, callable, enclosingStmt, 1, "RHS null")
if (c.valueArgumentsCount > 2) { if (c.codeQlValueArgumentsCount > 2) {
logger.errorElement("Extra arguments found", c) logger.errorElement("Extra arguments found", c)
} }
} }
@@ -3122,7 +3122,7 @@ open class KotlinFileExtractor(
idx: Int, idx: Int,
msg: String msg: String
) { ) {
val op = c.getValueArgument(idx) val op = c.codeQlGetValueArgument(idx)
if (op == null) { if (op == null) {
logger.errorElement(msg, c) logger.errorElement(msg, c)
} else { } else {
@@ -3267,8 +3267,8 @@ open class KotlinFileExtractor(
// and which should be replaced by defaults. The final Object parameter is apparently always // and which should be replaced by defaults. The final Object parameter is apparently always
// null. // null.
(listOfNotNull(if (f.shouldExtractAsStatic) null else f.dispatchReceiverParameter?.type) + (listOfNotNull(if (f.shouldExtractAsStatic) null else f.dispatchReceiverParameter?.type) +
listOfNotNull(f.extensionReceiverParameter?.type) + listOfNotNull(f.codeQlExtensionReceiverParameter?.type) +
f.valueParameters.map { it.type } + f.codeQlValueParameters.map { it.type } +
listOf(pluginContext.irBuiltIns.intType, getDefaultsMethodLastArgType(f))) listOf(pluginContext.irBuiltIns.intType, getDefaultsMethodLastArgType(f)))
.map { erase(it) } .map { erase(it) }
@@ -3345,7 +3345,7 @@ open class KotlinFileExtractor(
val overriddenCallTarget = val overriddenCallTarget =
(callTarget as? IrSimpleFunction)?.allOverridden(includeSelf = true)?.firstOrNull { (callTarget as? IrSimpleFunction)?.allOverridden(includeSelf = true)?.firstOrNull {
it.overriddenSymbols.isEmpty() && it.overriddenSymbols.isEmpty() &&
it.valueParameters.any { p -> p.defaultValue != null } it.codeQlValueParameters.any { p -> p.defaultValue != null }
} ?: callTarget } ?: callTarget
if (isExternalDeclaration(overriddenCallTarget)) { if (isExternalDeclaration(overriddenCallTarget)) {
// Likewise, ensure the overridden target gets extracted. // Likewise, ensure the overridden target gets extracted.
@@ -3419,7 +3419,7 @@ open class KotlinFileExtractor(
} }
val valueArgsWithDummies = val valueArgsWithDummies =
valueArguments.zip(callTarget.valueParameters).map { (expr, param) -> valueArguments.zip(callTarget.codeQlValueParameters).map { (expr, param) ->
expr ?: IrConstImpl.defaultValueForType(0, 0, param.type) expr ?: IrConstImpl.defaultValueForType(0, 0, param.type)
} }
@@ -3529,7 +3529,7 @@ open class KotlinFileExtractor(
callTarget: IrFunction, callTarget: IrFunction,
valueArguments: List<IrExpression?> valueArguments: List<IrExpression?>
): Boolean { ): Boolean {
val varargParam = callTarget.valueParameters.withIndex().find { it.value.isVararg } val varargParam = callTarget.codeQlValueParameters.withIndex().find { it.value.isVararg }
// If the vararg param is the only one not specified, and it has no default value, then we // If the vararg param is the only one not specified, and it has no default value, then we
// don't need to call a $default method, // don't need to call a $default method,
// as omitting it already implies passing an empty vararg array. // as omitting it already implies passing an empty vararg array.
@@ -3805,7 +3805,7 @@ open class KotlinFileExtractor(
) = ) =
extractCallValueArguments( extractCallValueArguments(
callId, callId,
(0 until call.valueArgumentsCount).map { call.getValueArgument(it) }, (0 until call.codeQlValueArgumentsCount).map { call.codeQlGetValueArgument(it) },
enclosingStmt, enclosingStmt,
enclosingCallable, enclosingCallable,
idxOffset idxOffset
@@ -3874,7 +3874,7 @@ open class KotlinFileExtractor(
(owner.parentClassOrNull?.fqNameWhenAvailable?.asString() == type || (owner.parentClassOrNull?.fqNameWhenAvailable?.asString() == type ||
(owner.parent is IrExternalPackageFragment && (owner.parent is IrExternalPackageFragment &&
getFileClassFqName(owner)?.asString() == type)) && getFileClassFqName(owner)?.asString() == type)) &&
owner.valueParameters owner.codeQlValueParameters
.map { it.type.classFqName?.asString() } .map { it.type.classFqName?.asString() }
.toTypedArray() contentEquals parameterTypes .toTypedArray() contentEquals parameterTypes
} }
@@ -3926,8 +3926,8 @@ open class KotlinFileExtractor(
val result = val result =
javaLangString?.declarations?.findSubType<IrFunction> { javaLangString?.declarations?.findSubType<IrFunction> {
it.name.asString() == "valueOf" && it.name.asString() == "valueOf" &&
it.valueParameters.size == 1 && it.codeQlValueParameters.size == 1 &&
it.valueParameters[0].type == pluginContext.irBuiltIns.anyNType it.codeQlValueParameters[0].type == pluginContext.irBuiltIns.anyNType
} }
if (result == null) { if (result == null) {
logger.error("Couldn't find declaration java.lang.String.valueOf(Object)") logger.error("Couldn't find declaration java.lang.String.valueOf(Object)")
@@ -3951,7 +3951,7 @@ open class KotlinFileExtractor(
val kotlinNoWhenBranchMatchedConstructor by lazy { val kotlinNoWhenBranchMatchedConstructor by lazy {
val result = val result =
kotlinNoWhenBranchMatchedExn?.declarations?.findSubType<IrConstructor> { kotlinNoWhenBranchMatchedExn?.declarations?.findSubType<IrConstructor> {
it.valueParameters.isEmpty() it.codeQlValueParameters.isEmpty()
} }
if (result == null) { if (result == null) {
logger.error("Couldn't find no-arg constructor for kotlin.NoWhenBranchMatchedException") logger.error("Couldn't find no-arg constructor for kotlin.NoWhenBranchMatchedException")
@@ -3990,7 +3990,7 @@ open class KotlinFileExtractor(
verboseln("No match as function name is ${target.name.asString()} not $fName") verboseln("No match as function name is ${target.name.asString()} not $fName")
return false return false
} }
val extensionReceiverParameter = target.extensionReceiverParameter val extensionReceiverParameter = target.codeQlExtensionReceiverParameter
val targetClass = val targetClass =
if (extensionReceiverParameter == null) { if (extensionReceiverParameter == null) {
if (isNullable == true) { if (isNullable == true) {
@@ -4098,8 +4098,8 @@ open class KotlinFileExtractor(
) { ) {
val typeArgs = val typeArgs =
if (extractMethodTypeArguments) if (extractMethodTypeArguments)
(0 until c.typeArgumentsCount) (0 until c.codeQlTypeArgumentsCount)
.map { c.getTypeArgument(it) } .map { c.codeQlGetTypeArgument(it) }
.requireNoNullsOrNull() .requireNoNullsOrNull()
else listOf() else listOf()
@@ -4116,9 +4116,9 @@ open class KotlinFileExtractor(
parent, parent,
idx, idx,
enclosingStmt, enclosingStmt,
(0 until c.valueArgumentsCount).map { c.getValueArgument(it) }, (0 until c.codeQlValueArgumentsCount).map { c.codeQlGetValueArgument(it) },
c.dispatchReceiver, c.dispatchReceiver,
c.extensionReceiver, c.codeQlExtensionReceiver,
typeArgs, typeArgs,
extractClassTypeArguments, extractClassTypeArguments,
c.superQualifierSymbol c.superQualifierSymbol
@@ -4126,12 +4126,12 @@ open class KotlinFileExtractor(
} }
fun extractSpecialEnumFunction(fnName: String) { fun extractSpecialEnumFunction(fnName: String) {
if (c.typeArgumentsCount != 1) { if (c.codeQlTypeArgumentsCount != 1) {
logger.errorElement("Expected to find exactly one type argument", c) logger.errorElement("Expected to find exactly one type argument", c)
return return
} }
val enumType = (c.getTypeArgument(0) as? IrSimpleType)?.classifier?.owner val enumType = (c.codeQlGetTypeArgument(0) as? IrSimpleType)?.classifier?.owner
if (enumType == null) { if (enumType == null) {
logger.errorElement("Couldn't find type of enum type", c) logger.errorElement("Couldn't find type of enum type", c)
return return
@@ -4178,13 +4178,13 @@ open class KotlinFileExtractor(
} else { } else {
extractExpressionExpr(receiver, callable, id, 0, enclosingStmt) extractExpressionExpr(receiver, callable, id, 0, enclosingStmt)
} }
if (c.valueArgumentsCount < 1) { if (c.codeQlValueArgumentsCount < 1) {
logger.errorElement("No RHS found", c) logger.errorElement("No RHS found", c)
} else { } else {
if (c.valueArgumentsCount > 1) { if (c.codeQlValueArgumentsCount > 1) {
logger.errorElement("Extra arguments found", c) logger.errorElement("Extra arguments found", c)
} }
val arg = c.getValueArgument(0) val arg = c.codeQlGetValueArgument(0)
if (arg == null) { if (arg == null) {
logger.errorElement("RHS null", c) logger.errorElement("RHS null", c)
} else { } else {
@@ -4205,7 +4205,7 @@ open class KotlinFileExtractor(
} else { } else {
extractExpressionExpr(receiver, callable, id, 0, enclosingStmt) extractExpressionExpr(receiver, callable, id, 0, enclosingStmt)
} }
if (c.valueArgumentsCount > 0) { if (c.codeQlValueArgumentsCount > 0) {
logger.errorElement("Extra arguments found", c) logger.errorElement("Extra arguments found", c)
} }
} }
@@ -4219,7 +4219,7 @@ open class KotlinFileExtractor(
} }
fun binopExt(id: Label<out DbExpr>) { fun binopExt(id: Label<out DbExpr>) {
binopReceiver(id, c.extensionReceiver, "Extension receiver") binopReceiver(id, c.codeQlExtensionReceiver, "Extension receiver")
} }
fun unaryopDisp(id: Label<out DbExpr>) { fun unaryopDisp(id: Label<out DbExpr>) {
@@ -4227,7 +4227,7 @@ open class KotlinFileExtractor(
} }
fun unaryopExt(id: Label<out DbExpr>) { fun unaryopExt(id: Label<out DbExpr>) {
unaryopReceiver(id, c.extensionReceiver, "Extension receiver") unaryopReceiver(id, c.codeQlExtensionReceiver, "Extension receiver")
} }
val dr = c.dispatchReceiver val dr = c.dispatchReceiver
@@ -4249,7 +4249,7 @@ open class KotlinFileExtractor(
parent, parent,
idx, idx,
enclosingStmt, enclosingStmt,
listOf(c.extensionReceiver, c.getValueArgument(0)), listOf(c.codeQlExtensionReceiver, c.codeQlGetValueArgument(0)),
null, null,
null null
) )
@@ -4350,7 +4350,7 @@ open class KotlinFileExtractor(
// != gets desugared into not and ==. Here we resugar it. // != gets desugared into not and ==. Here we resugar it.
c.origin == IrStatementOrigin.EXCLEQ && c.origin == IrStatementOrigin.EXCLEQ &&
isFunction(target, "kotlin", "Boolean", "not") && isFunction(target, "kotlin", "Boolean", "not") &&
c.valueArgumentsCount == 0 && c.codeQlValueArgumentsCount == 0 &&
dr != null && dr != null &&
dr is IrCall && dr is IrCall &&
isBuiltinCallInternal(dr, "EQEQ") -> { isBuiltinCallInternal(dr, "EQEQ") -> {
@@ -4362,7 +4362,7 @@ open class KotlinFileExtractor(
} }
c.origin == IrStatementOrigin.EXCLEQEQ && c.origin == IrStatementOrigin.EXCLEQEQ &&
isFunction(target, "kotlin", "Boolean", "not") && isFunction(target, "kotlin", "Boolean", "not") &&
c.valueArgumentsCount == 0 && c.codeQlValueArgumentsCount == 0 &&
dr != null && dr != null &&
dr is IrCall && dr is IrCall &&
isBuiltinCallInternal(dr, "EQEQEQ") -> { isBuiltinCallInternal(dr, "EQEQEQ") -> {
@@ -4374,7 +4374,7 @@ open class KotlinFileExtractor(
} }
c.origin == IrStatementOrigin.EXCLEQ && c.origin == IrStatementOrigin.EXCLEQ &&
isFunction(target, "kotlin", "Boolean", "not") && isFunction(target, "kotlin", "Boolean", "not") &&
c.valueArgumentsCount == 0 && c.codeQlValueArgumentsCount == 0 &&
dr != null && dr != null &&
dr is IrCall && dr is IrCall &&
isBuiltinCallInternal(dr, "ieee754equals") -> { isBuiltinCallInternal(dr, "ieee754equals") -> {
@@ -4576,7 +4576,7 @@ open class KotlinFileExtractor(
parent, parent,
idx, idx,
enclosingStmt, enclosingStmt,
listOf(c.extensionReceiver), listOf(c.codeQlExtensionReceiver),
null, null,
null null
) )
@@ -4596,8 +4596,8 @@ open class KotlinFileExtractor(
val locId = tw.getLocation(c) val locId = tw.getLocation(c)
extractExprContext(id, locId, callable, enclosingStmt) extractExprContext(id, locId, callable, enclosingStmt)
if (c.typeArgumentsCount == 1) { if (c.codeQlTypeArgumentsCount == 1) {
val typeArgument = c.getTypeArgument(0) val typeArgument = c.codeQlGetTypeArgument(0)
if (typeArgument == null) { if (typeArgument == null) {
logger.errorElement("Type argument missing in an arrayOfNulls call", c) logger.errorElement("Type argument missing in an arrayOfNulls call", c)
} else { } else {
@@ -4618,8 +4618,8 @@ open class KotlinFileExtractor(
) )
} }
if (c.valueArgumentsCount == 1) { if (c.codeQlValueArgumentsCount == 1) {
val dim = c.getValueArgument(0) val dim = c.codeQlGetValueArgument(0)
if (dim != null) { if (dim != null) {
extractExpressionExpr(dim, callable, id, 0, enclosingStmt) extractExpressionExpr(dim, callable, id, 0, enclosingStmt)
} else { } else {
@@ -4651,8 +4651,8 @@ open class KotlinFileExtractor(
c.type.getArrayElementTypeCodeQL(pluginContext.irBuiltIns) c.type.getArrayElementTypeCodeQL(pluginContext.irBuiltIns)
} else { } else {
// TODO: is there any reason not to always use getArrayElementTypeCodeQL? // TODO: is there any reason not to always use getArrayElementTypeCodeQL?
if (c.typeArgumentsCount == 1) { if (c.codeQlTypeArgumentsCount == 1) {
c.getTypeArgument(0).also { c.codeQlGetTypeArgument(0).also {
if (it == null) { if (it == null) {
logger.errorElement( logger.errorElement(
"Type argument missing in an arrayOf call", "Type argument missing in an arrayOf call",
@@ -4670,7 +4670,7 @@ open class KotlinFileExtractor(
} }
val arg = val arg =
if (c.valueArgumentsCount == 1) c.getValueArgument(0) if (c.codeQlValueArgumentsCount == 1) c.codeQlGetValueArgument(0)
else { else {
logger.errorElement( logger.errorElement(
"Expected to find only one (vararg) argument in ${c.symbol.owner.name.asString()} call", "Expected to find only one (vararg) argument in ${c.symbol.owner.name.asString()} call",
@@ -4719,7 +4719,7 @@ open class KotlinFileExtractor(
return return
} }
val ext = c.extensionReceiver val ext = c.codeQlExtensionReceiver
if (ext == null) { if (ext == null) {
logger.errorElement( logger.errorElement(
"No extension receiver found for `KClass::java` call", "No extension receiver found for `KClass::java` call",
@@ -4826,8 +4826,8 @@ open class KotlinFileExtractor(
c.origin == IrStatementOrigin.EQ && c.origin == IrStatementOrigin.EQ &&
c.dispatchReceiver != null -> { c.dispatchReceiver != null -> {
val array = c.dispatchReceiver val array = c.dispatchReceiver
val arrayIdx = c.getValueArgument(0) val arrayIdx = c.codeQlGetValueArgument(0)
val assignedValue = c.getValueArgument(1) val assignedValue = c.codeQlGetValueArgument(1)
if (array != null && arrayIdx != null && assignedValue != null) { if (array != null && arrayIdx != null && assignedValue != null) {
@@ -4882,22 +4882,22 @@ open class KotlinFileExtractor(
} }
isBuiltinCall(c, "<unsafe-coerce>", "kotlin.jvm.internal") -> { isBuiltinCall(c, "<unsafe-coerce>", "kotlin.jvm.internal") -> {
if (c.valueArgumentsCount != 1) { if (c.codeQlValueArgumentsCount != 1) {
logger.errorElement( logger.errorElement(
"Expected to find one argument for a kotlin.jvm.internal.<unsafe-coerce>() call, but found ${c.valueArgumentsCount}", "Expected to find one argument for a kotlin.jvm.internal.<unsafe-coerce>() call, but found ${c.codeQlValueArgumentsCount}",
c c
) )
return return
} }
if (c.typeArgumentsCount != 2) { if (c.codeQlTypeArgumentsCount != 2) {
logger.errorElement( logger.errorElement(
"Expected to find two type arguments for a kotlin.jvm.internal.<unsafe-coerce>() call, but found ${c.typeArgumentsCount}", "Expected to find two type arguments for a kotlin.jvm.internal.<unsafe-coerce>() call, but found ${c.codeQlTypeArgumentsCount}",
c c
) )
return return
} }
val valueArg = c.getValueArgument(0) val valueArg = c.codeQlGetValueArgument(0)
if (valueArg == null) { if (valueArg == null) {
logger.errorElement( logger.errorElement(
"Cannot find value argument for a kotlin.jvm.internal.<unsafe-coerce>() call", "Cannot find value argument for a kotlin.jvm.internal.<unsafe-coerce>() call",
@@ -4905,7 +4905,7 @@ open class KotlinFileExtractor(
) )
return return
} }
val typeArg = c.getTypeArgument(1) val typeArg = c.codeQlGetTypeArgument(1)
if (typeArg == null) { if (typeArg == null) {
logger.errorElement( logger.errorElement(
"Cannot find type argument for a kotlin.jvm.internal.<unsafe-coerce>() call", "Cannot find type argument for a kotlin.jvm.internal.<unsafe-coerce>() call",
@@ -4924,7 +4924,7 @@ open class KotlinFileExtractor(
extractExpressionExpr(valueArg, callable, id, 1, enclosingStmt) extractExpressionExpr(valueArg, callable, id, 1, enclosingStmt)
} }
isBuiltinCallInternal(c, "dataClassArrayMemberToString") -> { isBuiltinCallInternal(c, "dataClassArrayMemberToString") -> {
val arrayArg = c.getValueArgument(0) val arrayArg = c.codeQlGetValueArgument(0)
val realArrayClass = arrayArg?.type?.classOrNull val realArrayClass = arrayArg?.type?.classOrNull
if (realArrayClass == null) { if (realArrayClass == null) {
logger.errorElement( logger.errorElement(
@@ -4936,8 +4936,8 @@ open class KotlinFileExtractor(
val realCallee = val realCallee =
javaUtilArrays?.declarations?.findSubType<IrFunction> { decl -> javaUtilArrays?.declarations?.findSubType<IrFunction> { decl ->
decl.name.asString() == "toString" && decl.name.asString() == "toString" &&
decl.valueParameters.size == 1 && decl.codeQlValueParameters.size == 1 &&
decl.valueParameters[0].type.classOrNull?.let { decl.codeQlValueParameters[0].type.classOrNull?.let {
it == realArrayClass it == realArrayClass
} == true } == true
} }
@@ -4962,7 +4962,7 @@ open class KotlinFileExtractor(
} }
} }
isBuiltinCallInternal(c, "dataClassArrayMemberHashCode") -> { isBuiltinCallInternal(c, "dataClassArrayMemberHashCode") -> {
val arrayArg = c.getValueArgument(0) val arrayArg = c.codeQlGetValueArgument(0)
val realArrayClass = arrayArg?.type?.classOrNull val realArrayClass = arrayArg?.type?.classOrNull
if (realArrayClass == null) { if (realArrayClass == null) {
logger.errorElement( logger.errorElement(
@@ -4974,8 +4974,8 @@ open class KotlinFileExtractor(
val realCallee = val realCallee =
javaUtilArrays?.declarations?.findSubType<IrFunction> { decl -> javaUtilArrays?.declarations?.findSubType<IrFunction> { decl ->
decl.name.asString() == "hashCode" && decl.name.asString() == "hashCode" &&
decl.valueParameters.size == 1 && decl.codeQlValueParameters.size == 1 &&
decl.valueParameters[0].type.classOrNull?.let { decl.codeQlValueParameters[0].type.classOrNull?.let {
it == realArrayClass it == realArrayClass
} == true } == true
} }
@@ -5155,7 +5155,7 @@ open class KotlinFileExtractor(
val type = useType(eType) val type = useType(eType)
val isAnonymous = eType.isAnonymous val isAnonymous = eType.isAnonymous
val locId = tw.getLocation(e) val locId = tw.getLocation(e)
val valueArgs = (0 until e.valueArgumentsCount).map { e.getValueArgument(it) } val valueArgs = (0 until e.codeQlValueArgumentsCount).map { e.codeQlGetValueArgument(it) }
val id = val id =
if ( if (
@@ -5211,10 +5211,10 @@ open class KotlinFileExtractor(
realCallTarget is IrConstructor && realCallTarget is IrConstructor &&
realCallTarget.parentClassOrNull?.fqNameWhenAvailable?.asString() == realCallTarget.parentClassOrNull?.fqNameWhenAvailable?.asString() ==
"kotlin.Enum" && "kotlin.Enum" &&
realCallTarget.valueParameters.size == 2 && realCallTarget.codeQlValueParameters.size == 2 &&
realCallTarget.valueParameters[0].type == realCallTarget.codeQlValueParameters[0].type ==
pluginContext.irBuiltIns.stringType && pluginContext.irBuiltIns.stringType &&
realCallTarget.valueParameters[1].type == pluginContext.irBuiltIns.intType realCallTarget.codeQlValueParameters[1].type == pluginContext.irBuiltIns.intType
) { ) {
val id0 = val id0 =
@@ -5287,7 +5287,7 @@ open class KotlinFileExtractor(
} }
val args = val args =
(0 until e.typeArgumentsCount).map { e.getTypeArgument(it) }.requireNoNullsOrNull() (0 until e.codeQlTypeArgumentsCount).map { e.codeQlGetTypeArgument(it) }.requireNoNullsOrNull()
if (args == null) { if (args == null) {
logger.warnElement("Found null type argument in enum constructor call", e) logger.warnElement("Found null type argument in enum constructor call", e)
return return
@@ -5365,7 +5365,7 @@ open class KotlinFileExtractor(
// Check for an expression like x = get(x).op(e): // Check for an expression like x = get(x).op(e):
val opReceiver = updateRhs.dispatchReceiver val opReceiver = updateRhs.dispatchReceiver
if (isExpectedLhs(opReceiver)) { if (isExpectedLhs(opReceiver)) {
updateRhs.getValueArgument(0) updateRhs.codeQlGetValueArgument(0)
} else null } else null
} else null } else null
} }
@@ -5560,7 +5560,7 @@ open class KotlinFileExtractor(
"set" "set"
) )
) { ) {
val updateRhs0 = arraySetCall.getValueArgument(1) val updateRhs0 = arraySetCall.codeQlGetValueArgument(1)
if (updateRhs0 == null) { if (updateRhs0 == null) {
logger.errorElement("Update RHS not found", e) logger.errorElement("Update RHS not found", e)
return false return false
@@ -6403,12 +6403,12 @@ open class KotlinFileExtractor(
val ids = getLocallyVisibleFunctionLabels(e.function) val ids = getLocallyVisibleFunctionLabels(e.function)
val locId = tw.getLocation(e) val locId = tw.getLocation(e)
val ext = e.function.extensionReceiverParameter val ext = e.function.codeQlExtensionReceiverParameter
val parameters = val parameters =
if (ext != null) { if (ext != null) {
listOf(ext) + e.function.valueParameters listOf(ext) + e.function.codeQlValueParameters
} else { } else {
e.function.valueParameters e.function.codeQlValueParameters
} }
var types = parameters.map { it.type } var types = parameters.map { it.type }
@@ -6670,7 +6670,7 @@ open class KotlinFileExtractor(
is IrFunction -> { is IrFunction -> {
if ( if (
ownerParent.dispatchReceiverParameter == owner && ownerParent.dispatchReceiverParameter == owner &&
ownerParent.extensionReceiverParameter != null ownerParent.codeQlExtensionReceiverParameter != null
) { ) {
val ownerParent2 = ownerParent.parent val ownerParent2 = ownerParent.parent
@@ -7089,7 +7089,7 @@ open class KotlinFileExtractor(
makeReceiverInfo(callableReferenceExpr.dispatchReceiver, 0) makeReceiverInfo(callableReferenceExpr.dispatchReceiver, 0)
private val extensionReceiverInfo = private val extensionReceiverInfo =
makeReceiverInfo( makeReceiverInfo(
callableReferenceExpr.extensionReceiver, callableReferenceExpr.codeQlExtensionReceiver,
if (dispatchReceiverInfo == null) 0 else 1 if (dispatchReceiverInfo == null) 0 else 1
) )
@@ -7627,8 +7627,8 @@ open class KotlinFileExtractor(
} }
val expressionTypeArguments = val expressionTypeArguments =
(0 until propertyReferenceExpr.typeArgumentsCount).mapNotNull { (0 until propertyReferenceExpr.codeQlTypeArgumentsCount).mapNotNull {
propertyReferenceExpr.getTypeArgument(it) propertyReferenceExpr.codeQlGetTypeArgument(it)
} }
val idPropertyRef = tw.getFreshIdLabel<DbPropertyref>() val idPropertyRef = tw.getFreshIdLabel<DbPropertyref>()
@@ -7829,7 +7829,7 @@ open class KotlinFileExtractor(
if ( if (
functionReferenceExpr.dispatchReceiver != null && functionReferenceExpr.dispatchReceiver != null &&
functionReferenceExpr.extensionReceiver != null functionReferenceExpr.codeQlExtensionReceiver != null
) { ) {
logger.errorElement( logger.errorElement(
"Unexpected: dispatchReceiver and extensionReceiver are both non-null", "Unexpected: dispatchReceiver and extensionReceiver are both non-null",
@@ -7840,7 +7840,7 @@ open class KotlinFileExtractor(
if ( if (
target.owner.dispatchReceiverParameter != null && target.owner.dispatchReceiverParameter != null &&
target.owner.extensionReceiverParameter != null target.owner.codeQlExtensionReceiverParameter != null
) { ) {
logger.errorElement( logger.errorElement(
"Unexpected: dispatch and extension parameters are both non-null", "Unexpected: dispatch and extension parameters are both non-null",
@@ -7899,8 +7899,8 @@ open class KotlinFileExtractor(
null null
} }
expressionTypeArguments = expressionTypeArguments =
(0 until functionReferenceExpr.typeArgumentsCount).mapNotNull { (0 until functionReferenceExpr.codeQlTypeArgumentsCount).mapNotNull {
functionReferenceExpr.getTypeArgument(it) functionReferenceExpr.codeQlGetTypeArgument(it)
} }
dispatchReceiverIdx = -1 dispatchReceiverIdx = -1
} }
@@ -7965,7 +7965,7 @@ open class KotlinFileExtractor(
functionReferenceExpr, functionReferenceExpr,
declarationParent, declarationParent,
null, null,
{ it.valueParameters.size == 1 } { it.codeQlValueParameters.size == 1 }
) { ) {
// The argument to FunctionReference's constructor is the function arity. // The argument to FunctionReference's constructor is the function arity.
extractConstantInteger( extractConstantInteger(
@@ -8572,7 +8572,7 @@ open class KotlinFileExtractor(
reverse: Boolean = false reverse: Boolean = false
) { ) {
val typeArguments = val typeArguments =
(0 until c.typeArgumentsCount).map { c.getTypeArgument(it) }.requireNoNullsOrNull() (0 until c.codeQlTypeArgumentsCount).map { c.codeQlGetTypeArgument(it) }.requireNoNullsOrNull()
if (typeArguments == null) { if (typeArguments == null) {
logger.errorElement("Found a null type argument for a member access expression", c) logger.errorElement("Found a null type argument for a member access expression", c)
} else { } else {
@@ -8923,11 +8923,11 @@ open class KotlinFileExtractor(
tw.writeVariableBinding(lhsId, fieldId) tw.writeVariableBinding(lhsId, fieldId)
val parameters = mutableListOf<IrValueParameter>() val parameters = mutableListOf<IrValueParameter>()
val extParam = samMember.extensionReceiverParameter val extParam = samMember.codeQlExtensionReceiverParameter
if (extParam != null) { if (extParam != null) {
parameters.add(extParam) parameters.add(extParam)
} }
parameters.addAll(samMember.valueParameters) parameters.addAll(samMember.codeQlValueParameters)
fun extractArgument( fun extractArgument(
p: IrValueParameter, p: IrValueParameter,
@@ -9032,7 +9032,7 @@ open class KotlinFileExtractor(
elementToReportOn: IrElement, elementToReportOn: IrElement,
declarationParent: IrDeclarationParent, declarationParent: IrDeclarationParent,
compilerGeneratedKindOverride: CompilerGeneratedKinds? = null, compilerGeneratedKindOverride: CompilerGeneratedKinds? = null,
superConstructorSelector: (IrFunction) -> Boolean = { it.valueParameters.isEmpty() }, superConstructorSelector: (IrFunction) -> Boolean = { it.codeQlValueParameters.isEmpty() },
extractSuperconstructorArgs: (Label<DbSuperconstructorinvocationstmt>) -> Unit = {}, extractSuperconstructorArgs: (Label<DbSuperconstructorinvocationstmt>) -> Unit = {},
): Label<out DbClassorinterface> { ): Label<out DbClassorinterface> {
// Write class // Write class

View File

@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.addAnnotations import com.github.codeql.utils.versions.codeQlAddAnnotations
import org.jetbrains.kotlin.ir.types.classFqName import org.jetbrains.kotlin.ir.types.classFqName
import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.classOrNull
@@ -355,7 +355,7 @@ open class KotlinUsesExtractor(
} }
private fun propertySignature(p: IrProperty) = private fun propertySignature(p: IrProperty) =
((p.getter ?: p.setter)?.extensionReceiverParameter?.let { ((p.getter ?: p.setter)?.codeQlExtensionReceiverParameter?.let {
useType(erase(it.type)).javaResult.signature useType(erase(it.type)).javaResult.signature
} ?: "") } ?: "")
@@ -368,7 +368,7 @@ open class KotlinUsesExtractor(
// useDeclarationParent -> useFunction // useDeclarationParent -> useFunction
// -> extractFunctionLaterIfExternalFileMember, which would result for `fun <T> f(t: // -> extractFunctionLaterIfExternalFileMember, which would result for `fun <T> f(t:
// T) { ... }` for example. // T) { ... }` for example.
(listOfNotNull(d.extensionReceiverParameter) + d.valueParameters) (listOfNotNull(d.codeQlExtensionReceiverParameter) + d.codeQlValueParameters)
.map { useType(erase(it.type)).javaResult.signature } .map { useType(erase(it.type)).javaResult.signature }
.joinToString(separator = ",", prefix = "(", postfix = ")") .joinToString(separator = ",", prefix = "(", postfix = ")")
is IrProperty -> propertySignature(d) + externalClassExtractor.propertySignature is IrProperty -> propertySignature(d) + externalClassExtractor.propertySignature
@@ -488,8 +488,8 @@ open class KotlinUsesExtractor(
val result = val result =
replacementClass.declarations.findSubType<IrSimpleFunction> { replacementDecl -> replacementClass.declarations.findSubType<IrSimpleFunction> { replacementDecl ->
replacementDecl.name == f.name && replacementDecl.name == f.name &&
replacementDecl.valueParameters.size == f.valueParameters.size && replacementDecl.codeQlValueParameters.size == f.codeQlValueParameters.size &&
replacementDecl.valueParameters.zip(f.valueParameters).all { replacementDecl.codeQlValueParameters.zip(f.codeQlValueParameters).all {
erase(it.first.type) == erase(it.second.type) erase(it.first.type) == erase(it.second.type)
} }
} }
@@ -1265,7 +1265,7 @@ open class KotlinUsesExtractor(
private fun getWildcardSuppressionDirective(t: IrAnnotationContainer): Boolean? = private fun getWildcardSuppressionDirective(t: IrAnnotationContainer): Boolean? =
t.getAnnotation(jvmWildcardSuppressionAnnotation)?.let { t.getAnnotation(jvmWildcardSuppressionAnnotation)?.let {
@Suppress("USELESS_CAST") // `as? Boolean` is not needed for Kotlin < 2.1 @Suppress("USELESS_CAST") // `as? Boolean` is not needed for Kotlin < 2.1
(it.getValueArgument(0) as? CodeQLIrConst<Boolean>)?.value as? Boolean ?: true (it.codeQlGetValueArgument(0) as? CodeQLIrConst<Boolean>)?.value as? Boolean ?: true
} }
private fun addJavaLoweringArgumentWildcards( private fun addJavaLoweringArgumentWildcards(
@@ -1376,9 +1376,9 @@ open class KotlinUsesExtractor(
f.parent, f.parent,
parentId, parentId,
getFunctionShortName(f).nameInDB, getFunctionShortName(f).nameInDB,
(maybeParameterList ?: f.valueParameters).map { it.type }, (maybeParameterList ?: f.codeQlValueParameters).map { it.type },
getAdjustedReturnType(f), getAdjustedReturnType(f),
f.extensionReceiverParameter?.type, f.codeQlExtensionReceiverParameter?.type,
getFunctionTypeParameters(f), getFunctionTypeParameters(f),
classTypeArgsIncludingOuterClasses, classTypeArgsIncludingOuterClasses,
overridesCollectionsMethodWithAlteredParameterTypes(f), overridesCollectionsMethodWithAlteredParameterTypes(f),
@@ -1401,12 +1401,12 @@ open class KotlinUsesExtractor(
// The name of the function; normally f.name.asString(). // The name of the function; normally f.name.asString().
name: String, name: String,
// The types of the value parameters that the functions takes; normally // The types of the value parameters that the functions takes; normally
// f.valueParameters.map { it.type }. // f.codeQlValueParameters.map { it.type }.
parameterTypes: List<IrType>, parameterTypes: List<IrType>,
// The return type of the function; normally f.returnType. // The return type of the function; normally f.returnType.
returnType: IrType, returnType: IrType,
// The extension receiver of the function, if any; normally // The extension receiver of the function, if any; normally
// f.extensionReceiverParameter?.type. // f.codeQlExtensionReceiverParameter?.type.
extensionParamType: IrType?, extensionParamType: IrType?,
// The type parameters of the function. This does not include type parameters of enclosing // The type parameters of the function. This does not include type parameters of enclosing
// classes. // classes.
@@ -1579,7 +1579,7 @@ open class KotlinUsesExtractor(
parentClass.fqNameWhenAvailable?.asString() != parentClass.fqNameWhenAvailable?.asString() !=
"java.util.concurrent.ConcurrentHashMap" || "java.util.concurrent.ConcurrentHashMap" ||
getFunctionShortName(f).nameInDB != "keySet" || getFunctionShortName(f).nameInDB != "keySet" ||
f.valueParameters.isNotEmpty() || f.codeQlValueParameters.isNotEmpty() ||
f.returnType.classFqName?.asString() != "kotlin.collections.MutableSet" f.returnType.classFqName?.asString() != "kotlin.collections.MutableSet"
) { ) {
return f.returnType return f.returnType
@@ -1587,7 +1587,7 @@ open class KotlinUsesExtractor(
val otherKeySet = val otherKeySet =
parentClass.declarations.findSubType<IrFunction> { parentClass.declarations.findSubType<IrFunction> {
it.name.asString() == "keySet" && it.valueParameters.size == 1 it.name.asString() == "keySet" && it.codeQlValueParameters.size == 1
} ?: return f.returnType } ?: return f.returnType
return otherKeySet.returnType.codeQlWithHasQuestionMark(false) return otherKeySet.returnType.codeQlWithHasQuestionMark(false)
@@ -1695,8 +1695,8 @@ open class KotlinUsesExtractor(
javaClass.declarations.findSubType<IrFunction> { decl -> javaClass.declarations.findSubType<IrFunction> { decl ->
!decl.isFakeOverride && !decl.isFakeOverride &&
decl.name.asString() == jvmName && decl.name.asString() == jvmName &&
decl.valueParameters.size == f.valueParameters.size && decl.codeQlValueParameters.size == f.codeQlValueParameters.size &&
decl.valueParameters.zip(f.valueParameters).all { p -> decl.codeQlValueParameters.zip(f.codeQlValueParameters).all { p ->
erase(p.first.type).classifierOrNull == erase(p.first.type).classifierOrNull ==
erase(p.second.type).classifierOrNull erase(p.second.type).classifierOrNull
} }
@@ -2125,7 +2125,7 @@ open class KotlinUsesExtractor(
} }
return if (t.arguments.isNotEmpty()) return if (t.arguments.isNotEmpty())
t.addAnnotations(listOf(RawTypeAnnotation.annotationConstructor)) t.codeQlAddAnnotations(listOf(RawTypeAnnotation.annotationConstructor))
else t else t
} }
} }
@@ -2153,7 +2153,7 @@ open class KotlinUsesExtractor(
val idxOffset = val idxOffset =
if ( if (
declarationParent is IrFunction && declarationParent is IrFunction &&
declarationParent.extensionReceiverParameter != null declarationParent.codeQlExtensionReceiverParameter != null
) )
// For extension functions increase the index to match what the java extractor sees: // For extension functions increase the index to match what the java extractor sees:
1 1
@@ -2187,7 +2187,7 @@ open class KotlinUsesExtractor(
// Gets a field's corresponding property's extension receiver type, if any // Gets a field's corresponding property's extension receiver type, if any
fun getExtensionReceiverType(f: IrField) = fun getExtensionReceiverType(f: IrField) =
f.correspondingPropertySymbol?.owner?.let { f.correspondingPropertySymbol?.owner?.let {
(it.getter ?: it.setter)?.extensionReceiverParameter?.type (it.getter ?: it.setter)?.codeQlExtensionReceiverParameter?.type
} }
fun getFieldLabel(f: IrField): String { fun getFieldLabel(f: IrField): String {
@@ -2222,14 +2222,14 @@ open class KotlinUsesExtractor(
val setter = p.setter val setter = p.setter
val func = getter ?: setter val func = getter ?: setter
val ext = func?.extensionReceiverParameter val ext = func?.codeQlExtensionReceiverParameter
return if (ext == null) { return if (ext == null) {
"@\"property;{$parentId};${p.name.asString()}\"" "@\"property;{$parentId};${p.name.asString()}\""
} else { } else {
val returnType = val returnType =
getter?.returnType getter?.returnType
?: setter?.valueParameters?.singleOrNull()?.type ?: setter?.codeQlValueParameters?.singleOrNull()?.type
?: pluginContext.irBuiltIns.unitType ?: pluginContext.irBuiltIns.unitType
val typeParams = getFunctionTypeParameters(func) val typeParams = getFunctionTypeParameters(func)

View File

@@ -1,5 +1,10 @@
package com.github.codeql package com.github.codeql
import com.github.codeql.utils.versions.codeQlAnnotationFromSymbolOwner
import com.github.codeql.utils.versions.codeQlGetValueArgument
import com.github.codeql.utils.versions.codeQlPutValueArgument
import com.github.codeql.utils.versions.codeQlSetAnnotations
import com.github.codeql.utils.versions.codeQlSetDispatchReceiverParameter
import com.github.codeql.utils.versions.createImplicitParameterDeclarationWithWrappedDescriptor import com.github.codeql.utils.versions.createImplicitParameterDeclarationWithWrappedDescriptor
import java.lang.annotation.ElementType import java.lang.annotation.ElementType
import java.util.HashSet import java.util.HashSet
@@ -95,7 +100,7 @@ class MetaAnnotationSupport(
JvmAnnotationNames.REPEATABLE_ANNOTATION JvmAnnotationNames.REPEATABLE_ANNOTATION
} }
return if (jvmRepeatable != null) { return if (jvmRepeatable != null) {
((jvmRepeatable.getValueArgument(0) as? IrClassReference)?.symbol as? IrClassSymbol) ((jvmRepeatable.codeQlGetValueArgument(0) as? IrClassReference)?.symbol as? IrClassSymbol)
?.owner ?.owner
} else { } else {
getOrCreateSyntheticRepeatableAnnotationContainer(annotationClass) getOrCreateSyntheticRepeatableAnnotationContainer(annotationClass)
@@ -117,12 +122,12 @@ class MetaAnnotationSupport(
) )
return null return null
} else { } else {
return IrConstructorCallImpl.fromSymbolOwner( return codeQlAnnotationFromSymbolOwner(
containerClass.defaultType, containerClass.defaultType,
containerConstructor.symbol containerConstructor.symbol
) )
.apply { .apply {
putValueArgument( codeQlPutValueArgument(
0, 0,
IrVarargImpl( IrVarargImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
@@ -144,7 +149,7 @@ class MetaAnnotationSupport(
// Taken from AdditionalClassAnnotationLowering.kt // Taken from AdditionalClassAnnotationLowering.kt
private fun loadAnnotationTargets(targetEntry: IrConstructorCall): Set<KotlinTarget>? { private fun loadAnnotationTargets(targetEntry: IrConstructorCall): Set<KotlinTarget>? {
val valueArgument = targetEntry.getValueArgument(0) as? IrVararg ?: return null val valueArgument = targetEntry.codeQlGetValueArgument(0) as? IrVararg ?: return null
return valueArgument.elements return valueArgument.elements
.filterIsInstance<IrGetEnumValue>() .filterIsInstance<IrGetEnumValue>()
.mapNotNull { KotlinTarget.valueOrNull(it.symbol.owner.name.asString()) } .mapNotNull { KotlinTarget.valueOrNull(it.symbol.owner.name.asString()) }
@@ -230,14 +235,14 @@ class MetaAnnotationSupport(
) )
} }
return IrConstructorCallImpl.fromSymbolOwner( return codeQlAnnotationFromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
targetConstructor.returnType, targetConstructor.returnType,
targetConstructor.symbol, targetConstructor.symbol,
0 0
) )
.apply { putValueArgument(0, vararg) } .apply { codeQlPutValueArgument(0, vararg) }
} }
private val javaAnnotationRetention by lazy { private val javaAnnotationRetention by lazy {
@@ -263,7 +268,7 @@ class MetaAnnotationSupport(
// Taken from AnnotationCodegen.kt (not available in Kotlin < 1.6.20) // Taken from AnnotationCodegen.kt (not available in Kotlin < 1.6.20)
private fun IrClass.getAnnotationRetention(): KotlinRetention? { private fun IrClass.getAnnotationRetention(): KotlinRetention? {
val retentionArgument = val retentionArgument =
getAnnotation(StandardNames.FqNames.retention)?.getValueArgument(0) as? IrGetEnumValue getAnnotation(StandardNames.FqNames.retention)?.codeQlGetValueArgument(0) as? IrGetEnumValue
?: return null ?: return null
val retentionArgumentValue = retentionArgument.symbol.owner val retentionArgumentValue = retentionArgument.symbol.owner
return KotlinRetention.valueOf(retentionArgumentValue.name.asString()) return KotlinRetention.valueOf(retentionArgumentValue.name.asString())
@@ -283,7 +288,7 @@ class MetaAnnotationSupport(
val targetConstructor = val targetConstructor =
retentionType.declarations.firstIsInstanceOrNull<IrConstructor>() ?: return null retentionType.declarations.firstIsInstanceOrNull<IrConstructor>() ?: return null
return IrConstructorCallImpl.fromSymbolOwner( return codeQlAnnotationFromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
targetConstructor.returnType, targetConstructor.returnType,
@@ -291,7 +296,7 @@ class MetaAnnotationSupport(
0 0
) )
.apply { .apply {
putValueArgument( codeQlPutValueArgument(
0, 0,
IrGetEnumValueImpl( IrGetEnumValueImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
@@ -333,7 +338,7 @@ class MetaAnnotationSupport(
return return
} }
val newParam = thisReceiever.copyTo(this) val newParam = thisReceiever.copyTo(this)
dispatchReceiverParameter = newParam codeQlSetDispatchReceiverParameter(newParam)
body = body =
factory factory
.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) .createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET)
@@ -406,7 +411,7 @@ class MetaAnnotationSupport(
val repeatableContainerAnnotation = val repeatableContainerAnnotation =
kotlinAnnotationRepeatableContainer?.constructors?.single() kotlinAnnotationRepeatableContainer?.constructors?.single()
containerClass.annotations = codeQlSetAnnotations(containerClass,
annotationClass.annotations annotationClass.annotations
.filter { .filter {
it.isAnnotationWithEqualFqName(StandardNames.FqNames.retention) || it.isAnnotationWithEqualFqName(StandardNames.FqNames.retention) ||
@@ -415,7 +420,7 @@ class MetaAnnotationSupport(
.map { it.deepCopyWithSymbols(containerClass) } + .map { it.deepCopyWithSymbols(containerClass) } +
listOfNotNull( listOfNotNull(
repeatableContainerAnnotation?.let { repeatableContainerAnnotation?.let {
IrConstructorCallImpl.fromSymbolOwner( codeQlAnnotationFromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
it.returnType, it.returnType,
@@ -424,6 +429,7 @@ class MetaAnnotationSupport(
) )
} }
) )
)
containerClass containerClass
} }
@@ -462,14 +468,14 @@ class MetaAnnotationSupport(
containerClass.symbol, containerClass.symbol,
containerClass.defaultType containerClass.defaultType
) )
return IrConstructorCallImpl.fromSymbolOwner( return codeQlAnnotationFromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
repeatableConstructor.returnType, repeatableConstructor.returnType,
repeatableConstructor.symbol, repeatableConstructor.symbol,
0 0
) )
.apply { putValueArgument(0, containerReference) } .apply { codeQlPutValueArgument(0, containerReference) }
} }
private val javaAnnotationDocumented by lazy { private val javaAnnotationDocumented by lazy {
@@ -488,7 +494,7 @@ class MetaAnnotationSupport(
javaAnnotationDocumented?.declarations?.firstIsInstanceOrNull<IrConstructor>() javaAnnotationDocumented?.declarations?.firstIsInstanceOrNull<IrConstructor>()
?: return null ?: return null
return IrConstructorCallImpl.fromSymbolOwner( return codeQlAnnotationFromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
documentedConstructor.returnType, documentedConstructor.returnType,

View File

@@ -1,6 +1,7 @@
package com.github.codeql package com.github.codeql
import com.github.codeql.KotlinUsesExtractor.LocallyVisibleFunctionLabels import com.github.codeql.KotlinUsesExtractor.LocallyVisibleFunctionLabels
import com.github.codeql.utils.versions.codeQlExtensionReceiver
import com.semmle.extractor.java.PopulateFile import com.semmle.extractor.java.PopulateFile
import com.semmle.util.unicode.UTF8Util import com.semmle.util.unicode.UTF8Util
import java.io.BufferedWriter import java.io.BufferedWriter
@@ -331,7 +332,7 @@ open class FileTrapWriter(
is IrCall -> { is IrCall -> {
// Calls have incorrect startOffset, so we adjust them: // Calls have incorrect startOffset, so we adjust them:
val dr = e.dispatchReceiver?.let { getStartOffset(it) } val dr = e.dispatchReceiver?.let { getStartOffset(it) }
val er = e.extensionReceiver?.let { getStartOffset(it) } val er = e.codeQlExtensionReceiver?.let { getStartOffset(it) }
offsetMinOf(e.startOffset, dr, er) offsetMinOf(e.startOffset, dr, er)
} }
else -> e.startOffset else -> e.startOffset

View File

@@ -2,6 +2,7 @@ package com.github.codeql.comments
import com.github.codeql.* import com.github.codeql.*
import com.github.codeql.utils.isLocalFunction import com.github.codeql.utils.isLocalFunction
import com.github.codeql.utils.versions.codeQlExtensionReceiverParameter
import com.github.codeql.utils.versions.isDispatchReceiver import com.github.codeql.utils.versions.isDispatchReceiver
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
@@ -11,7 +12,7 @@ import org.jetbrains.kotlin.ir.util.parentClassOrNull
private fun IrValueParameter.isExtensionReceiver(): Boolean { private fun IrValueParameter.isExtensionReceiver(): Boolean {
val parentFun = parent as? IrFunction ?: return false val parentFun = parent as? IrFunction ?: return false
return parentFun.extensionReceiverParameter == this return parentFun.codeQlExtensionReceiverParameter == this
} }
open class CommentExtractor( open class CommentExtractor(

View File

@@ -1,6 +1,8 @@
package com.github.codeql.utils package com.github.codeql.utils
import com.github.codeql.utils.versions.CodeQLIrConst import com.github.codeql.utils.versions.CodeQLIrConst
import com.github.codeql.utils.versions.codeQlGetValueArgument
import com.github.codeql.utils.versions.codeQlValueArgumentsCount
import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
@@ -76,9 +78,9 @@ private fun getSpecialJvmName(f: IrFunction): String? {
fun getJvmName(container: IrAnnotationContainer): String? { fun getJvmName(container: IrAnnotationContainer): String? {
for (a: IrConstructorCall in container.annotations) { for (a: IrConstructorCall in container.annotations) {
val t = a.type val t = a.type
if (t is IrSimpleType && a.valueArgumentsCount == 1) { if (t is IrSimpleType && a.codeQlValueArgumentsCount == 1) {
val owner = t.classifier.owner val owner = t.classifier.owner
val v = a.getValueArgument(0) val v = a.codeQlGetValueArgument(0)
if (owner is IrClass) { if (owner is IrClass) {
val aPkg = owner.packageFqName?.asString() val aPkg = owner.packageFqName?.asString()
val name = owner.name.asString() val name = owner.name.asString()

View File

@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol
import org.jetbrains.kotlin.ir.types.addAnnotations import com.github.codeql.utils.versions.codeQlAddAnnotations
import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.makeNotNull import org.jetbrains.kotlin.ir.types.makeNotNull
import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.types.makeNullable
@@ -192,7 +192,7 @@ object RawTypeAnnotation {
addConstructor { isPrimary = true } addConstructor { isPrimary = true }
} }
val constructor = annoClass.constructors.single() val constructor = annoClass.constructors.single()
IrConstructorCallImpl.fromSymbolOwner(constructor.constructedClassType, constructor.symbol) codeQlAnnotationFromSymbolOwner(constructor.constructedClassType, constructor.symbol)
} }
} }
@@ -202,7 +202,7 @@ fun IrType.toRawType(): IrType =
when (val owner = this.classifier.owner) { when (val owner = this.classifier.owner) {
is IrClass -> { is IrClass -> {
if (this.arguments.isNotEmpty()) if (this.arguments.isNotEmpty())
this.addAnnotations(listOf(RawTypeAnnotation.annotationConstructor)) this.codeQlAddAnnotations(listOf(RawTypeAnnotation.annotationConstructor))
else this else this
} }
is IrTypeParameter -> owner.superTypes[0].toRawType() is IrTypeParameter -> owner.superTypes[0].toRawType()
@@ -215,7 +215,7 @@ fun IrType.toRawType(): IrType =
fun IrClass.toRawType(): IrType { fun IrClass.toRawType(): IrType {
val result = this.typeWith(listOf()) val result = this.typeWith(listOf())
return if (this.typeParameters.isNotEmpty()) return if (this.typeParameters.isNotEmpty())
result.addAnnotations(listOf(RawTypeAnnotation.annotationConstructor)) result.codeQlAddAnnotations(listOf(RawTypeAnnotation.annotationConstructor))
else result else result
} }

View File

@@ -0,0 +1,70 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.addAnnotations
/**
* Compatibility accessors for pre-2.4.0 API patterns.
* In pre-2.4.0 versions, these delegate directly to the existing APIs.
*/
// IrFunction: valueParameters
val IrFunction.codeQlValueParameters: List<IrValueParameter>
get() = valueParameters
// IrFunction: extensionReceiverParameter
val IrFunction.codeQlExtensionReceiverParameter: IrValueParameter?
get() = extensionReceiverParameter
// IrMemberAccessExpression: valueArgumentsCount
val IrMemberAccessExpression<*>.codeQlValueArgumentsCount: Int
get() = valueArgumentsCount
// IrMemberAccessExpression: getValueArgument
fun IrMemberAccessExpression<*>.codeQlGetValueArgument(index: Int): IrExpression? = getValueArgument(index)
// IrMemberAccessExpression: putValueArgument
fun IrMemberAccessExpression<*>.codeQlPutValueArgument(index: Int, value: IrExpression?) {
putValueArgument(index, value)
}
// IrMemberAccessExpression: extensionReceiver
val IrMemberAccessExpression<*>.codeQlExtensionReceiver: IrExpression?
get() = extensionReceiver
// IrMemberAccessExpression: typeArgumentsCount
val IrMemberAccessExpression<*>.codeQlTypeArgumentsCount: Int
get() = typeArgumentsCount
// IrMemberAccessExpression: getTypeArgument
fun IrMemberAccessExpression<*>.codeQlGetTypeArgument(index: Int): IrType? = getTypeArgument(index)
// addAnnotations compat: in pre-2.4.0, addAnnotations expects List<IrConstructorCall>
fun IrType.codeQlAddAnnotations(annotations: List<IrConstructorCall>): IrType =
addAnnotations(annotations)
// IrMutableAnnotationContainer.annotations setter: in pre-2.4.0, annotations is var with List<IrConstructorCall>
fun codeQlSetAnnotations(container: org.jetbrains.kotlin.ir.declarations.IrMutableAnnotationContainer, annotations: List<IrConstructorCall>) {
container.annotations = annotations
}
// IrFunction: set dispatch receiver parameter (pre-2.4.0 it's a var)
fun IrFunction.codeQlSetDispatchReceiverParameter(param: IrValueParameter?) {
dispatchReceiverParameter = param
}
// In pre-2.4.0, annotations are List<IrConstructorCall> so IrConstructorCallImpl works directly.
fun codeQlAnnotationFromSymbolOwner(
startOffset: Int, endOffset: Int, type: IrType, symbol: IrConstructorSymbol, typeArgumentsCount: Int
): IrConstructorCall =
IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, type, symbol, typeArgumentsCount)
fun codeQlAnnotationFromSymbolOwner(type: IrType, symbol: IrConstructorSymbol): IrConstructorCall =
IrConstructorCallImpl.fromSymbolOwner(type, symbol)

View File

@@ -3,10 +3,32 @@
package com.github.codeql package com.github.codeql
import com.intellij.mock.MockProject
import com.intellij.openapi.extensions.LoadingOrder
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi
import org.jetbrains.kotlin.config.CompilerConfiguration
@OptIn(ExperimentalCompilerApi::class) @OptIn(ExperimentalCompilerApi::class)
abstract class Kotlin2ComponentRegistrar : ComponentRegistrar { abstract class Kotlin2ComponentRegistrar : ComponentRegistrar {
/* Nothing to do; supportsK2 doesn't exist yet. */ /* Nothing to do; supportsK2 doesn't exist yet. */
private var project: MockProject? = null
override fun registerProjectComponents(
project: MockProject,
configuration: CompilerConfiguration
) {
this.project = project
doRegisterExtensions(configuration)
}
abstract fun doRegisterExtensions(configuration: CompilerConfiguration)
fun registerExtractorExtension(extension: IrGenerationExtension) {
val p = project ?: throw IllegalStateException("registerExtractorExtension called before registerProjectComponents")
val extensionPoint = p.extensionArea.getExtensionPoint(IrGenerationExtension.extensionPointName)
extensionPoint.registerExtension(extension, LoadingOrder.LAST, p)
}
} }

View File

@@ -3,11 +3,35 @@
package com.github.codeql package com.github.codeql
import com.intellij.mock.MockProject
import com.intellij.openapi.extensions.LoadingOrder
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi
import org.jetbrains.kotlin.config.CompilerConfiguration
@OptIn(ExperimentalCompilerApi::class) @OptIn(ExperimentalCompilerApi::class)
abstract class Kotlin2ComponentRegistrar : ComponentRegistrar { abstract class Kotlin2ComponentRegistrar : ComponentRegistrar {
override val supportsK2: Boolean override val supportsK2: Boolean
get() = true get() = true
private var project: MockProject? = null
override fun registerProjectComponents(
project: MockProject,
configuration: CompilerConfiguration
) {
this.project = project
doRegisterExtensions(configuration)
}
abstract fun doRegisterExtensions(configuration: CompilerConfiguration)
fun registerExtractorExtension(extension: IrGenerationExtension) {
val p = project ?: throw IllegalStateException("registerExtractorExtension called before registerProjectComponents")
// Register with LoadingOrder.LAST to ensure the extractor runs after other
// IR generation plugins (like kotlinx.serialization) have generated their code.
val extensionPoint = p.extensionArea.getExtensionPoint(IrGenerationExtension.extensionPointName)
extensionPoint.registerExtension(extension, LoadingOrder.LAST, p)
}
} }

View File

@@ -0,0 +1,121 @@
@file:Suppress("DEPRECATION")
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.IrAnnotation
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrAnnotationImpl
import org.jetbrains.kotlin.ir.expressions.impl.fromSymbolOwner
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.addAnnotations
/**
* Compatibility accessors for pre-2.4.0 API patterns.
* In 2.4.0, valueParameters/extensionReceiverParameter/extensionReceiver/
* getValueArgument/putValueArgument/valueArgumentsCount/typeArgumentsCount/getTypeArgument
* have been removed. This file provides the 2.4.0 implementations.
*/
// IrFunction: valueParameters -> parameters filtered to Regular kind
val IrFunction.codeQlValueParameters: List<IrValueParameter>
get() = parameters.filter { it.kind == org.jetbrains.kotlin.ir.declarations.IrParameterKind.Regular }
// IrFunction: extensionReceiverParameter
val IrFunction.codeQlExtensionReceiverParameter: IrValueParameter?
get() = parameters.firstOrNull { it.kind == org.jetbrains.kotlin.ir.declarations.IrParameterKind.ExtensionReceiver }
// Helper: get the offset of value arguments in the arguments list
// In 2.4.0, arguments[] includes dispatch/extension receivers before regular params
private fun IrMemberAccessExpression<*>.valueArgumentOffset(): Int {
val owner = symbol.owner as? IrFunction ?: return 0
return owner.parameters.count { it.kind != org.jetbrains.kotlin.ir.declarations.IrParameterKind.Regular }
}
// IrMemberAccessExpression: valueArgumentsCount
val IrMemberAccessExpression<*>.codeQlValueArgumentsCount: Int
get() = arguments.size - valueArgumentOffset()
// IrMemberAccessExpression: getValueArgument
fun IrMemberAccessExpression<*>.codeQlGetValueArgument(index: Int): IrExpression? = arguments[index + valueArgumentOffset()]
// IrMemberAccessExpression: putValueArgument
fun IrMemberAccessExpression<*>.codeQlPutValueArgument(index: Int, value: IrExpression?) {
arguments[index + valueArgumentOffset()] = value
}
// IrMemberAccessExpression: extensionReceiver
// For IrCall/IrFunctionReference, look at symbol.owner (IrFunction) directly.
// For IrPropertyReference, symbol.owner is IrProperty; use the getter's parameters instead.
val IrMemberAccessExpression<*>.codeQlExtensionReceiver: IrExpression?
get() {
val erp = extensionReceiverParameterIndex() ?: return null
return arguments[erp]
}
private fun IrMemberAccessExpression<*>.extensionReceiverParameterIndex(): Int? {
// Direct function owner (IrCall, IrFunctionReference, etc.)
(symbol.owner as? IrFunction)?.codeQlExtensionReceiverParameter?.let {
return it.indexInParameters
}
// Property reference: look at getter or setter function
(this as? org.jetbrains.kotlin.ir.expressions.IrPropertyReference)?.let { propRef ->
propRef.getter?.owner?.codeQlExtensionReceiverParameter?.let {
return it.indexInParameters
}
propRef.setter?.owner?.codeQlExtensionReceiverParameter?.let {
return it.indexInParameters
}
}
return null
}
// IrMemberAccessExpression: typeArgumentsCount
val IrMemberAccessExpression<*>.codeQlTypeArgumentsCount: Int
get() = typeArguments.size
// IrMemberAccessExpression: getTypeArgument
fun IrMemberAccessExpression<*>.codeQlGetTypeArgument(index: Int): IrType? = typeArguments[index]
// addAnnotations compat: in 2.4.0, addAnnotations expects List<IrAnnotation>
// IrConstructorCall implements IrAnnotation in 2.4.0, so filterIsInstance is identity
fun IrType.codeQlAddAnnotations(annotations: List<IrConstructorCall>): IrType =
addAnnotations(annotations.filterIsInstance<IrAnnotation>())
// IrMutableAnnotationContainer.annotations setter: in 2.4.0, expects List<IrAnnotation>
fun codeQlSetAnnotations(container: org.jetbrains.kotlin.ir.declarations.IrMutableAnnotationContainer, annotations: List<IrConstructorCall>) {
container.annotations = annotations.filterIsInstance<IrAnnotation>()
}
// IrFunction: set dispatch receiver parameter
// In 2.4.0, dispatchReceiverParameter is val; modify the parameters list directly.
fun IrFunction.codeQlSetDispatchReceiverParameter(param: IrValueParameter?) {
val existing = parameters.indexOfFirst { it.kind == org.jetbrains.kotlin.ir.declarations.IrParameterKind.DispatchReceiver }
val mutableParams = parameters.toMutableList()
if (existing >= 0) {
if (param != null) {
mutableParams[existing] = param
} else {
mutableParams.removeAt(existing)
}
} else if (param != null) {
param.kind = org.jetbrains.kotlin.ir.declarations.IrParameterKind.DispatchReceiver
mutableParams.add(0, param)
}
parameters = mutableParams
}
// In 2.4.0, annotation lists require IrAnnotation instances.
// Use IrAnnotationImpl.fromSymbolOwner instead of IrConstructorCallImpl.fromSymbolOwner.
fun codeQlAnnotationFromSymbolOwner(
startOffset: Int, endOffset: Int, type: IrType, symbol: IrConstructorSymbol, typeArgumentsCount: Int
): IrConstructorCall =
IrAnnotationImpl.fromSymbolOwner(startOffset, endOffset, type, symbol, typeArgumentsCount)
fun codeQlAnnotationFromSymbolOwner(type: IrType, symbol: IrConstructorSymbol): IrConstructorCall =
IrAnnotationImpl.fromSymbolOwner(type, symbol)

View File

@@ -0,0 +1,45 @@
@file:Suppress("DEPRECATION", "DEPRECATION_ERROR")
@file:OptIn(ExperimentalCompilerApi::class)
package com.github.codeql
import com.intellij.mock.MockProject
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi
import org.jetbrains.kotlin.config.CompilerConfiguration
abstract class Kotlin2ComponentRegistrar : CompilerPluginRegistrar(), ComponentRegistrar {
override val supportsK2: Boolean
get() = true
override val pluginId: String
get() = "kotlin-extractor"
// ComponentRegistrar implementation (legacy path, still called by Kotlin compiler)
override fun registerProjectComponents(
project: MockProject,
configuration: CompilerConfiguration
) {
// In 2.4.0, we use CompilerPluginRegistrar path instead.
// This is only called if the compiler uses the ComponentRegistrar service file.
// We do nothing here since registerExtensions will be called separately.
}
private var extensionStorage: CompilerPluginRegistrar.ExtensionStorage? = null
override fun ExtensionStorage.registerExtensions(configuration: CompilerConfiguration) {
this@Kotlin2ComponentRegistrar.extensionStorage = this
doRegisterExtensions(configuration)
}
abstract fun doRegisterExtensions(configuration: CompilerConfiguration)
protected fun registerExtractorExtension(extension: IrGenerationExtension) {
val storage = extensionStorage ?: throw IllegalStateException("registerExtractorExtension called before registerExtensions")
with(storage) {
IrGenerationExtension.registerExtension(extension)
}
}
}

View File

@@ -0,0 +1,13 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrParameterKind
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
fun parameterIndexExcludingReceivers(vp: IrValueParameter): Int {
val offset =
(vp.parent as? IrFunction)?.let { f ->
f.parameters.count { it.kind == IrParameterKind.DispatchReceiver || it.kind == IrParameterKind.ExtensionReceiver || it.kind == IrParameterKind.Context }
} ?: 0
return vp.indexInParameters - offset
}

View File

@@ -0,0 +1 @@
com.github.codeql.KotlinExtractorComponentRegistrar

View File

@@ -1,8 +1,5 @@
# when updating this list, `bazel mod tidy` should be run from `codeql` to update `MODULE.bazel` # when updating this list, `bazel mod tidy` should be run from `codeql` to update `MODULE.bazel`
VERSIONS = [ VERSIONS = [
"1.8.0",
"1.9.0-Beta",
"1.9.20-Beta",
"2.0.0-RC1", "2.0.0-RC1",
"2.0.20-Beta2", "2.0.20-Beta2",
"2.1.0-Beta1", "2.1.0-Beta1",
@@ -11,6 +8,7 @@ VERSIONS = [
"2.2.20-Beta2", "2.2.20-Beta2",
"2.3.0", "2.3.0",
"2.3.20", "2.3.20",
"2.4.0",
] ]
def _version_to_tuple(v): def _version_to_tuple(v):

View File

@@ -1,5 +1,5 @@
{ {
"markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 2.3.30.", "markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 2.4.10.",
"severity": "error", "severity": "error",
"source": { "source": {
"extractorName": "java", "extractorName": "java",

View File

@@ -0,0 +1,3 @@
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 44417 of field callee is not in type @callable. Appears in tuple (-16777158,44417)
Relevant element: callee=44417
Full ID for 44417: @"callable;(0).f((55))(55)". The ID may expand to @"callable;{@"class;Test"}.f({@"type;int"}){@"type;int"}"

View File

@@ -2,9 +2,9 @@ exprs
| Test.java:5:19:5:25 | Integer | Integer | | Test.java:5:19:5:25 | Integer | Integer |
| Test.java:5:38:5:44 | Integer | Integer | | Test.java:5:38:5:44 | Integer | Integer |
| Test.java:5:58:5:58 | p | Integer | | Test.java:5:58:5:58 | p | Integer |
| user.kt:2:7:2:7 | x | int | | user.kt:2:3:2:16 | x | int |
| user.kt:2:11:2:11 | t | Test | | user.kt:2:11:2:11 | t | Test |
| user.kt:2:11:2:16 | f(...) | Integer | | user.kt:2:11:2:16 | <Call to unknown method> | int |
| user.kt:2:13:2:16 | <implicit not null> | int | | user.kt:2:13:2:16 | <implicit not null> | int |
| user.kt:2:13:2:16 | int | int | | user.kt:2:13:2:16 | int | int |
| user.kt:2:15:2:15 | 5 | int | | user.kt:2:15:2:15 | 5 | int |

View File

@@ -6,6 +6,6 @@ def test(codeql, java_full):
codeql.database.create( codeql.database.create(
command=[ command=[
f"javac {java_srcs} -d build", f"javac {java_srcs} -d build",
"kotlinc -language-version 1.9 user.kt -cp build", "kotlinc -language-version 2.0 user.kt -cp build",
] ]
) )

View File

@@ -1,2 +1,2 @@
| user.kt:3:14:3:22 | getF(...) | lib/lib/TestKt.class:0:0:0:0 | getF | | user.kt:3:14:3:22 | getF(...) | file:///!unknown-binary-location/lib/TestKt.class:0:0:0:0 | getF |
| user.kt:3:26:3:28 | getF(...) | lib/lib/TestKt.class:0:0:0:0 | getF | | user.kt:3:26:3:28 | getF(...) | file:///!unknown-binary-location/lib/TestKt.class:0:0:0:0 | getF |

View File

@@ -2,5 +2,5 @@ import commands
def test(codeql, java_full): def test(codeql, java_full):
commands.run("kotlinc -language-version 1.9 test.kt -d lib") commands.run("kotlinc -language-version 2.0 test.kt -d lib")
codeql.database.create(command="kotlinc -language-version 1.9 user.kt -cp lib") codeql.database.create(command="kotlinc -language-version 2.0 user.kt -cp lib")

View File

@@ -9,4 +9,4 @@
| Percentage of calls with call target | 100 | | Percentage of calls with call target | 100 |
| Total number of lines | 3 | | Total number of lines | 3 |
| Total number of lines with extension kt | 3 | | Total number of lines with extension kt | 3 |
| Uses Kotlin 2: false | 1 | | Uses Kotlin 2: true | 1 |

View File

@@ -1,2 +1,2 @@
def test(codeql, java_full): def test(codeql, java_full):
codeql.database.create(command="kotlinc -J-Xmx2G -language-version 1.9 SomeClass.kt") codeql.database.create(command="kotlinc -J-Xmx2G -language-version 2.0 SomeClass.kt")

View File

@@ -1,3 +1,2 @@
| AKt.class:0:0:0:0 | AKt | true |
| B.kt:0:0:0:0 | BKt | true | | B.kt:0:0:0:0 | BKt | true |
| C.kt:1:1:3:1 | C | false | | C.kt:1:1:3:1 | C | false |

View File

@@ -2,5 +2,5 @@ import commands
def test(codeql, java_full): def test(codeql, java_full):
commands.run("kotlinc -language-version 1.9 A.kt") commands.run("kotlinc -language-version 2.0 A.kt")
codeql.database.create(command="kotlinc -cp . -language-version 1.9 B.kt C.kt") codeql.database.create(command="kotlinc -cp . -language-version 2.0 B.kt C.kt")

View File

@@ -1,4 +0,0 @@
| equals | Test |
| hashCode | Test |
| toString | Test |
| toString | java.lang.CharSequence |

View File

@@ -3,4 +3,4 @@ import commands
def test(codeql, java_full): def test(codeql, java_full):
commands.run(["javac", "Test.java", "-d", "bin"]) commands.run(["javac", "Test.java", "-d", "bin"])
codeql.database.create(command="kotlinc -language-version 1.9 user.kt -cp bin") codeql.database.create(command="kotlinc -language-version 2.0 user.kt -cp bin")

View File

@@ -0,0 +1,9 @@
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 43828 of field callee is not in type @callable. Appears in tuple (-16776213,43828)
Relevant element: callee=43828
Full ID for 43828: @"callable;(0).takesComparable((35),(35))(36)". The ID may expand to @"callable;{@"class;JavaDefns"}.takesComparable({@"class;java.lang.Comparable;{@"wildcard;super{@"class;java.lang.CharSequence"}"}"},{@"class;java.lang.Comparable;{@"wildcard;super{@"class;java.lang.CharSequence"}"}"}){@"type;void"}"
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 43832 of field callee is not in type @callable. Appears in tuple (-16776208,43832)
Relevant element: callee=43832
Full ID for 43832: @"callable;(0).takesArrayOfComparable((54),(54))(36)". The ID may expand to @"callable;{@"class;JavaDefns"}.takesArrayOfComparable({@"array;1;{@"class;java.lang.Comparable;{@"wildcard;super(19)"}"}"},{@"array;1;{@"class;java.lang.Comparable;{@"wildcard;super(19)"}"}"}){@"type;void"}"
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 43837 of field callee is not in type @callable. Appears in tuple (-16776201,43837)
Relevant element: callee=43837
Full ID for 43837: @"callable;(0).<init>((35),(35))(36)". The ID may expand to @"callable;{@"class;JavaDefns"}.<init>({@"class;java.lang.Comparable;{@"wildcard;super{@"class;java.lang.CharSequence"}"}"},{@"class;java.lang.Comparable;{@"wildcard;super{@"class;java.lang.CharSequence"}"}"}){@"type;void"}"

View File

@@ -8,16 +8,16 @@
| JavaDefns | takesComparable | invar | Comparable<CharSequence> | | JavaDefns | takesComparable | invar | Comparable<CharSequence> |
| JavaDefns | takesNestedComparable | innerContravar | Comparable<Comparable<? super CharSequence>> | | JavaDefns | takesNestedComparable | innerContravar | Comparable<Comparable<? super CharSequence>> |
| JavaDefns | takesNestedComparable | outerContravar | Comparable<? super Comparable<CharSequence>> | | JavaDefns | takesNestedComparable | outerContravar | Comparable<? super Comparable<CharSequence>> |
| JavaDefns2 | JavaDefns2 | p0 | Comparable<CharSequence> | | JavaDefns2 | JavaDefns2 | p0 | Comparable<? super CharSequence> |
| JavaDefns2 | JavaDefns2 | p1 | Comparable<? super CharSequence> | | JavaDefns2 | JavaDefns2 | p1 | Comparable<? super CharSequence> |
| JavaDefns2 | returnsInvariant | return | Comparable<CharSequence> | | JavaDefns2 | returnsInvariant | return | Comparable<CharSequence> |
| JavaDefns2 | returnsWildcard | return | Comparable<? super CharSequence> | | JavaDefns2 | returnsWildcard | return | Comparable<? super CharSequence> |
| JavaDefns2 | takesArrayOfComparable | p0 | Comparable<CharSequence>[] | | JavaDefns2 | takesArrayOfComparable | p0 | Comparable<? super CharSequence>[] |
| JavaDefns2 | takesArrayOfComparable | p1 | Comparable<? super CharSequence>[] | | JavaDefns2 | takesArrayOfComparable | p1 | Comparable<? super CharSequence>[] |
| JavaDefns2 | takesComparable | p0 | Comparable<CharSequence> | | JavaDefns2 | takesComparable | p0 | Comparable<? super CharSequence> |
| JavaDefns2 | takesComparable | p1 | Comparable<? super CharSequence> | | JavaDefns2 | takesComparable | p1 | Comparable<? super CharSequence> |
| JavaDefns2 | takesNestedComparable | p0 | Comparable<Comparable<? super CharSequence>> | | JavaDefns2 | takesNestedComparable | p0 | Comparable<? super Comparable<? super CharSequence>> |
| JavaDefns2 | takesNestedComparable | p1 | Comparable<? super Comparable<CharSequence>> | | JavaDefns2 | takesNestedComparable | p1 | Comparable<? super Comparable<? super CharSequence>> |
| KotlinDefns | returnsContravar | return | Comparable<CharSequence> | | KotlinDefns | returnsContravar | return | Comparable<CharSequence> |
| KotlinDefns | returnsContravarForced | return | Comparable<? super CharSequence> | | KotlinDefns | returnsContravarForced | return | Comparable<? super CharSequence> |
| KotlinDefns | returnsCovar | return | List<CharSequence> | | KotlinDefns | returnsCovar | return | List<CharSequence> |

View File

@@ -8,6 +8,6 @@ def test(codeql, java_full):
command=[ command=[
"kotlinc kotlindefns.kt", "kotlinc kotlindefns.kt",
"javac JavaUser.java JavaDefns.java -cp .", "javac JavaUser.java JavaDefns.java -cp .",
"kotlinc -language-version 1.9 -cp . kotlinuser.kt", "kotlinc -language-version 2.0 -cp . kotlinuser.kt",
] ]
) )

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* Kotlin 2.4.0 can now be analysed.

View File

@@ -0,0 +1,4 @@
---
category: deprecated
---
* Kotlin versions below 2.0.0 are no longer supported for analysis. The minimum supported version is now Kotlin 2.0.0.

View File

@@ -4,33 +4,67 @@
overlay[local?] overlay[local?]
module; module;
private import java as J private import internal.rangeanalysis.BoundSpecific
private import semmle.code.java.dataflow.SSA
private import semmle.code.java.dataflow.RangeUtils as RU
private import codeql.rangeanalysis.Bound as SharedBound
private module BoundDefs implements SharedBound::BoundDefinitions<J::Location> { private newtype TBound =
class SsaVariable extends Ssa::SsaDefinition { TBoundZero() or
/** Gets a use of this variable. */ TBoundSsa(SsaVariable v) { v.getSourceVariable().getType() instanceof IntegralType } or
Expr getAUse() { result = super.getARead() } TBoundExpr(Expr e) {
interestingExprBound(e) and
not exists(SsaVariable v | e = v.getAUse())
} }
class SsaSourceVariable = Ssa::SourceVariable; /**
* A bound that may be inferred for an expression plus/minus an integer delta.
*/
abstract class Bound extends TBound {
/** Gets a textual representation of this bound. */
abstract string toString();
class Type = J::Type; /** Gets an expression that equals this bound plus `delta`. */
abstract Expr getExpr(int delta);
class Expr = J::Expr; /** Gets an expression that equals this bound. */
Expr getExpr() { result = this.getExpr(0) }
class IntegralType = J::IntegralType; /** Gets the location of this bound. */
abstract Location getLocation();
class ConstantIntegerExpr = RU::ConstantIntegerExpr;
/** Holds if `e` is a bound expression and it is not an SSA variable read. */
predicate interestingExprBound(Expr e) {
e.(J::FieldRead).getField() instanceof J::ArrayLengthField
}
} }
module BoundImpl = SharedBound::Bound<J::Location, BoundDefs>; /**
* The bound that corresponds to the integer 0. This is used to represent all
* integer bounds as bounds are always accompanied by an added integer delta.
*/
class ZeroBound extends Bound, TBoundZero {
override string toString() { result = "0" }
import BoundImpl override Expr getExpr(int delta) { result.(ConstantIntegerExpr).getIntValue() = delta }
override Location getLocation() { result.hasLocationInfo("", 0, 0, 0, 0) }
}
/**
* A bound corresponding to the value of an SSA variable.
*/
class SsaBound extends Bound, TBoundSsa {
/** Gets the SSA variable that equals this bound. */
SsaVariable getSsa() { this = TBoundSsa(result) }
override string toString() { result = this.getSsa().toString() }
override Expr getExpr(int delta) { result = this.getSsa().getAUse() and delta = 0 }
override Location getLocation() { result = this.getSsa().getLocation() }
}
/**
* A bound that corresponds to the value of a specific expression that might be
* interesting, but isn't otherwise represented by the value of an SSA variable.
*/
class ExprBound extends Bound, TBoundExpr {
override string toString() { result = this.getExpr().toString() }
override Expr getExpr(int delta) { this = TBoundExpr(result) and delta = 0 }
override Location getLocation() { result = this.getExpr().getLocation() }
}

View File

@@ -0,0 +1,27 @@
/**
* Provides Java-specific definitions for bounds.
*/
overlay[local?]
module;
private import java as J
private import semmle.code.java.dataflow.SSA as Ssa
private import semmle.code.java.dataflow.RangeUtils as RU
class SsaVariable extends Ssa::SsaDefinition {
/** Gets a use of this variable. */
Expr getAUse() { result = super.getARead() }
}
class Expr = J::Expr;
class Location = J::Location;
class IntegralType = J::IntegralType;
class ConstantIntegerExpr = RU::ConstantIntegerExpr;
/** Holds if `e` is a bound expression and it is not an SSA variable read. */
predicate interestingExprBound(Expr e) {
e.(J::FieldRead).getField() instanceof J::ArrayLengthField
}

View File

@@ -0,0 +1,16 @@
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 79083 of field callee is not in type @callable. Appears in tuple (-16776495,79083)
Relevant element: callee=79083
Full ID for 79083: @"callable;(21913).toString()(64)". The ID may expand to @"callable;{@"class;java.nio.file.Path"}.toString(){@"class;java.lang.String"}"
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 79083 of field callee is not in type @callable. Appears in tuple (-16776429,79083)
Relevant element: callee=79083
Full ID for 79083: @"callable;(21913).toString()(64)". The ID may expand to @"callable;{@"class;java.nio.file.Path"}.toString(){@"class;java.lang.String"}"
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 79083 of field callee is not in type @callable. Appears in tuple (-16776357,79083)
Relevant element: callee=79083
Full ID for 79083: @"callable;(21913).toString()(64)". The ID may expand to @"callable;{@"class;java.nio.file.Path"}.toString(){@"class;java.lang.String"}"
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 79083 of field callee is not in type @callable. Appears in tuple (-16776266,79083)
Relevant element: callee=79083
Full ID for 79083: @"callable;(21913).toString()(64)". The ID may expand to @"callable;{@"class;java.nio.file.Path"}.toString(){@"class;java.lang.String"}"
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 79083 of field callee is not in type @callable. Appears in tuple (-16776200,79083)
Relevant element: callee=79083
Full ID for 79083: @"callable;(21913).toString()(64)". The ID may expand to @"callable;{@"class;java.nio.file.Path"}.toString(){@"class;java.lang.String"}"
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): More errors, not displayed. There are 16 values of field callee that are not in type @callable for a relation of size 1821

View File

@@ -0,0 +1,31 @@
| Test.java:137:22:137:27 | source | Unexpected result: hasTaintFlow |
| Test.java:141:35:141:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:148:22:148:27 | source | Unexpected result: hasTaintFlow |
| Test.java:152:35:152:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:159:22:159:27 | source | Unexpected result: hasTaintFlow |
| Test.java:163:35:163:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:178:35:178:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:181:35:181:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:189:35:189:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:192:35:192:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:200:35:200:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:203:35:203:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:362:22:362:27 | source | Unexpected result: hasTaintFlow |
| Test.java:366:35:366:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:373:22:373:27 | source | Unexpected result: hasTaintFlow |
| Test.java:377:35:377:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:384:22:384:27 | source | Unexpected result: hasTaintFlow |
| Test.java:388:35:388:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:402:22:402:27 | source | Unexpected result: hasTaintFlow |
| Test.java:406:35:406:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:413:22:413:27 | source | Unexpected result: hasTaintFlow |
| Test.java:417:35:417:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:424:22:424:27 | source | Unexpected result: hasTaintFlow |
| Test.java:428:35:428:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:436:22:436:27 | source | Unexpected result: hasTaintFlow |
| Test.java:440:35:440:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:447:22:447:27 | source | Unexpected result: hasTaintFlow |
| Test.java:451:35:451:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:458:22:458:27 | source | Unexpected result: hasTaintFlow |
| Test.java:462:35:462:51 | // $ hasTaintFlow | Missing result: hasTaintFlow |
| Test.java:604:31:604:47 | // $ hasTaintFlow | Missing result: hasTaintFlow |

View File

@@ -0,0 +1 @@
| CleartextStorageSharedPrefsTest.java:110:84:110:118 | // $ hasCleartextStorageSharedPrefs | Missing result: hasCleartextStorageSharedPrefs |

View File

@@ -0,0 +1,6 @@
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 80453 of field callee is not in type @callable. Appears in tuple (-16773210,80453)
Relevant element: callee=80453
Full ID for 80453: @"callable;(846).toString()(21)". The ID may expand to @"callable;{@"class;java.lang.CharSequence"}.toString(){@"class;java.lang.String"}"
[VALUE_NOT_IN_TYPE] predicate callableBinding(@caller callerid, @callable callee): Value 80453 of field callee is not in type @callable. Appears in tuple (-16773194,80453)
Relevant element: callee=80453
Full ID for 80453: @"callable;(846).toString()(21)". The ID may expand to @"callable;{@"class;java.lang.CharSequence"}.toString(){@"class;java.lang.String"}"

View File

@@ -63,7 +63,6 @@ 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-444/InsecureHttpParser.ql
ql/javascript/ql/src/experimental/Security/CWE-522-DecompressionBombs/DecompressionBombs.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/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/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-020/UntrustedDataToExternalAPI.ql
ql/javascript/ql/src/experimental/heuristics/ql/src/Security/CWE-078/CommandInjection.ql ql/javascript/ql/src/experimental/heuristics/ql/src/Security/CWE-078/CommandInjection.ql

View File

@@ -1,4 +0,0 @@
---
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.

View File

@@ -1,59 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
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.
</p>
<p>
The affected forms include IPv4-mapped IPv6 (<code>::ffff:169.254.169.254</code>),
NAT64 (<code>64:ff9b::a9fe:a9fe</code>) and 6to4 (<code>2002::</code>). A URL such as
<code>http://[::ffff:169.254.169.254]/</code> passes a dotted-quad denylist unchanged
while still reaching the internal address.
</p>
</overview>
<recommendation>
<p>
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
<code>ipaddr.js</code> classify these forms correctly via their range API, and
SSRF-protection libraries such as <code>request-filtering-agent</code> apply the check
after DNS resolution. Validate the resolved address rather than the textual host.
</p>
</recommendation>
<example>
<p>
The following guard rejects private IPv4 ranges using the <code>private-ip</code>
package, which inspects the textual IPv4 form only. An attacker supplies
<code>::ffff:169.254.169.254</code>, which the guard classifies as public, but the
request still reaches the internal metadata endpoint.
</p>
<sample src="examples/SsrfIpv6TransitionIncompleteGuardBad.js"/>
<p>
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.
</p>
<sample src="examples/SsrfIpv6TransitionIncompleteGuardGood.js"/>
</example>
<references>
<li>OWASP: <a href="https://owasp.org/www-community/attacks/Server_Side_Request_Forgery">Server-Side Request Forgery</a>.</li>
<li>Common Weakness Enumeration: <a href="https://cwe.mitre.org/data/definitions/918.html">CWE-918</a>.</li>
<li>Common Weakness Enumeration: <a href="https://cwe.mitre.org/data/definitions/1389.html">CWE-1389</a>.</li>
</references>
</qhelp>

View File

@@ -1,129 +0,0 @@
/**
* @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."

View File

@@ -1,14 +0,0 @@
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 };

View File

@@ -1,16 +0,0 @@
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 };

View File

@@ -1,2 +0,0 @@
| 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. |

View File

@@ -1 +0,0 @@
experimental/Security/CWE-918/SsrfIpv6TransitionIncompleteGuard.ql

View File

@@ -1,13 +0,0 @@
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 };

View File

@@ -1,18 +0,0 @@
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 };

View File

@@ -1,32 +0,0 @@
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 };

View File

@@ -1,16 +0,0 @@
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 };

View File

@@ -36,8 +36,6 @@ private module Input implements InputSig<Location, PythonDataFlow> {
// parameter, but dataflow-consistency queries should _not_ complain about there not // parameter, but dataflow-consistency queries should _not_ complain about there not
// being a post-update node for the synthetic `**kwargs` parameter. // being a post-update node for the synthetic `**kwargs` parameter.
n instanceof SynthDictSplatParameterNode n instanceof SynthDictSplatParameterNode
or
Private::Conversions::readStep(n, _, _)
} }
predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {

View File

@@ -1,4 +0,0 @@
---
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.

View File

@@ -1,4 +0,0 @@
---
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.

View File

@@ -256,12 +256,9 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
*/ */
overlay[local] overlay[local]
predicate isStaticmethod(Function func) { predicate isStaticmethod(Function func) {
// The decorator is *syntactically* a `Name` "staticmethod" — we don't exists(NameNode id | id.getId() = "staticmethod" and id.isGlobal() |
// care which variable it resolves to. `staticmethod` is a builtin and func.getADecorator() = id.getNode()
// 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"
} }
/** /**
@@ -271,9 +268,9 @@ predicate isStaticmethod(Function func) {
*/ */
overlay[local] overlay[local]
predicate isClassmethod(Function func) { predicate isClassmethod(Function func) {
// See `isStaticmethod` for the rationale for matching on the AST `Name` exists(NameNode id | id.getId() = "classmethod" and id.isGlobal() |
// rather than going via the CFG and `isGlobal()`. func.getADecorator() = id.getNode()
func.getADecorator().(Name).getId() = "classmethod" )
or or
exists(Class cls | exists(Class cls |
cls.getAMethod() = func and cls.getAMethod() = func and
@@ -288,8 +285,9 @@ predicate isClassmethod(Function func) {
/** Holds if the function `func` has a `property` decorator. */ /** Holds if the function `func` has a `property` decorator. */
overlay[local] overlay[local]
predicate hasPropertyDecorator(Function func) { predicate hasPropertyDecorator(Function func) {
// See `isStaticmethod` for the rationale for matching on the AST `Name`. exists(NameNode id | id.getId() = "property" and id.isGlobal() |
func.getADecorator().(Name).getId() = "property" func.getADecorator() = id.getNode()
)
} }
/** /**

View File

@@ -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 * 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. * no reason to include steps for list content right now.
*/ */
predicate storeStepCommon(Node nodeFrom, Content c, Node nodeTo) { predicate storeStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) {
tupleStoreStep(nodeFrom, c, nodeTo) tupleStoreStep(nodeFrom, c, nodeTo)
or or
dictStoreStep(nodeFrom, c, nodeTo) dictStoreStep(nodeFrom, c, nodeTo)
@@ -767,8 +767,7 @@ predicate storeStepCommon(Node nodeFrom, Content c, Node nodeTo) {
* Holds if data can flow from `nodeFrom` to `nodeTo` via an assignment to * Holds if data can flow from `nodeFrom` to `nodeTo` via an assignment to
* content `c`. * content `c`.
*/ */
predicate storeStep(Node nodeFrom, ContentSet cs, Node nodeTo) { predicate storeStep(Node nodeFrom, ContentSet c, Node nodeTo) {
exists(Content c | cs = singleton(c) |
storeStepCommon(nodeFrom, c, nodeTo) storeStepCommon(nodeFrom, c, nodeTo)
or or
listStoreStep(nodeFrom, c, nodeTo) listStoreStep(nodeFrom, c, nodeTo)
@@ -781,6 +780,9 @@ predicate storeStep(Node nodeFrom, ContentSet cs, Node nodeTo) {
or or
any(Orm::AdditionalOrmSteps es).storeStep(nodeFrom, c, nodeTo) any(Orm::AdditionalOrmSteps es).storeStep(nodeFrom, c, nodeTo)
or or
FlowSummaryImpl::Private::Steps::summaryStoreStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), c,
nodeTo.(FlowSummaryNode).getSummaryNode())
or
synthStarArgsElementParameterNodeStoreStep(nodeFrom, c, nodeTo) synthStarArgsElementParameterNodeStoreStep(nodeFrom, c, nodeTo)
or or
synthDictSplatArgumentNodeStoreStep(nodeFrom, c, nodeTo) synthDictSplatArgumentNodeStoreStep(nodeFrom, c, nodeTo)
@@ -788,10 +790,6 @@ predicate storeStep(Node nodeFrom, ContentSet cs, Node nodeTo) {
yieldStoreStep(nodeFrom, c, nodeTo) yieldStoreStep(nodeFrom, c, nodeTo)
or or
VariableCapture::storeStep(nodeFrom, c, nodeTo) VariableCapture::storeStep(nodeFrom, c, nodeTo)
)
or
FlowSummaryImpl::Private::Steps::summaryStoreStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), cs,
nodeTo.(FlowSummaryNode).getSummaryNode())
} }
/** /**
@@ -987,7 +985,7 @@ predicate attributeStoreStep(Node nodeFrom, AttributeContent c, Node nodeTo) {
/** /**
* Subset of `readStep` that should be shared with type-tracking. * Subset of `readStep` that should be shared with type-tracking.
*/ */
predicate readStepCommon(Node nodeFrom, Content c, Node nodeTo) { predicate readStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) {
subscriptReadStep(nodeFrom, c, nodeTo) subscriptReadStep(nodeFrom, c, nodeTo)
or or
iterableUnpackingReadStep(nodeFrom, c, nodeTo) iterableUnpackingReadStep(nodeFrom, c, nodeTo)
@@ -996,8 +994,7 @@ predicate readStepCommon(Node nodeFrom, Content c, Node nodeTo) {
/** /**
* Holds if data can flow from `nodeFrom` to `nodeTo` via a read of content `c`. * Holds if data can flow from `nodeFrom` to `nodeTo` via a read of content `c`.
*/ */
predicate readStep(Node nodeFrom, ContentSet cs, Node nodeTo) { predicate readStep(Node nodeFrom, ContentSet c, Node nodeTo) {
exists(Content c | cs = singleton(c) |
readStepCommon(nodeFrom, c, nodeTo) readStepCommon(nodeFrom, c, nodeTo)
or or
matchReadStep(nodeFrom, c, nodeTo) matchReadStep(nodeFrom, c, nodeTo)
@@ -1006,15 +1003,12 @@ predicate readStep(Node nodeFrom, ContentSet cs, Node nodeTo) {
or or
attributeReadStep(nodeFrom, c, nodeTo) attributeReadStep(nodeFrom, c, nodeTo)
or or
FlowSummaryImpl::Private::Steps::summaryReadStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), c,
nodeTo.(FlowSummaryNode).getSummaryNode())
or
synthDictSplatParameterNodeReadStep(nodeFrom, c, nodeTo) synthDictSplatParameterNodeReadStep(nodeFrom, c, nodeTo)
or or
VariableCapture::readStep(nodeFrom, c, nodeTo) VariableCapture::readStep(nodeFrom, c, nodeTo)
)
or
FlowSummaryImpl::Private::Steps::summaryReadStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), cs,
nodeTo.(FlowSummaryNode).getSummaryNode())
or
Conversions::readStep(nodeFrom, cs, nodeTo)
} }
/** Data flows from a sequence to a subscript of the sequence. */ /** Data flows from a sequence to a subscript of the sequence. */
@@ -1070,68 +1064,23 @@ predicate attributeReadStep(Node nodeFrom, AttributeContent c, AttrRead nodeTo)
nodeTo.accesses(nodeFrom, c.getAttribute()) 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.isAnyTupleOrDictionaryElement()
}
predicate encoderReadStep(Node nodeFrom, ContentSet c, Node nodeTo) {
exists(Encoding encoding |
nodeFrom = encoding.getAnInput() and
nodeTo = encoding.getOutput()
) and
c.isAnyTupleOrDictionaryElement()
}
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.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.isAnyDictionaryElement()
}
predicate readStep(Node nodeFrom, ContentSet c, Node nodeTo) {
decoderReadStep(nodeFrom, c, nodeTo)
or
encoderReadStep(nodeFrom, c, nodeTo)
or
formatReadStep(nodeFrom, c, nodeTo)
}
}
/** /**
* Holds if values stored inside content `c` are cleared at node `n`. For example, * 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` * any value stored inside `f` is cleared at the pre-update node associated with `x`
* in `x.f = newValue`. * in `x.f = newValue`.
*/ */
predicate clearsContent(Node n, ContentSet cs) { predicate clearsContent(Node n, ContentSet c) {
exists(Content c | cs = singleton(c) |
matchClearStep(n, c) matchClearStep(n, c)
or or
attributeClearStep(n, c) attributeClearStep(n, c)
or or
dictClearStep(n, c) dictClearStep(n, c)
or or
FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c)
or
dictSplatParameterNodeClearStep(n, c) dictSplatParameterNodeClearStep(n, c)
or or
VariableCapture::clearsContent(n, c) VariableCapture::clearsContent(n, c)
)
or
FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), cs)
} }
/** /**
@@ -1249,65 +1198,12 @@ 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`. */ /** An approximated `Content`. */
class ContentApprox extends TContentApprox { class ContentApprox = Unit;
/** Gets a textual representation of this element. */
string toString() { result = "" }
}
/** Gets an approximated value for content `c`. */ /** Gets an approximated value for content `c`. */
ContentApprox getContentApprox(Content c) { pragma[inline]
c = TListElementContent() and ContentApprox getContentApprox(Content c) { any() }
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`. */ /** Helper for `.getEnclosingCallable`. */
DataFlowCallable getCallableScope(Scope s) { DataFlowCallable getCallableScope(Scope s) {

View File

@@ -898,78 +898,19 @@ class CapturedVariableContent extends Content, TCapturedVariableContent {
override string getMaDRepresentation() { none() } 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() or
TAnyTupleOrDictionaryElement()
/** /**
* An entity that represents a set of `Content`s. * An entity that represents a set of `Content`s.
* *
* The set may be interpreted differently depending on whether it is * The set may be interpreted differently depending on whether it is
* stored into (`getAStoreContent`) or read from (`getAReadContent`). * stored into (`getAStoreContent`) or read from (`getAReadContent`).
*/ */
class ContentSet extends TContentSet { class ContentSet instanceof Content {
/** 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() }
/** 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. */ /** Gets a content that may be stored into when storing into this set. */
Content getAStoreContent() { this = TSingletonContent(result) } Content getAStoreContent() { result = this }
/** Gets a content that may be read from when reading from this set. */ /** Gets a content that may be read from when reading from this set. */
Content getAReadContent() { Content getAReadContent() { result = this }
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)
or
this = TAnyTupleOrDictionaryElement() and
(
result instanceof TupleElementContent or
result instanceof DictionaryElementContent or
result instanceof DictionaryElementAnyContent
)
}
/** Gets a textual representation of this content set. */ /** Gets a textual representation of this content set. */
string toString() { string toString() { result = super.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"
or
this = TAnyTupleOrDictionaryElement() and result = "Any tuple or dictionary element"
}
} }
/** Gets the singleton `ContentSet` wrapping the `Content` `c`. */
ContentSet singleton(Content c) { result = TSingletonContent(c) }

View File

@@ -66,29 +66,21 @@ module Input implements InputSig<Location, DataFlowImplSpecific::PythonDataFlow>
} }
string encodeContent(ContentSet cs, string arg) { string encodeContent(ContentSet cs, string arg) {
exists(Content c | cs.isSingleton(c) | cs = TListElementContent() and result = "ListElement" and arg = ""
c = TListElementContent() and result = "ListElement" and arg = ""
or or
c = TSetElementContent() and result = "SetElement" and arg = "" cs = TSetElementContent() and result = "SetElement" and arg = ""
or or
exists(int index | exists(int index |
c = TTupleElementContent(index) and result = "TupleElement" and arg = index.toString() cs = TTupleElementContent(index) and result = "TupleElement" and arg = index.toString()
) )
or or
exists(string key | exists(string key |
c = TDictionaryElementContent(key) and result = "DictionaryElement" and arg = key cs = TDictionaryElementContent(key) and result = "DictionaryElement" and arg = key
) )
or or
c = TDictionaryElementAnyContent() and result = "DictionaryElementAny" and arg = "" cs = TDictionaryElementAnyContent() and result = "DictionaryElementAny" and arg = ""
or or
exists(string attr | c = TAttributeContent(attr) and result = "Attribute" and arg = attr) exists(string attr | cs = TAttributeContent(attr) and result = "Attribute" and arg = attr)
)
or
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] bindingset[token]
@@ -147,29 +139,27 @@ module Private {
predicate withContent = SC::withContent/1; predicate withContent = SC::withContent/1;
/** Gets a summary component that represents a list element. */ /** Gets a summary component that represents a list element. */
SummaryComponent listElement() { result = content(singleton(any(ListElementContent c))) } SummaryComponent listElement() { result = content(any(ListElementContent c)) }
/** Gets a summary component that represents a set element. */ /** Gets a summary component that represents a set element. */
SummaryComponent setElement() { result = content(singleton(any(SetElementContent c))) } SummaryComponent setElement() { result = content(any(SetElementContent c)) }
/** Gets a summary component that represents a tuple element. */ /** Gets a summary component that represents a tuple element. */
SummaryComponent tupleElement(int index) { SummaryComponent tupleElement(int index) {
exists(TupleElementContent c | c.getIndex() = index and result = content(singleton(c))) exists(TupleElementContent c | c.getIndex() = index and result = content(c))
} }
/** Gets a summary component that represents a dictionary element. */ /** Gets a summary component that represents a dictionary element. */
SummaryComponent dictionaryElement(string key) { SummaryComponent dictionaryElement(string key) {
exists(DictionaryElementContent c | c.getKey() = key and result = content(singleton(c))) exists(DictionaryElementContent c | c.getKey() = key and result = content(c))
} }
/** Gets a summary component that represents a dictionary element at any key. */ /** Gets a summary component that represents a dictionary element at any key. */
SummaryComponent dictionaryElementAny() { SummaryComponent dictionaryElementAny() { result = content(any(DictionaryElementAnyContent c)) }
result = content(singleton(any(DictionaryElementAnyContent c)))
}
/** Gets a summary component that represents an attribute element. */ /** Gets a summary component that represents an attribute element. */
SummaryComponent attribute(string attr) { SummaryComponent attribute(string attr) {
exists(AttributeContent c | c.getAttribute() = attr and result = content(singleton(c))) exists(AttributeContent c | c.getAttribute() = attr and result = content(c))
} }
/** Gets a summary component that represents the return value of a call. */ /** Gets a summary component that represents the return value of a call. */

View File

@@ -11,34 +11,12 @@ private import semmle.python.ApiGraphs
*/ */
predicate defaultTaintSanitizer(DataFlow::Node node) { none() } 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.isAnyTupleOrDictionaryElement()
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 * Holds if default `TaintTracking::Configuration`s should allow implicit reads
* of `c` at sinks and inputs to additional taint steps. * of `c` at sinks and inputs to additional taint steps.
*/ */
bindingset[node] bindingset[node]
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { none() }
exists(node) and
defaultTaintReadContent(c)
}
private module Cached { private module Cached {
/** /**
@@ -150,6 +128,11 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT
nodeFrom.getNode() = object and nodeFrom.getNode() = object and
method_name in ["partition", "rpartition", "rsplit", "split", "splitlines"] method_name in ["partition", "rpartition", "rsplit", "split", "splitlines"]
or 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 // Mapping[str, Any] -> str
method_name = "format_map" and method_name = "format_map" and
nodeFrom.getNode() = call.getArg(0) nodeFrom.getNode() = call.getArg(0)
@@ -178,21 +161,32 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT
} }
/** /**
* Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to reading * Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to containers
* content from containers (lists/sets/dictionaries/tuples): subscripts, iteration, * (lists/sets/dictionaries): literals, constructor invocation, methods. Note that this
* constructor invocation, methods. * is currently very imprecise, as an example, since we model `dict.get`, we treat any
* `<tainted object>.get(<arg>)` will be tainted, whether it's true or not.
*/ */
predicate containerStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { predicate containerStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
exists(DataFlow::ContentSet contentSet | // construction by literal
DataFlowPrivate::readStep(nodeFrom, contentSet, nodeTo) and //
exists(DataFlow::Content c | c = contentSet.getAReadContent() | // TODO: once we have proper flow-summary modeling, we might not need this step any
c instanceof DataFlow::TupleElementContent or // longer -- but there needs to be a matching read-step for the store-step, and we
c instanceof DataFlow::DictionaryElementContent or // don't provide that right now.
c instanceof DataFlow::DictionaryElementAnyContent or DataFlowPrivate::listStoreStep(nodeFrom, _, nodeTo)
c instanceof DataFlow::ListElementContent or or
c instanceof DataFlow::SetElementContent 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.
//
// 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)
} }
/** /**

View File

@@ -241,7 +241,7 @@ module TypeTrackingInput implements Shared::TypeTrackingInput<Location> {
// is only fed set/list content) // is only fed set/list content)
not nodeFrom instanceof DataFlowPublic::IterableElementNode not nodeFrom instanceof DataFlowPublic::IterableElementNode
or or
TypeTrackerSummaryFlow::basicStoreStep(nodeFrom, nodeTo, DataFlowPublic::singleton(content)) TypeTrackerSummaryFlow::basicStoreStep(nodeFrom, nodeTo, content)
} }
/** /**
@@ -272,15 +272,14 @@ module TypeTrackingInput implements Shared::TypeTrackingInput<Location> {
nodeFrom.asCfgNode() instanceof SequenceNode nodeFrom.asCfgNode() instanceof SequenceNode
) )
or or
TypeTrackerSummaryFlow::basicLoadStep(nodeFrom, nodeTo, DataFlowPublic::singleton(content)) TypeTrackerSummaryFlow::basicLoadStep(nodeFrom, nodeTo, content)
} }
/** /**
* Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`. * Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`.
*/ */
predicate loadStoreStep(Node nodeFrom, Node nodeTo, Content loadContent, Content storeContent) { predicate loadStoreStep(Node nodeFrom, Node nodeTo, Content loadContent, Content storeContent) {
TypeTrackerSummaryFlow::basicLoadStoreStep(nodeFrom, nodeTo, TypeTrackerSummaryFlow::basicLoadStoreStep(nodeFrom, nodeTo, loadContent, storeContent)
DataFlowPublic::singleton(loadContent), DataFlowPublic::singleton(storeContent))
} }
/** /**

View File

@@ -4244,7 +4244,6 @@ module StdlibPrivate {
) )
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent // TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and ) and
// Element content is mutated into list element content
output = "ReturnValue.ListElement" and output = "ReturnValue.ListElement" and
preservesValue = true preservesValue = true
or or
@@ -4271,9 +4270,11 @@ module StdlibPrivate {
preservesValue = true preservesValue = true
) )
or or
input = "Argument[0].ListElement" and // TODO: We need to also translate iterable content such as list element
// but we currently lack TupleElementAny
input = "Argument[0]" and
output = "ReturnValue" and output = "ReturnValue" and
preservesValue = true preservesValue = false
} }
} }
@@ -4968,26 +4969,6 @@ 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) {
(
// For code like `" ".join([name])`
input = "Argument[0,iterable:].ListElement" and
preservesValue = true
) and
output = "ReturnValue"
}
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// asyncio // asyncio
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@@ -1,6 +0,0 @@
extensions:
- addsTo:
pack: codeql/python-all
extensible: summaryModel
data:
- ['lxml', 'Member[etree].Member[fromstringlist]', 'Argument[0,strings:].ListElement', 'ReturnValue', 'taint']

View File

@@ -1,6 +0,0 @@
extensions:
- addsTo:
pack: codeql/python-all
extensible: summaryModel
data:
- ['xml', 'Member[etree].Member[fromstringlist]', 'Argument[0,strings:].ListElement', 'ReturnValue', 'taint']

View File

@@ -61,11 +61,10 @@ module EscapingCaptureFlowConfig implements DataFlow::ConfigSig {
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet cs) { predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet cs) {
isSink(node) and isSink(node) and
( (
cs.isAnyTupleOrDictionaryElement() cs.(DataFlow::TupleElementContent).getIndex() in [0 .. 10] or
or cs instanceof DataFlow::ListElementContent or
cs.getAStoreContent() instanceof DataFlow::ListElementContent cs instanceof DataFlow::SetElementContent or
or cs instanceof DataFlow::DictionaryElementAnyContent
cs.getAStoreContent() instanceof DataFlow::SetElementContent
) )
} }
} }

View File

@@ -3,15 +3,11 @@ edges
| TarSlipImprov.py:15:7:15:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:15:1:15:3 | ControlFlowNode for tar | provenance | | | 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: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 | 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 | 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: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: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 | 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 | 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: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: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 | | | TarSlipImprov.py:39:65:39:67 | ControlFlowNode for tar | TarSlipImprov.py:26:21:26:27 | ControlFlowNode for tarfile | provenance | |
@@ -38,19 +34,16 @@ edges
| TarSlipImprov.py:142:9:142:13 | ControlFlowNode for entry | TarSlipImprov.py:143:36:143:40 | ControlFlowNode for entry | provenance | | | 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: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: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: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 [List element] | TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() [List element] | provenance | | | TarSlipImprov.py:152:13:152:20 | ControlFlowNode for Yield | TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() | 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: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 | 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() | 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: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: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: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 | 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: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: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 | | | TarSlipImprov.py:177:9:177:13 | ControlFlowNode for entry | TarSlipImprov.py:178:36:178:40 | ControlFlowNode for entry | provenance | |
@@ -67,9 +60,7 @@ edges
| TarSlipImprov.py:231:43:231:52 | ControlFlowNode for corpus_tar | TarSlipImprov.py:233:9:233:9 | ControlFlowNode for f | provenance | | | 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: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 | 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 | 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: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: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 | | | TarSlipImprov.py:259:9:259:13 | ControlFlowNode for entry | TarSlipImprov.py:261:25:261:29 | ControlFlowNode for entry | provenance | |
@@ -94,24 +85,19 @@ edges
| TarSlipImprov.py:304:7:304:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:304:1:304:3 | ControlFlowNode for tar | provenance | | | 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: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 | 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 | 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 nodes
| TarSlipImprov.py:15:1:15:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | | 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: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: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 | 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: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: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: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: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 | 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: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 | 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: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: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() | | TarSlipImprov.py:39:49:39:68 | ControlFlowNode for members_filter1() | semmle.label | ControlFlowNode for members_filter1() |
@@ -147,17 +133,14 @@ nodes
| TarSlipImprov.py:151:14:151:50 | ControlFlowNode for closing() | semmle.label | ControlFlowNode for closing() | | 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: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:151:55:151:56 | ControlFlowNode for tf | semmle.label | ControlFlowNode for tf |
| TarSlipImprov.py:152:13:152:20 | ControlFlowNode for Yield [List element] | semmle.label | ControlFlowNode for Yield [List element] | | TarSlipImprov.py:152:13:152:20 | ControlFlowNode for Yield | semmle.label | ControlFlowNode for Yield |
| TarSlipImprov.py:152:19:152:20 | ControlFlowNode for tf | semmle.label | ControlFlowNode for tf | | 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 | 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() | 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: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: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: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 | 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: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: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 | | TarSlipImprov.py:176:36:176:38 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar |
@@ -180,7 +163,6 @@ nodes
| TarSlipImprov.py:231:43:231:52 | ControlFlowNode for corpus_tar | semmle.label | ControlFlowNode for corpus_tar | | 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: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 | 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: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: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() | | TarSlipImprov.py:254:1:254:31 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
@@ -216,13 +198,11 @@ nodes
| TarSlipImprov.py:304:7:304:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | 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: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 | 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: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: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() | | TarSlipImprov.py:316:1:316:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
subpaths 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 | 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 #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: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() | | 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() |

View File

@@ -93,9 +93,7 @@ edges
| UnsafeUnpack.py:163:23:163:28 | ControlFlowNode for member | UnsafeUnpack.py:166:37:166:42 | ControlFlowNode for member | provenance | | | 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: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 | 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 | 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: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: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 | | | UnsafeUnpack.py:173:11:173:17 | ControlFlowNode for tarpath | UnsafeUnpack.py:176:17:176:23 | ControlFlowNode for tarpath | provenance | |
@@ -191,7 +189,6 @@ nodes
| UnsafeUnpack.py:163:23:163:28 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | | 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: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 | 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: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: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 | | UnsafeUnpack.py:171:1:171:8 | ControlFlowNode for response | semmle.label | ControlFlowNode for response |

View File

@@ -3,10 +3,8 @@ 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: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: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:22:52:22:54 | ControlFlowNode for cmd | 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:23:41:23:57 | ControlFlowNode for List | provenance | |
| Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:24:48:24:50 | 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: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 | | | 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 | | | Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | Scrapli.py:24:42:24:44 | ControlFlowNode for cmd | provenance | |
@@ -34,8 +32,6 @@ nodes
| Netmiko.py:21:52:21:54 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | | 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: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: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 | | 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: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 | | Pexpect.py:16:14:16:16 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd |

View File

@@ -7,7 +7,6 @@ edges
| xslt.py:10:17:10:43 | ControlFlowNode for Attribute() | xslt.py:10:5:10:13 | ControlFlowNode for xsltQuery | provenance | | | 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: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: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 | Config |
| xslt.py:11:27:11:35 | ControlFlowNode for xsltQuery | xslt.py:11:17:11:36 | ControlFlowNode for Attribute() | provenance | Decoding-XML | | 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 | | | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:3:26:3:32 | ControlFlowNode for request | provenance | |
@@ -22,7 +21,6 @@ edges
| xsltInjection.py:10:17:10:43 | ControlFlowNode for Attribute() | xsltInjection.py:10:5:10:13 | ControlFlowNode for xsltQuery | provenance | | | 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: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: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 | Config |
| xsltInjection.py:11:27:11:35 | ControlFlowNode for xsltQuery | xsltInjection.py:11:17:11:36 | ControlFlowNode for Attribute() | provenance | Decoding-XML | | 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 | | | xsltInjection.py:17:5:17:13 | ControlFlowNode for xsltQuery | xsltInjection.py:18:27:18:35 | ControlFlowNode for xsltQuery | provenance | |
@@ -31,7 +29,6 @@ edges
| xsltInjection.py:17:17:17:43 | ControlFlowNode for Attribute() | xsltInjection.py:17:5:17:13 | ControlFlowNode for xsltQuery | provenance | | | 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: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: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 | Config |
| xsltInjection.py:18:27:18:35 | ControlFlowNode for xsltQuery | xsltInjection.py:18:17:18:36 | ControlFlowNode for Attribute() | provenance | Decoding-XML | | 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 | | | xsltInjection.py:26:5:26:13 | ControlFlowNode for xsltQuery | xsltInjection.py:27:27:27:35 | ControlFlowNode for xsltQuery | provenance | |
@@ -40,7 +37,6 @@ edges
| xsltInjection.py:26:17:26:43 | ControlFlowNode for Attribute() | xsltInjection.py:26:5:26:13 | ControlFlowNode for xsltQuery | provenance | | | 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: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: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 | Config |
| xsltInjection.py:27:27:27:35 | ControlFlowNode for xsltQuery | xsltInjection.py:27:17:27:36 | ControlFlowNode for Attribute() | provenance | Decoding-XML | | 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 | | | xsltInjection.py:35:5:35:13 | ControlFlowNode for xsltQuery | xsltInjection.py:36:34:36:42 | ControlFlowNode for xsltQuery | provenance | |
@@ -49,22 +45,17 @@ edges
| xsltInjection.py:35:17:35:43 | ControlFlowNode for Attribute() | xsltInjection.py:35:5:35:13 | ControlFlowNode for xsltQuery | provenance | | | 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: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: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 | Config |
| xsltInjection.py:36:34:36:42 | ControlFlowNode for xsltQuery | xsltInjection.py:36:17:36:43 | ControlFlowNode for Attribute() | provenance | Decoding-XML | | 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:20:45:28 | ControlFlowNode for xsltQuery | provenance | | | xsltInjection.py:44:5:44:13 | ControlFlowNode for xsltQuery | xsltInjection.py:45:5:45:15 | ControlFlowNode for xsltStrings | 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: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: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: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 [List element] | xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | provenance | | | xsltInjection.py:45:5:45:15 | ControlFlowNode for xsltStrings | xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings | 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: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: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 [List element] | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | 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 [List element] | 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 | 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 nodes
| xslt.py:3:26:3:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | 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 | | xslt.py:3:26:3:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
@@ -114,12 +105,10 @@ nodes
| xsltInjection.py:44:17:44:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | 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: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:44:17:44:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| xsltInjection.py:45:5:45:15 | ControlFlowNode for xsltStrings [List element] | semmle.label | ControlFlowNode for xsltStrings [List element] | | xsltInjection.py:45:5:45:15 | ControlFlowNode for xsltStrings | semmle.label | ControlFlowNode for xsltStrings |
| 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: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:17:46:49 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | semmle.label | ControlFlowNode for xsltStrings [List element] | | xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings | semmle.label | ControlFlowNode for xsltStrings |
| xsltInjection.py:50:24:50:32 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root | | xsltInjection.py:50:24:50:32 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root |
subpaths subpaths
#select #select

View File

@@ -32,13 +32,11 @@ 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: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: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 |
| 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: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: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: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: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 |
| 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 | | | 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 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 | | | anthropic_test.py:2:26:2:32 | ControlFlowNode for request | anthropic_test.py:11:15:11:21 | ControlFlowNode for request | provenance | |
@@ -63,7 +61,7 @@ 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: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: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: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: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: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: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:63:28:63:51 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:8 |
@@ -74,7 +72,7 @@ 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: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: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: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: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: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: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:53:33:53:37 | ControlFlowNode for query | provenance | |
@@ -84,14 +82,6 @@ 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: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: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: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 models
| 1 | Sink: Anthropic; Member[beta].Member[messages].Member[create].Argument[messages:].ListElement.DictionaryElement[content]; prompt-injection | | 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 | | 2 | Sink: Anthropic; Member[beta].Member[messages].Member[create].Argument[system:]; prompt-injection |
@@ -150,13 +140,7 @@ nodes
| openai_test.py:18:15:18:19 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | | 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: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: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: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: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: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 | | openai_test.py:42:15:42:19 | ControlFlowNode for query | semmle.label | ControlFlowNode for query |

View File

@@ -131,5 +131,6 @@ from unknown_settings import password # $ SensitiveDataSource=password
print(password) # $ SensitiveUse=password print(password) # $ SensitiveUse=password
_config = {"sleep_timer": 5, "mysql_password": password} _config = {"sleep_timer": 5, "mysql_password": password}
# since we have precise dictionary content, other items of the config are not tainted # since we have taint-step from store of `password`, we will consider any item in the
print(_config["sleep_timer"]) # dictionary to be a password :(
print(_config["sleep_timer"]) # $ SPURIOUS: SensitiveUse=password

View File

@@ -7,9 +7,13 @@ edges
| summaries.py:36:38:36:38 | ControlFlowNode for x | summaries.py:36:41:36:45 | ControlFlowNode for BinaryExpr | provenance | | | 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: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: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: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: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: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: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: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 | | | summaries.py:48:15:48:15 | ControlFlowNode for x | summaries.py:49:12:49:18 | ControlFlowNode for BinaryExpr | provenance | |
@@ -38,7 +42,6 @@ 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 | 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: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: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: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: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 | | | summaries.py:68:6:68:23 | ControlFlowNode for tainted_resultlist [List element] | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | provenance | |
@@ -53,8 +56,11 @@ nodes
| summaries.py:36:41:36:45 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | 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: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: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: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: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: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: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] | | summaries.py:45:6:45:17 | ControlFlowNode for tainted_list [List element] | semmle.label | ControlFlowNode for tainted_list [List element] |

View File

@@ -32,6 +32,7 @@ def test_construction():
list(tainted_tuple), # $ tainted list(tainted_tuple), # $ tainted
list(tainted_set), # $ tainted list(tainted_set), # $ tainted
list(tainted_dict.values()), # $ tainted list(tainted_dict.values()), # $ tainted
list(tainted_dict.items()), # $ tainted
tuple(tainted_list), # $ tainted tuple(tainted_list), # $ tainted
set(tainted_list), # $ tainted set(tainted_list), # $ tainted
@@ -40,11 +41,10 @@ def test_construction():
dict(k = tainted_string)["k"], # $ tainted dict(k = tainted_string)["k"], # $ tainted
dict(dict(k = tainted_string))["k"], # $ tainted dict(dict(k = tainted_string))["k"], # $ tainted
dict(["k", tainted_string]), # $ tainted dict(["k", tainted_string]), # $ tainted
list(tainted_dict.items()), # $ tainted
) )
ensure_not_tainted( ensure_not_tainted(
dict(k = tainted_string)["k1"], dict(k = tainted_string)["k1"]
) )
@@ -59,7 +59,7 @@ def test_access(x, y, z):
sorted(tainted_list), # $ tainted sorted(tainted_list), # $ tainted
reversed(tainted_list), # $ tainted reversed(tainted_list), # $ tainted
iter(tainted_list), # $ tainted iter(tainted_list), # $ tainted
next(iter(tainted_list)), # $ tainted next(iter(tainted_list)), # $ MISSING: tainted
[i for i in tainted_list], # $ tainted [i for i in tainted_list], # $ tainted
[tainted_list for _i in [1,2,3]], # $ tainted [tainted_list for _i in [1,2,3]], # $ tainted
) )

View File

@@ -53,7 +53,7 @@ def contrived_1():
(a, b, c), (d, e, f) = tainted_list, no_taint_list (a, b, c), (d, e, f) = tainted_list, no_taint_list
ensure_tainted(a, b, c) # $ tainted ensure_tainted(a, b, c) # $ tainted
ensure_not_tainted(d, e, f) ensure_not_tainted(d, e, f) # $ SPURIOUS: tainted
def contrived_2(): def contrived_2():

View File

@@ -3,12 +3,10 @@ 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: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: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: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: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: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: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: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 | | 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 nodes
@@ -19,8 +17,6 @@ nodes
| taint_step_test.py:11:18:11:21 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | | 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: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: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: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: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 | | taint_step_test.py:19:48:19:51 | ControlFlowNode for file | semmle.label | ControlFlowNode for file |

View File

@@ -7,49 +7,3 @@ cursor.execute("some sql", (42,)) # $ getSql="some sql"
cursor.executemany("some sql", (42,)) # $ getSql="some sql" cursor.executemany("some sql", (42,)) # $ getSql="some sql"
cursor.close() cursor.close()
# ---------------------------------------------------------------------------
# Connection stored in a class attribute and accessed via various patterns
# ---------------------------------------------------------------------------
class WrapperA:
def __init__(self):
self._conn = dbapi.connect(address="hostname", port=300, user="username", pass_arg="testpass")
def get_connection(self):
return self._conn
# Getter called on a fresh constructor result
conn_a1 = WrapperA().get_connection()
cursor_a1 = conn_a1.cursor()
cursor_a1.execute("some sql", (42,)) # $ MISSING: getSql="some sql"
# Getter called via a stored wrapper instance
wrapper_instance = WrapperA()
conn_a2 = wrapper_instance.get_connection()
cursor_a2 = conn_a2.cursor()
cursor_a2.execute("some sql", (42,)) # $ MISSING: getSql="some sql"
# Direct attribute access on a fresh constructor result
conn_b = WrapperA()._conn
cursor_b = conn_b.cursor()
cursor_b.execute("some sql", (42,)) # $ MISSING: getSql="some sql"
class WrapperB:
"""Stores the connection under a different attribute name."""
def __init__(self):
self._hana = dbapi.connect(address="hostname", port=300, user="username", pass_arg="testpass")
def cursor(self):
return self._hana.cursor()
# Direct attribute access on a stored instance (mirrors hdb_con3 in the issue)
conn_c = WrapperB()._hana
cursor_c = conn_c.cursor()
cursor_c.execute("some sql", (42,)) # $ MISSING: getSql="some sql"

View File

@@ -6,16 +6,16 @@ pat = ... # some pattern
compiled_pat = re.compile(pat) compiled_pat = re.compile(pat)
# see https://docs.python.org/3/library/re.html#functions # see https://docs.python.org/3/library/re.html#functions
ensure_tainted( ensure_not_tainted(
# returns Match object, which is tested properly below. (note: the match objects contain # returns Match object, which is tested properly below. (note: with the flow summary
# tainted values but are not themselves tainted - this test relies on implicit reads at sinks). # modeling, objects containing tainted values are not themselves tainted).
re.search(pat, ts), # $ tainted re.search(pat, ts),
re.match(pat, ts), # $ tainted re.match(pat, ts),
re.fullmatch(pat, ts), # $ tainted re.fullmatch(pat, ts),
compiled_pat.search(ts), # $ tainted compiled_pat.search(ts),
compiled_pat.match(ts), # $ tainted compiled_pat.match(ts),
compiled_pat.fullmatch(ts), # $ tainted compiled_pat.fullmatch(ts),
) )
# Match object # Match object
@@ -80,9 +80,9 @@ ensure_tainted(
) )
ensure_not_tainted( ensure_not_tainted(
re.subn(pat, repl="safe", string=ts),
re.subn(pat, repl="safe", string=ts)[1], # // the number of substitutions made re.subn(pat, repl="safe", string=ts)[1], # // the number of substitutions made
) )
ensure_tainted( 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 re.subn(pat, repl="safe", string=ts)[0], # $ tainted // the string
) )

View File

@@ -63,8 +63,7 @@ class TaintTest(tornado.web.RequestHandler):
request.headers["header-name"], # $ tainted request.headers["header-name"], # $ tainted
request.headers.get_list("header-name"), # $ tainted request.headers.get_list("header-name"), # $ tainted
request.headers.get_all(), # $ tainted request.headers.get_all(), # $ tainted
[(k, v) for (k, v) in request.headers.get_all()][0], # $ tainted [(k, v) for (k, v) in request.headers.get_all()], # $ tainted
list([(k, v) for (k, v) in request.headers.get_all()])[0], # $ tainted
# Dict[str, http.cookies.Morsel] # Dict[str, http.cookies.Morsel]
request.cookies, # $ tainted request.cookies, # $ tainted
@@ -72,11 +71,6 @@ class TaintTest(tornado.web.RequestHandler):
request.cookies["cookie-name"].key, # $ tainted request.cookies["cookie-name"].key, # $ tainted
request.cookies["cookie-name"].value, # $ tainted request.cookies["cookie-name"].value, # $ tainted
request.cookies["cookie-name"].coded_value, # $ tainted request.cookies["cookie-name"].coded_value, # $ tainted
# 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
) )

View File

@@ -11,13 +11,10 @@
edges 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: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: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:18 | ControlFlowNode for ALL_LOCALS | provenance | | | 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:8:20:17 | ControlFlowNode for ALL_LOCALS | provenance | | | 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:14:16:22 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:16:1:16:10 | 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: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 | BindToAllInterfaces_test.py:21:8:21:10 | ControlFlowNode for tup | 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: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: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 | | | 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 | |
@@ -28,10 +25,9 @@ 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: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: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: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:12 | ControlFlowNode for host | 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:8:46:44 | ControlFlowNode for Attribute() | BindToAllInterfaces_test.py:46:1:46:4 | 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: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: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 | | 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 nodes
@@ -41,11 +37,8 @@ nodes
| BindToAllInterfaces_test.py:9:9:9:16 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | | 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: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: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:17:9:17:24 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple |
| 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:1:20:3 | ControlFlowNode for tup | semmle.label | ControlFlowNode for tup |
| 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: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:12 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral |
| BindToAllInterfaces_test.py:26:9:26:18 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | | BindToAllInterfaces_test.py:26:9:26:18 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple |
@@ -62,7 +55,6 @@ nodes
| BindToAllInterfaces_test.py:46:1:46:4 | ControlFlowNode for host | semmle.label | ControlFlowNode for host | | 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: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: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: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:18 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral |
| BindToAllInterfaces_test.py:53:10:53:25 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | | BindToAllInterfaces_test.py:53:10:53:25 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple |

View File

@@ -5,13 +5,11 @@ 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: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: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: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: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: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: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: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: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: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: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 | | test.py:23:16:23:27 | ControlFlowNode for Attribute | test.py:23:16:23:39 | ControlFlowNode for Attribute() | provenance | dict.get |

View File

@@ -1,13 +1,10 @@
edges 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: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: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:34:11:37 | 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:35:14:38 | ControlFlowNode for name | 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: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: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: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: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: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 | | | 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 | |
@@ -18,10 +15,7 @@ nodes
| src/unsafe_shell_test.py:5:25:5:28 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | | 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: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: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: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: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: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 | | src/unsafe_shell_test.py:26:20:26:23 | ControlFlowNode for name | semmle.label | ControlFlowNode for name |

View File

@@ -7,10 +7,8 @@ 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: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: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: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: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: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: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 | | reflected_xss.py:27:23:27:29 | ControlFlowNode for request | reflected_xss.py:27:5:27:8 | ControlFlowNode for data | provenance | AdditionalTaintStep |
nodes nodes

Some files were not shown because too many files have changed in this diff Show More