Compare commits

..

30 Commits

Author SHA1 Message Date
yoff
cada7e98d2 Python: model exception edges for raise-prone expressions inside try/with
The new CFG previously only emitted exception edges for explicit `raise`
and `assert` statements. As a result, code that became reachable only
via the exception path of an arbitrary expression (e.g., the body of an
`except` handler following a try-body whose `call()` could raise) was
classified as dead, breaking analyses like StackTraceExposure,
FileNotAlwaysClosed, ExceptionInfo, UseOfExit, and CatchingBaseException.

This commit adds a `mayThrow` predicate over expressions that are known
sources of implicit exceptions in Python (calls, attribute access,
subscripts, arithmetic/comparison operators, imports, await/yield/yield
from) plus `from m import *` at the statement level, and routes them
through the shared CFG's `beginAbruptCompletion(_, _, ExceptionSuccessor,
always=false)` hook.

The set of exception sources is restricted to nodes that are
syntactically inside a `try`/`with` statement in the same scope.
This mirrors Java's `ControlFlowGraph::mayThrow`, which only emits
exception edges where local handling can observe them — outside such
contexts, the edges add CFG complexity (weakening BarrierGuard
precision and breaking SSA continuity around augmented assignments and
subscript stores) without analysis benefit, since exceptions just
propagate to the function exit anyway.

Net effect on the test suite: ~100 alerts restored across the exception-
related query tests (StackTraceExposure +29, ExceptionInfo +17,
FileNotAlwaysClosed +52, UseOfExit +1, CatchingBaseException restored)
with no precision regressions. Affected `.expected` files and the
regression-guard `dead_under_no_raise.py` are updated accordingly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-18 15:17:36 +00:00
yoff
3c9b0f770b Python: switch dataflow library to new (shared) CFG + SSA
Flips the Python dataflow trunk from the legacy CFG (semmle/python/Flow.qll)
and legacy ESSA SSA (semmle/python/essa/*) to the new shared CFG facade
(semmle.python.controlflow.internal.Cfg) and the new SSA adapter
(semmle.python.dataflow.new.internal.SsaImpl), both introduced
additively in the preceding PRs in this stack.

This is the trunk-flip equivalent of the original draft PR #21894 (kept
around as documentation), rebased on top of the four preparatory PRs:

  P1: Remove AstNode.getAFlowNode() and rewrite callers (#21919).
  P2: Qualify Flow.qll's AST references with Py:: prefix (#21920).
  P3: Add new shared-CFG-backed control flow graph (#21921).
  P4: Add new shared-SSA-backed SSA adapter (#21923).

The Python dataflow library (semmle/python/dataflow/new/) now imports
the new CFG facade and SSA adapter. All CFG-typed predicates
(ControlFlowNode, CallNode, BasicBlock, NameNode, AttrNode, ...) are
qualified with the Cfg:: prefix; SSA references switch from
EssaVariable/EssaDefinition to SsaImpl::Definition/SourceVariable.

GuardNode is redesigned to use the new CFG's outcome-node model
(isAfterTrue / isAfterFalse) instead of the legacy ConditionBlock +
flipped indirection. Only BarrierGuard<...> is preserved as public
API.

Framework files (Bottle, FastApi, Django, Tornado, Pyramid, Stdlib,
...) are updated to take CFG nodes from the new facade.

A handful of dataflow consistency tweaks for the new CFG:
- Augmented-assignment targets are treated as both load and store.
- 'from X import *' produces uncertain SSA writes for unknown names.
- CFG nodes are canonicalised so dataflow does not see equivalent
  pre/post-order pairs as distinct nodes.

Two AST tweaks for the new CFG:
- AstNodeImpl: omit PEP 695 type-parameter names from
  FunctionDefExpr / ClassDefExpr children.
- ImportResolution: drop the legacy essa import.

Test churn (~175 files): reblessed library- and query-test .expected
files reflect slightly different CFG granularity, different toString
output, and a handful of true alert deltas in security queries.

Verification: all 367 lib + src + consistency-queries compile clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-18 15:17:35 +00:00
Copilot
e93ef0f9d3 Python: add new shared-SSA-backed SSA adapter
Preparatory refactor for the shared-CFG dataflow migration. Adds the
new Python SSA adapter additively, without changing any production
behaviour.

Library additions:

- semmle.python.dataflow.new.internal.SsaImpl — Python SSA
  implementation built on the new (shared) CFG. Mirrors the Java SSA
  adapter (java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll):
  an InputSig is defined in terms of positional (BasicBlock, int)
  variable references, and the shared
  codeql.ssa.Ssa::Make<Location, Cfg, Input> module is then
  instantiated.

  SourceVariable is the AST-level Py::Variable. Variable references
  are looked up via the new CFG facade's NameNode.defines/uses/deletes
  predicates (added in the preceding PR), which themselves are
  one-line bridges to AST-level Name.defines/uses/deletes.

  Implicit-entry definitions are inserted for non-local/global/builtin
  reads, captured variables, and (when needed) parameters.

Test additions:

- library-tests/dataflow-new-ssa/ — exercises the new SSA over a
  representative test corpus and checks expected def/use chains.

- library-tests/dataflow-new-ssa-vs-legacy/ — runs both new SSA and
  legacy ESSA over the same corpus and diffs the results, so any
  semantic divergence shows up as a test failure.

Production impact:

None. The new SSA adapter has zero callers in lib/ and src/ — the
legacy ESSA SSA (semmle/python/essa/*) remains the default. The
dataflow library is not migrated yet; that lands in a follow-up PR.

Verified by:
- All 367 lib + src + consistency-queries compile clean.
- All 641 ControlFlow + PointsTo + dataflow + essa + consistency
  library-tests pass.
- Both new dataflow-new-ssa[/vs-legacy] test packs pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-18 15:17:34 +00:00
Copilot
6248d3ad9d Python: add new shared-CFG-backed control flow graph
Preparatory refactor for the shared-CFG dataflow migration. Adds the
new Python CFG library additively, without changing any production
behaviour.

Library additions:

- semmle.python.controlflow.internal.AstNodeImpl — mediates between
  the Python AST and the shared codeql.controlflow.ControlFlowGraph
  signature. Wraps Python's Stmt/Expr/Scope/Pattern and adds two
  synthetic kinds of node (BlockStmt for body slots, intermediate
  nodes for multi-operand boolean expressions).

- semmle.python.controlflow.internal.Cfg — public facade
  re-exposing the same API surface as semmle/python/Flow.qll
  (ControlFlowNode, CallNode, BasicBlock, NameNode, DefinitionNode,
  CompareNode, ...), backed by the shared CFG.

- lib/printCfgNew.ql — debug/visualisation query for the new CFG.

- consistency-queries/CfgConsistency.ql — consistency query running
  the shared CFG's standard checks against Python.

Shared library:

- shared.controlflow.ControlFlowGraph — adds two defaulted
  getWhileElse / getForeachElse predicates to AstSig so Python can
  model while-else / for-else (no behavioural change for other
  languages).

Test additions:

- ControlFlow/bindings/* — annotation-driven SSA-binding tests for
  the new CFG (annassign, compound, comprehension, decorated,
  except_handler, imports, match_pattern, parameters, simple,
  type_params, walrus_starred, with_stmt, dead_under_no_raise).

- ControlFlow/store-load/* — basic store/load coverage.

- ControlFlow/evaluation-order/NewCfg*.ql — mirrors of the existing
  OldCfg evaluation-order self-validation suite, run against the
  new CFG via NewCfgImpl.qll.

- Minor extensions to existing test_if.py / test_boolean.py +
  cosmetic .expected churn on a handful of OldCfg tests.

No dataflow, SSA, or production query is migrated yet — that lands in
follow-up PRs. The new CFG library has zero callers in lib/ and src/.

Verified by:
- All lib + src + consistency-queries compile clean (367 queries).
- All 56 ControlFlow library-tests pass.
- All 474 dataflow + PointsTo library-tests + consistency tests pass.
- syntax_error/CONSISTENCY/CfgConsistency passes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-18 15:17:34 +00:00
yoff
f0cdfbd9f4 Shared CFG: add defaulted getWhileElse/getForeachElse/getCatchType to AstSig
Adds three new defaulted signature predicates to the shared CFG library:

- getWhileElse / getForeachElse: `else` block of a while/for loop, if
  any (used by Python's `while-else` / `for-else` constructs).
- getCatchType: type expression of a catch clause, if any (used by
  Python's `except SomeExpr:` where the catch type is a runtime
  expression that needs CFG evaluation).

Each predicate defaults to `none()`, so behaviour is unchanged for any
language that doesn't override it (verified by re-running
java/ql/test/library-tests/controlflow/).

The Make0 succession rules are extended:
- WhileStmt/ForeachStmt: route the loop-exit edge through the else
  block before reaching the after-position.
- CatchClause: route the matching-evaluation through the type
  expression (if present) before reaching the after-value position.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-18 15:17:34 +00:00
Owen Mansel-Chan
91a57f7773 Update tests 2026-06-18 15:17:33 +00:00
Owen Mansel-Chan
e38a5a52b5 Model panicking log functions better 2026-06-18 15:17:33 +00:00
Owen Mansel-Chan
6bc6051ef0 Taint doesn't flow through panicking functions 2026-06-18 15:17:33 +00:00
Owen Mansel-Chan
8402153711 Accept changed test output 2026-06-18 15:17:33 +00:00
Owen Mansel-Chan
22cefa0f46 Improve test for non-returning fns 2026-06-18 15:17:33 +00:00
Owen Mansel-Chan
87f3c92a7f Add missing QLDocs 2026-06-18 15:17:33 +00:00
Owen Mansel-Chan
06bf40cfc6 (Trivial) Fix QLDoc grammar 2026-06-18 15:17:33 +00:00
Owen Mansel-Chan
2d6a80c70f Add change note 2026-06-18 15:17:33 +00:00
Owen Mansel-Chan
db229689eb Improve glog and klog tests 2026-06-18 15:17:33 +00:00
Owen Mansel-Chan
024fb74410 Improve glog (and klog) modelling 2026-06-18 15:17:33 +00:00
Owen Mansel-Chan
f80d9cab9b Improve noretFunctions test 2026-06-18 15:17:33 +00:00
Owen Mansel-Chan
9053c67e95 Recognize more non-returning logging functions 2026-06-18 15:17:32 +00:00
Tom Hvitved
f2bb30ee0f Address review comments 2026-06-18 15:17:32 +00:00
Tom Hvitved
fd7fbd4993 Apply suggestions from code review
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-18 15:17:32 +00:00
Tom Hvitved
5c3b231a01 Ruby: Adopt shared local name resolution library 2026-06-18 15:17:32 +00:00
Tom Hvitved
a08c24a38f Ruby: Add more variable tests 2026-06-18 15:17:32 +00:00
Tom Hvitved
51d752b2ca Rust: Run codegen 2026-06-18 15:17:32 +00:00
Tom Hvitved
15cd643f8a Rust: Adopt shared local name resolution library 2026-06-18 15:17:32 +00:00
Tom Hvitved
9fd266e576 Rust: More local variable tests 2026-06-18 15:17:32 +00:00
Tom Hvitved
996777dfe9 Shared: Add local name binding library 2026-06-18 15:17:32 +00:00
yoff
52d2309186 Apply suggestions from code review
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-18 15:17:31 +00:00
Copilot
b99e4898b8 Python: qualify Flow.qll's AST references with Py:: prefix
Preparatory refactor for the shared-CFG dataflow migration. Switches
'import python' to 'import python as Py' inside Flow.qll, and qualifies
every AST-class reference (Expr, Bytes, Dict, AssignExpr, Compare,
Module, Scope, Call, Attribute, SsaVariable, AugAssign, etc.) with the
Py:: prefix.

Flow.qll's own CFG types (ControlFlowNode, BasicBlock, CallNode,
NameNode, DefinitionNode, CompareNode, ...) keep their unqualified
names — they remain the public CFG API exported from this file.

This is a semantic noop: the qualification was applied mechanically by
script and no name resolution changes. Verified by:
- All 361 lib/ + src/ queries compile clean.
- All 186 ControlFlow + PointsTo + dataflow library-tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-18 15:17:31 +00:00
yoff
3bce589d45 Python: deprecate Function.getAReturnValueFlowNode() and rewrite internal callers
Follow-up to the getAFlowNode deprecation in the same PR: same AST→legacy-CFG
bridge pattern. The 11 internal call sites (across objects/, types/,
frameworks/, and TypeTrackingImpl) are rewritten to bind a `Return ret`
explicitly, then constrain via `ret.getScope() = f and n.getNode() = ret.getValue()`.

The predicate itself is preserved with a deprecation note so external
users do not experience churn.

Semantic noop.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-18 15:17:12 +00:00
Copilot
a13dfaa44f Python: deprecate AstNode.getAFlowNode() and rewrite internal callers
Preparatory refactor for the shared-CFG dataflow migration.

Deprecates the AstNode.getAFlowNode() cached predicate on the public
Python QL API and rewrites all ~140 internal callers across lib/, src/,
test/, and tools/ from `expr.getAFlowNode() = cfgNode` to
`cfgNode.getNode() = expr`, using ControlFlowNode.getNode() which
already exists in Flow.qll.

The predicate itself is preserved (with a deprecation note pointing at
the new pattern) so external users do not experience churn — they can
migrate at their own pace and the AST/CFG hierarchies still get the
intended untangling once the deprecation eventually elapses.

Semantic noop verified by:
- All 361 lib/ + src/ queries compile clean.
- All 122 ControlFlow + PointsTo library-tests pass.
- All 64 dataflow library-tests pass.
- All 113 Variables/Exceptions/Expressions/Statements/Functions/Imports/
  Security/CWE-798/ModificationOfParameterWithDefault query-tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 08:37:30 +00:00
yoff
ac5fa629ef Python: inline init_module_submodule_defn into ImportResolution
The new-dataflow ImportResolution module only used
semmle.python.essa.SsaDefinitions for the 5-line helper predicate
SsaSource::init_module_submodule_defn. Inline it locally and drop the
dependency on legacy SsaDefinitions. This is the only remaining direct
import of semmle.python.essa.* in the new dataflow stack, so dropping
it makes the layering cleaner.

Semantic noop on the current SSA: SsaSourceVariable.getName() and
GlobalVariable.getId() both project the same DB column
(variable(_,_,result)), and the old call's 'init.getEntryNode() = f'
join was just constraining init = package via Scope.getEntryNode()'s
functional uniqueness. RA dump of accesses.ql confirms only the
expected predicate-rename shuffle; all 70 dataflow + ApiGraphs library
tests pass.

This factors out commit 8cab5a20f2 from the larger shared-CFG
migration #21925.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 08:24:17 +00:00
2214 changed files with 21039 additions and 85306 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

@@ -2,7 +2,7 @@
* @github/code-scanning-alert-coverage * @github/code-scanning-alert-coverage
# CodeQL language libraries # CodeQL language libraries
/actions/ @github/code-scanning-alert-coverage /actions/ @github/codeql-dynamic
/cpp/ @github/codeql-c-analysis /cpp/ @github/codeql-c-analysis
/csharp/ @github/codeql-csharp /csharp/ @github/codeql-csharp
/csharp/autobuilder/Semmle.Autobuild.Cpp @github/codeql-c-extractor @github/code-scanning-language-coverage /csharp/autobuilder/Semmle.Autobuild.Cpp @github/codeql-c-extractor @github/code-scanning-language-coverage
@@ -59,5 +59,9 @@ MODULE.bazel @github/codeql-ci-reviewers
/.github/workflows/rust.yml @github/codeql-rust /.github/workflows/rust.yml @github/codeql-rust
/.github/workflows/swift.yml @github/codeql-swift /.github/workflows/swift.yml @github/codeql-swift
# Misc
/misc/scripts/accept-expected-changes-from-ci.py @RasmusWL
/misc/scripts/generate-code-scanning-query-list.py @RasmusWL
# .devcontainer # .devcontainer
/.devcontainer/ @github/codeql-ci-reviewers /.devcontainer/ @github/codeql-ci-reviewers

View File

@@ -273,7 +273,7 @@ use_repo(
) )
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

@@ -2,7 +2,7 @@
### Minor Analysis Improvements ### Minor Analysis Improvements
* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, including regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a SHA-1 or SHA-256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used. * The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, include regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a sha1 or sha256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used.
## 0.4.36 ## 0.4.36

View File

@@ -1,4 +0,0 @@
---
category: fix
---
* The query `actions/pr-on-self-hosted-runner` was updated to the latest standard runner labels reducing false positive results.

View File

@@ -2,4 +2,4 @@
### Minor Analysis Improvements ### Minor Analysis Improvements
* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, including regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a SHA-1 or SHA-256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used. * The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, include regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a sha1 or sha256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used.

View File

@@ -1920,5 +1920,3 @@ private YamlMappingLikeNode resolveMatrixAccessPath(
else result = resolveMatrixAccessPath(newRoot, rest) else result = resolveMatrixAccessPath(newRoot, rest)
) )
} }
class Comment = YamlComment;

View File

@@ -52,12 +52,6 @@ private module YamlSig implements LibYaml::InputSig {
class ParseErrorBase extends LocatableBase, @yaml_error { class ParseErrorBase extends LocatableBase, @yaml_error {
string getMessage() { yaml_errors(this, result) } string getMessage() { yaml_errors(this, result) }
} }
class CommentBase extends LocatableBase, @yaml_comment {
string getText() { yaml_comments(this, result, _) }
override string toString() { yaml_comments(this, _, result) }
}
} }
import LibYaml::Make<YamlSig> import LibYaml::Make<YamlSig>

View File

@@ -2,12 +2,10 @@ import actions
bindingset[runner] bindingset[runner]
predicate isGithubHostedRunner(string runner) { predicate isGithubHostedRunner(string runner) {
// The list of github hosted repos: // list of github hosted repos: https://github.com/actions/runner-images/blob/main/README.md#available-images
// https://github.com/actions/runner-images/blob/main/README.md#available-images runner
// https://docs.github.com/en/enterprise-cloud@latest/actions/how-tos/write-workflows/choose-where-workflows-run/choose-the-runner-for-a-job#standard-github-hosted-runners-for-public-repositories .toLowerCase()
runner.toLowerCase().regexpMatch("^ubuntu-([0-9.]+|latest|slim)(-arm)?$") or .regexpMatch("^(ubuntu-([0-9.]+|latest)|macos-([0-9]+|latest)(-x?large)?|windows-([0-9.]+|latest))$")
runner.toLowerCase().regexpMatch("^macos-([0-9]+|latest)(-x?large|-intel)?$") or
runner.toLowerCase().regexpMatch("^windows-([0-9.]+|latest)(-vs[0-9.]+)?(-arm)?$")
} }
bindingset[runner] bindingset[runner]

View File

@@ -15,7 +15,7 @@
### Bug Fixes ### Bug Fixes
* Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on a minor point, added one more listed resource and added one more recommendation for things to check. * Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on in minor point, added one more listed resource and added one more recommendation for things to check.
## 0.6.28 ## 0.6.28

View File

@@ -1,8 +1,8 @@
/** /**
* @name Checkout of untrusted code in a non-privileged context * @name Checkout of untrusted code in a trusted context
* @description Checking out and running the build script from a fork executes untrusted code. Even in a * @description Privileged workflows have read/write access to the base repository and access to secrets.
* non-privileged workflow, this can be abused, for example to compromise self-hosted runners * By explicitly checking out and running the build script from a fork the untrusted code is running in an environment
* or to poison caches and artifacts that are later consumed by privileged workflows. * that is able to push to the base repository and to access secrets.
* @kind problem * @kind problem
* @problem.severity warning * @problem.severity warning
* @precision medium * @precision medium
@@ -20,4 +20,4 @@ from PRHeadCheckoutStep checkout
where where
// the checkout occurs in a non-privileged context // the checkout occurs in a non-privileged context
inNonPrivilegedContext(checkout) inNonPrivilegedContext(checkout)
select checkout, "Potential unsafe checkout of untrusted pull request on non-privileged workflow." select checkout, "Potential unsafe checkout of untrusted pull request on privileged workflow."

View File

@@ -1,4 +0,0 @@
---
category: queryMetadata
---
* The name, description, and alert message of `actions/untrusted-checkout/medium` have been corrected to describe a non-privileged context.

View File

@@ -15,4 +15,4 @@
### Bug Fixes ### Bug Fixes
* Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on a minor point, added one more listed resource and added one more recommendation for things to check. * Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on in minor point, added one more listed resource and added one more recommendation for things to check.

View File

@@ -1,43 +0,0 @@
name: test
on:
pull_request:
jobs:
test:
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- ubuntu-24.04
- ubuntu-24.04-arm
- ubuntu-22.04
- ubuntu-22.04-arm
- ubuntu-26.04
- ubuntu-26.04-arm
- ubuntu-slim
- macos-26
- macos-26-xlarge
- macos-26-intel
- macos-26-large
- macos-latest-large
- macos-15-large
- macos-15
- macos-15-intel
- macos-latest
- macos-15
- macos-15-xlarge
- macos-14-large
- macos-14
- macos-14-xlarge
- windows-2025-vs2026
- windows-latest
- windows-2025
- windows-2022
- windows-11
- windows-11-arm
- windows-11-vs2026-arm
runs-on: ${{ matrix.os }}
steps:
- run: cmd

View File

@@ -1,10 +1,10 @@
| .github/workflows/artifactpoisoning81.yml:11:9:14:6 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/artifactpoisoning81.yml:11:9:14:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/dependabot2.yml:33:9:38:6 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/dependabot2.yml:33:9:38:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/mend.yml:22:9:29:6 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/mend.yml:22:9:29:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/poc3.yml:18:7:25:4 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/poc3.yml:18:7:25:4 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/poc.yml:30:9:36:6 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/poc.yml:30:9:36:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/priv_pull_request_checkout.yml:14:9:20:6 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/priv_pull_request_checkout.yml:14:9:20:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/test3.yml:28:9:33:6 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/test3.yml:28:9:33:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/test4.yml:18:7:25:4 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/test4.yml:18:7:25:4 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/test8.yml:20:9:26:6 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/test8.yml:20:9:26:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/test9.yml:11:9:16:6 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/test9.yml:11:9:16:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |

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

@@ -1,2 +0,0 @@
description: Fix NameQualifier inconsistency
compatibility: full

View File

@@ -1071,7 +1071,7 @@ class NullPointerType extends BuiltInType {
* const float fa[40]; * const float fa[40];
* ``` * ```
*/ */
class DerivedType extends Type, NameQualifyingElement, @derivedtype { class DerivedType extends Type, @derivedtype {
override string toString() { result = this.getName() } override string toString() { result = this.getName() }
override string getName() { derivedtypes(underlyingElement(this), result, _, _) } override string getName() { derivedtypes(underlyingElement(this), result, _, _) }

View File

@@ -1430,8 +1430,7 @@ specialnamequalifyingelements(
@namequalifyingelement = @namespace @namequalifyingelement = @namespace
| @specialnamequalifyingelement | @specialnamequalifyingelement
| @usertype | @usertype
| @decltype | @decltype;
| @derivedtype;
namequalifiers( namequalifiers(
unique int id: @namequalifier, unique int id: @namequalifier,

View File

@@ -1,2 +0,0 @@
description: Fix NameQualifier inconsistency
compatibility: full

View File

@@ -1,7 +1,3 @@
| inconsistency2.cpp:3:3:3:5 | T:: | inconsistency2.cpp:3:3:3:6 | x | inconsistency2.cpp:2:20:2:20 | T |
| inconsistency2.cpp:3:3:3:11 | const s:: | inconsistency2.cpp:3:3:3:6 | x | file://:0:0:0:0 | const s |
| inconsistency.cpp:7:20:7:22 | S:: | inconsistency.cpp:7:20:7:23 | (int)... | inconsistency.cpp:4:8:4:8 | S |
| inconsistency.cpp:7:20:7:22 | S:: | inconsistency.cpp:7:20:7:23 | A | inconsistency.cpp:4:8:4:8 | S |
| name_qualifiers.cpp:29:7:29:8 | :: | name_qualifiers.cpp:29:7:29:9 | x | file://:0:0:0:0 | (global namespace) | | name_qualifiers.cpp:29:7:29:8 | :: | name_qualifiers.cpp:29:7:29:9 | x | file://:0:0:0:0 | (global namespace) |
| name_qualifiers.cpp:31:7:31:10 | N1:: | name_qualifiers.cpp:31:7:31:12 | nx | name_qualifiers.cpp:4:11:4:12 | N1 | | name_qualifiers.cpp:31:7:31:10 | N1:: | name_qualifiers.cpp:31:7:31:12 | nx | name_qualifiers.cpp:4:11:4:12 | N1 |
| name_qualifiers.cpp:34:7:34:8 | :: | name_qualifiers.cpp:34:9:34:12 | N1:: | file://:0:0:0:0 | (global namespace) | | name_qualifiers.cpp:34:7:34:8 | :: | name_qualifiers.cpp:34:9:34:12 | N1:: | file://:0:0:0:0 | (global namespace) |

View File

@@ -1,5 +1,7 @@
import cpp import cpp
from NameQualifier nq, Location l from NameQualifier nq, Location l
where l = nq.getQualifiedElement().getLocation() where
l = nq.getQualifiedElement().getLocation() and
l.getFile().getShortName() = "name_qualifiers"
select nq, nq.getQualifiedElement(), nq.getQualifyingElement() select nq, nq.getQualifiedElement(), nq.getQualifyingElement()

View File

@@ -1,8 +1,8 @@
// This file is present to test whether name-qualifying an enum constant leads to a database inconsistency. // This file is present to test whether name-qualifying an enum constant leads to a database inconsistency.
// As such, there is no QL part of the test.
struct S { enum E { A }; }; struct S { enum E { A }; };
static void f() { static int f() {
switch(0) { case S::A: break; } switch(0) { case S::A: break; }
} }

View File

@@ -1,12 +0,0 @@
namespace {
template <typename T> T f() {
T::x;
return {};
}
struct s {
static int x;
};
struct t {
s x = f<const s>();
};
}

View File

@@ -1,2 +0,0 @@
description: Restructure and rename types related to operations.
compatibility: full

View File

@@ -1,6 +1,5 @@
using System.IO; using System.IO;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.Kinds; using Semmle.Extraction.Kinds;
@@ -9,7 +8,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
internal abstract class ElementAccess : Expression<ExpressionSyntax> internal abstract class ElementAccess : Expression<ExpressionSyntax>
{ {
protected ElementAccess(ExpressionNodeInfo info, ExpressionSyntax qualifier, BracketedArgumentListSyntax argumentList) protected ElementAccess(ExpressionNodeInfo info, ExpressionSyntax qualifier, BracketedArgumentListSyntax argumentList)
: base(info.SetKind(GetKind(info.Context, info.Node, qualifier))) : base(info.SetKind(GetKind(info.Context, qualifier)))
{ {
this.qualifier = qualifier; this.qualifier = qualifier;
this.argumentList = argumentList; this.argumentList = argumentList;
@@ -18,125 +17,6 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
private readonly ExpressionSyntax qualifier; private readonly ExpressionSyntax qualifier;
private readonly BracketedArgumentListSyntax argumentList; private readonly BracketedArgumentListSyntax argumentList;
private ISymbol? GetTargetSymbol()
{
return Context.GetSymbolInfo(base.Syntax).Symbol;
}
private static void SetExprArgument(TextWriter trapFile, Expression left, Expression right)
{
trapFile.expr_argument(left, 0);
trapFile.expr_argument(right, 0);
}
private Expression MakeZeroFromEndExpression(IExpressionParentEntity parent, int child)
{
var info = new ExpressionInfo(
Context,
AnnotatedTypeSymbol.CreateNotAnnotated(Context.Compilation.GetSpecialType(SpecialType.System_Int32)),
Location,
ExprKind.INDEX,
parent,
child,
isCompilerGenerated: true,
null);
var index = new Expression(info);
MakeZeroLiteral(index, 0);
return index;
}
private Expression MakeZeroLiteral(IExpressionParentEntity parent, int child)
{
return Literal.CreateGenerated(Context, parent, child, Context.Compilation.GetSpecialType(SpecialType.System_Int32), 0, Location);
}
/// <summary>
/// It is assumed that either the input is
/// 1. A normal expression that can be used as endpoint (e.g a constant like "3").
/// 2. An index expression indicating that we should read from the end (e.g "^1").
/// </summary>
/// <param name="syntax">The syntax node representing the range endpoint.</param>
/// <param name="parent">The parent expression entity.</param>
/// <param name="child">The child index within the parent.</param>
/// <returns>An expression representing the endpoint of a range to be used in conjunction with a slice operation.</returns>
private Expression MakeFromRangeEndpoint(ExpressionSyntax syntax, IExpressionParentEntity parent, int child)
{
var info = new ExpressionNodeInfo(Context, syntax, parent, child);
return syntax.Kind() == SyntaxKind.IndexExpression
? PrefixUnary.Create(info.SetKind(ExprKind.INDEX))
: Factory.Create(info);
}
/// <summary>
/// Determines whether the given method is a slice method, which is defined as a method with
/// the name "Slice" or "Substring" and two parameters.
/// </summary>
/// <param name="method">The method symbol to check.</param>
/// <returns>True if the method is a slice method; false otherwise.</returns>
private bool IsSlice(IMethodSymbol method, out RangeExpressionSyntax? range)
{
range = null;
if (argumentList.Arguments.Count == 1)
{
range = argumentList.Arguments[0].Expression as RangeExpressionSyntax;
}
return (method.Name == "Slice" || method.Name == "Substring")
&& method.Parameters.Length == 2;
}
/// <summary>
/// Populates a slice method call based on the given range.
/// Roslyn translates indexer accesses with range expressions in the following way.
/// 1. s[a..b] -> s.Slice(a, b - a)
/// 2. s[..b] -> s.Slice(0, b)
/// 3. s[a..] -> s.Slice(a, s.Length - a)
/// 4. s[..] -> s.Slice(0, s.Length)
/// However, it is possible that both the qualifier or the index endpoints may contain method calls.
/// If we want to translate this accurately, we would need to introduce synthetic statements for qualifier and
/// the endpoints, which should then be used in the slice method call.
/// To avoid this, we translate as follows.
/// 1. s[a..b] -> s.Slice(a, b)
/// 2. s[..b] -> s.Slice(0, b)
/// 3. s[a..] -> s.Slice(a, ^0)
/// 4. s[..] -> s.Slice(0, ^0)
///
/// Even though index expressions can't technically be used in this way, they signal that we
/// could perceive ^b as "length - b".
///
/// Call arguments are only populated when a range expression is directly available in
/// the list of arguments.
/// This means that cases like below are not handled.
/// System.Range x = 1..3;
/// s[x]
/// </summary>
/// <param name="trapFile">The trap file to write to.</param>
/// <param name="slice">The slice method symbol.</param>
/// <param name="range">The range expression syntax.</param>
private void PopulateSlice(TextWriter trapFile, IMethodSymbol slice, RangeExpressionSyntax? range)
{
if (range is not null)
{
// Populate the call arguments
var left = range.LeftOperand is ExpressionSyntax lsyntax
? MakeFromRangeEndpoint(lsyntax, this, 0)
: MakeZeroLiteral(this, 0);
var right = range.RightOperand is ExpressionSyntax rsyntax
? MakeFromRangeEndpoint(rsyntax, this, 1)
: MakeZeroFromEndExpression(this, 1);
SetExprArgument(trapFile, left, right);
}
trapFile.expr_call(this, Method.Create(Context, slice));
}
protected override void PopulateExpression(TextWriter trapFile) protected override void PopulateExpression(TextWriter trapFile)
{ {
if (Kind == ExprKind.POINTER_INDIRECTION) if (Kind == ExprKind.POINTER_INDIRECTION)
@@ -150,19 +30,11 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
else else
{ {
Create(Context, qualifier, this, -1); Create(Context, qualifier, this, -1);
var target = GetTargetSymbol();
if (target is IMethodSymbol method && IsSlice(method, out var range))
{
// When an indexer on a span or string is used in conjunction with a range expression, the compiler translates
// this into a call to the "Slice" or "Substring" method.
// In this case, we want to populate a slice/substring method call instead of an indexer access.
PopulateSlice(trapFile, method, range);
return;
}
PopulateArguments(trapFile, argumentList, 0); PopulateArguments(trapFile, argumentList, 0);
if (target is IPropertySymbol { IsIndexer: true } indexer)
var symbolInfo = Context.GetSymbolInfo(base.Syntax);
if (symbolInfo.Symbol is IPropertySymbol indexer)
{ {
trapFile.expr_access(this, Indexer.Create(Context, indexer)); trapFile.expr_access(this, Indexer.Create(Context, indexer));
} }
@@ -174,11 +46,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
private static bool IsArray(ITypeSymbol symbol) => private static bool IsArray(ITypeSymbol symbol) =>
symbol.TypeKind == Microsoft.CodeAnalysis.TypeKind.Array || symbol.IsInlineArray(); symbol.TypeKind == Microsoft.CodeAnalysis.TypeKind.Array || symbol.IsInlineArray();
private static ExprKind GetKind(Context cx, ExpressionSyntax syntax, ExpressionSyntax qualifier) private static ExprKind GetKind(Context cx, ExpressionSyntax qualifier)
{ {
if (cx.GetSymbolInfo(syntax).Symbol is IMethodSymbol)
return ExprKind.METHOD_INVOCATION;
var qualifierType = cx.GetType(qualifier); var qualifierType = cx.GetType(qualifier);
// This is a compilation error, so make a guess and continue. // This is a compilation error, so make a guess and continue.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Improved extraction of range-access expressions on spans and strings (for example, `a[0..3]`). These expressions are now extracted as `Slice` (span) or `Substring` (string) calls.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Improved property and indexer call target resolution for partially overridden properties and indexers.

View File

@@ -1,4 +0,0 @@
---
category: majorAnalysis
---
* Added Razor Page handler method parameters (e.g., `OnGet`, `OnPost`, `OnPostAsync`) as remote flow sources, enabling security queries such as `cs/sql-injection` to detect vulnerabilities in `PageModel` subclasses.

View File

@@ -1,4 +0,0 @@
---
category: breaking
---
* Renamed types related to *operation* expressions. The QL classes `BinaryArithmeticOperation`, `BinaryBitwiseOperation`, and `BinaryLogicalOperation` now include compound assignments; for example, `BinaryArithmeticOperation` now includes `a += b`.

View File

@@ -50,15 +50,15 @@ private predicate maybeUsedInElfHashFunction(Variable v, Operation xor, Operatio
| |
add instanceof AddOperation and add instanceof AddOperation and
e1.getAChild*() = add.getAnOperand() and e1.getAChild*() = add.getAnOperand() and
e1 instanceof BinaryBitwiseExpr and e1 instanceof BinaryBitwiseOperation and
e2 = e1.(BinaryBitwiseExpr).getLeftOperand() and e2 = e1.(BinaryBitwiseOperation).getLeftOperand() and
v = addAssign.getTargetVariable() and v = addAssign.getTargetVariable() and
addAssign.getAChild*() = add and addAssign.getAChild*() = add and
(xor instanceof BitwiseXorExpr or xor instanceof AssignXorExpr) and (xor instanceof BitwiseXorExpr or xor instanceof AssignXorExpr) and
addAssign.getControlFlowNode().getASuccessor*() = xor.getControlFlowNode() and addAssign.getControlFlowNode().getASuccessor*() = xor.getControlFlowNode() and
xorAssign.getAChild*() = xor and xorAssign.getAChild*() = xor and
v = xorAssign.getTargetVariable() and v = xorAssign.getTargetVariable() and
(notOp instanceof UnaryBitwiseOperation or notOp instanceof AssignBitwiseExpr) and (notOp instanceof UnaryBitwiseOperation or notOp instanceof AssignBitwiseOperation) and
xor.getControlFlowNode().getASuccessor*() = notOp.getControlFlowNode() and xor.getControlFlowNode().getASuccessor*() = notOp.getControlFlowNode() and
notAssign.getAChild*() = notOp and notAssign.getAChild*() = notOp and
v = notAssign.getTargetVariable() and v = notAssign.getTargetVariable() and

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

@@ -290,7 +290,7 @@ module AssignableInternal {
newtype TAssignableDefinition = newtype TAssignableDefinition =
TAssignmentDefinition(Assignment a) { TAssignmentDefinition(Assignment a) {
not a.getLeftOperand() instanceof TupleExpr and not a.getLeftOperand() instanceof TupleExpr and
not a instanceof AssignCallExpr and not a instanceof AssignCallOperation and
not a instanceof AssignCoalesceExpr not a instanceof AssignCoalesceExpr
} or } or
TTupleAssignmentDefinition(AssignExpr ae, Expr leaf) { tupleAssignmentDefinition(ae, leaf) } or TTupleAssignmentDefinition(AssignExpr ae, Expr leaf) { tupleAssignmentDefinition(ae, leaf) } or
@@ -324,7 +324,7 @@ module AssignableInternal {
TAddressOfDefinition(AddressOfExpr aoe) or TAddressOfDefinition(AddressOfExpr aoe) or
TPatternDefinition(TopLevelPatternDecl tlpd) or TPatternDefinition(TopLevelPatternDecl tlpd) or
TAssignOperationDefinition(AssignOperation ao) { TAssignOperationDefinition(AssignOperation ao) {
ao instanceof AssignCallExpr and not ao instanceof CompoundAssignmentOperatorCall ao instanceof AssignCallOperation and not ao instanceof CompoundAssignmentOperatorCall
or or
ao instanceof AssignCoalesceExpr ao instanceof AssignCoalesceExpr
} }

View File

@@ -57,28 +57,6 @@ class DeclarationWithGetSetAccessors extends DeclarationWithAccessors, TopLevelE
/** Gets the `set` accessor of this declaration, if any. */ /** Gets the `set` accessor of this declaration, if any. */
Setter getSetter() { result = this.getAnAccessor() } Setter getSetter() { result = this.getAnAccessor() }
/** Gets the target accessor of this declaration when used in a read context, if any. */
Accessor getReadTarget() {
result = this.getGetter()
or
not exists(this.getGetter()) and
result = this.getOverridee().getReadTarget()
}
/** Gets the target accessor of this declaration when used in a write context, if any. */
Accessor getWriteTarget() {
result = this.getSetter()
or
not exists(this.getSetter()) and
result = this.getOverridee().getWriteTarget()
or
result =
any(Getter g |
g = this.getReadTarget() and
g.getAnnotatedReturnType().isRef()
)
}
override DeclarationWithGetSetAccessors getOverridee() { override DeclarationWithGetSetAccessors getOverridee() {
result = DeclarationWithAccessors.super.getOverridee() result = DeclarationWithAccessors.super.getOverridee()
} }

View File

@@ -912,17 +912,18 @@ module Internal {
) )
or or
// In C#, `null + 1` has type `int?` with value `null` // In C#, `null + 1` has type `int?` with value `null`
result = exists(BinaryOperation bo, Expr o |
any(BinaryArithmeticOperation bao | bo instanceof BinaryArithmeticOperation or
exists(Expr o | bo instanceof AssignArithmeticOperation
bao.getAnOperand() = e and |
bao.getAnOperand() = o and result = bo and
// The other operand must be provably non-null in order bo.getAnOperand() = e and
// for `only if` to hold bo.getAnOperand() = o and
nonNullValueImplied(o) and // The other operand must be provably non-null in order
e != o // for `only if` to hold
) nonNullValueImplied(o) and
) e != o
)
} }
/** /**
@@ -933,10 +934,10 @@ module Internal {
any(QualifiableExpr qe | any(QualifiableExpr qe |
qe.isConditional() and qe.isConditional() and
result = qe.getQualifier() result = qe.getQualifier()
) ) or
or
// In C#, `null + 1` has type `int?` with value `null` // In C#, `null + 1` has type `int?` with value `null`
e = any(BinaryArithmeticOperation bao | result = bao.getAnOperand()) e = any(BinaryArithmeticOperation bao | result = bao.getAnOperand()) or
e = any(AssignArithmeticOperation aao | result = aao.getAnOperand())
} }
deprecated predicate isGuard(Expr e, GuardValue val) { deprecated predicate isGuard(Expr e, GuardValue val) {

View File

@@ -172,10 +172,6 @@ module Ast implements AstSig<Location> {
class DoStmt = CS::DoStmt; class DoStmt = CS::DoStmt;
class UntilStmt extends LoopStmt {
UntilStmt() { none() }
}
final private class FinalForStmt = CS::ForStmt; final private class FinalForStmt = CS::ForStmt;
class ForStmt extends FinalForStmt { class ForStmt extends FinalForStmt {
@@ -207,7 +203,7 @@ module Ast implements AstSig<Location> {
final private class FinalTryStmt = CS::TryStmt; final private class FinalTryStmt = CS::TryStmt;
class TryStmt extends FinalTryStmt { class TryStmt extends FinalTryStmt {
AstNode getBody(int index) { index = 0 and result = this.getBlock() } Stmt getBody() { result = this.getBlock() }
CatchClause getCatch(int index) { result = this.getCatchClause(index) } CatchClause getCatch(int index) { result = this.getCatchClause(index) }

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

@@ -124,7 +124,9 @@ private module Internal {
TDispatchDynamicOperatorCall(DynamicOperatorCall doc) or TDispatchDynamicOperatorCall(DynamicOperatorCall doc) or
TDispatchDynamicMemberAccess(DynamicMemberAccess dma) or TDispatchDynamicMemberAccess(DynamicMemberAccess dma) or
TDispatchDynamicElementAccess(DynamicElementAccess dea) or TDispatchDynamicElementAccess(DynamicElementAccess dea) or
TDispatchDynamicEventAccess(AssignArithmeticExpr aao, DynamicMemberAccess dma, string name) { TDispatchDynamicEventAccess(
AssignArithmeticOperation aao, DynamicMemberAccess dma, string name
) {
isPotentialEventCall(aao, dma, name) isPotentialEventCall(aao, dma, name)
} or } or
TDispatchDynamicObjectCreation(DynamicObjectCreation doc) or TDispatchDynamicObjectCreation(DynamicObjectCreation doc) or
@@ -228,7 +230,7 @@ private module Internal {
* accessor. * accessor.
*/ */
private predicate isPotentialEventCall( private predicate isPotentialEventCall(
AssignArithmeticExpr aao, DynamicMemberAccess dma, string name AssignArithmeticOperation aao, DynamicMemberAccess dma, string name
) { ) {
aao instanceof DynamicOperatorCall and aao instanceof DynamicOperatorCall and
dma = aao.getLeftOperand() and dma = aao.getLeftOperand() and
@@ -1395,7 +1397,9 @@ private module Internal {
private class DispatchDynamicEventAccess extends DispatchReflectionOrDynamicCall, private class DispatchDynamicEventAccess extends DispatchReflectionOrDynamicCall,
TDispatchDynamicEventAccess TDispatchDynamicEventAccess
{ {
override AssignArithmeticExpr getCall() { this = TDispatchDynamicEventAccess(result, _, _) } override AssignArithmeticOperation getCall() {
this = TDispatchDynamicEventAccess(result, _, _)
}
override string getName() { this = TDispatchDynamicEventAccess(_, _, result) } override string getName() { this = TDispatchDynamicEventAccess(_, _, result) }

View File

@@ -11,27 +11,19 @@ import Expr
* (`UnaryArithmeticOperation`) or a binary arithmetic operation * (`UnaryArithmeticOperation`) or a binary arithmetic operation
* (`BinaryArithmeticOperation`). * (`BinaryArithmeticOperation`).
*/ */
class ArithmeticOperation extends Operation, @arith_operation { class ArithmeticOperation extends Operation, @arith_op_expr {
override string getOperator() { none() } override string getOperator() { none() }
} }
/** /**
* A binary arithmetic operation. Either a binary arithmetic expression (`BinaryArithmeticExpr`) or * A unary arithmetic operation. Either a unary minus operation
* an arithmetic assignment expression (`AssignArithmeticExpr`). * (`UnaryMinusExpr`), a unary plus operation (`UnaryPlusExpr`),
*/
class BinaryArithmeticOperation extends ArithmeticOperation, BinaryOperation, @bin_arith_operation {
override string getOperator() { none() }
}
/**
* A unary arithmetic operation. Either a unary minus expression
* (`UnaryMinusExpr`), a unary plus expression (`UnaryPlusExpr`),
* or a mutator operation (`MutatorOperation`). * or a mutator operation (`MutatorOperation`).
*/ */
class UnaryArithmeticOperation extends ArithmeticOperation, UnaryOperation, @un_arith_operation { } class UnaryArithmeticOperation extends ArithmeticOperation, UnaryOperation, @un_arith_op_expr { }
/** /**
* A unary minus expression, for example `-x`. * A unary minus operation, for example `-x`.
*/ */
class UnaryMinusExpr extends UnaryArithmeticOperation, @minus_expr { class UnaryMinusExpr extends UnaryArithmeticOperation, @minus_expr {
override string getOperator() { result = "-" } override string getOperator() { result = "-" }
@@ -40,7 +32,7 @@ class UnaryMinusExpr extends UnaryArithmeticOperation, @minus_expr {
} }
/** /**
* A unary plus expression, for example `+x`. * A unary plus operation, for example `+x`.
*/ */
class UnaryPlusExpr extends UnaryArithmeticOperation, @plus_expr { class UnaryPlusExpr extends UnaryArithmeticOperation, @plus_expr {
override string getOperator() { result = "+" } override string getOperator() { result = "+" }
@@ -52,40 +44,40 @@ class UnaryPlusExpr extends UnaryArithmeticOperation, @plus_expr {
* A mutator operation. Either an increment operation (`IncrementOperation`) * A mutator operation. Either an increment operation (`IncrementOperation`)
* or a decrement operation (`DecrementOperation`). * or a decrement operation (`DecrementOperation`).
*/ */
class MutatorOperation extends UnaryArithmeticOperation, @mut_operation { } class MutatorOperation extends UnaryArithmeticOperation, @mut_op_expr { }
/** /**
* An increment operation. Either a postfix increment expression * An increment operation. Either a postfix increment operation
* (`PostIncrExpr`) or a prefix increment expression (`PreIncrExpr`). * (`PostIncrExpr`) or a prefix increment operation (`PreIncrExpr`).
*/ */
class IncrementOperation extends MutatorOperation, @incr_operation { class IncrementOperation extends MutatorOperation, @incr_op_expr {
override string getOperator() { result = "++" } override string getOperator() { result = "++" }
} }
/** /**
* A decrement operation. Either a postfix decrement expression * A decrement operation. Either a postfix decrement operation
* (`PostDecrExpr`) or a prefix decrement expression (`PreDecrExpr`). * (`PostDecrExpr`) or a prefix decrement operation (`PreDecrExpr`).
*/ */
class DecrementOperation extends MutatorOperation, @decr_operation { class DecrementOperation extends MutatorOperation, @decr_op_expr {
override string getOperator() { result = "--" } override string getOperator() { result = "--" }
} }
/** /**
* A prefix increment expression, for example `++x`. * A prefix increment operation, for example `++x`.
*/ */
class PreIncrExpr extends IncrementOperation, @pre_incr_expr { class PreIncrExpr extends IncrementOperation, @pre_incr_expr {
override string getAPrimaryQlClass() { result = "PreIncrExpr" } override string getAPrimaryQlClass() { result = "PreIncrExpr" }
} }
/** /**
* A prefix decrement expression, for example `--x`. * A prefix decrement operation, for example `--x`.
*/ */
class PreDecrExpr extends DecrementOperation, @pre_decr_expr { class PreDecrExpr extends DecrementOperation, @pre_decr_expr {
override string getAPrimaryQlClass() { result = "PreDecrExpr" } override string getAPrimaryQlClass() { result = "PreDecrExpr" }
} }
/** /**
* A postfix increment expression, for example `x++`. * A postfix increment operation, for example `x++`.
*/ */
class PostIncrExpr extends IncrementOperation, @post_incr_expr { class PostIncrExpr extends IncrementOperation, @post_incr_expr {
override string toString() { result = "..." + this.getOperator() } override string toString() { result = "..." + this.getOperator() }
@@ -94,7 +86,7 @@ class PostIncrExpr extends IncrementOperation, @post_incr_expr {
} }
/** /**
* A postfix decrement expression, for example `x--`. * A postfix decrement operation, for example `x--`.
*/ */
class PostDecrExpr extends DecrementOperation, @post_decr_expr { class PostDecrExpr extends DecrementOperation, @post_decr_expr {
override string toString() { result = "..." + this.getOperator() } override string toString() { result = "..." + this.getOperator() }
@@ -103,84 +95,55 @@ class PostDecrExpr extends DecrementOperation, @post_decr_expr {
} }
/** /**
* An addition operation, either `x + y` or `x += y`. * A binary arithmetic operation. Either an addition operation
* (`AddExpr`), a subtraction operation (`SubExpr`), a multiplication
* operation (`MulExpr`), a division operation (`DivExpr`), or a
* remainder operation (`RemExpr`).
*/ */
class AddOperation extends BinaryArithmeticOperation, @add_operation { } class BinaryArithmeticOperation extends ArithmeticOperation, BinaryOperation, @bin_arith_op_expr {
override string getOperator() { none() }
/**
* A subtraction operation, either `x - y` or `x -= y`.
*/
class SubOperation extends BinaryArithmeticOperation, @sub_operation { }
/**
* A multiplication operation, either `x * y` or `x *= y`.
*/
class MulOperation extends BinaryArithmeticOperation, @mul_operation { }
/**
* A division operation, either `x / y` or `x /= y`.
*/
class DivOperation extends BinaryArithmeticOperation, @div_operation {
/** Gets the numerator of this division operation. */
Expr getNumerator() { result = this.getLeftOperand() }
/** Gets the denominator of this division operation. */
Expr getDenominator() { result = this.getRightOperand() }
} }
/** /**
* A remainder operation, either `x % y` or `x %= y`. * An addition operation, for example `x + y`.
*/ */
class RemOperation extends BinaryArithmeticOperation, @rem_operation { } class AddExpr extends BinaryArithmeticOperation, AddOperation, @add_expr {
/**
* A binary arithmetic expression. Either an addition expression
* (`AddExpr`), a subtraction expression (`SubExpr`), a multiplication
* expression (`MulExpr`), a division expression (`DivExpr`), or a
* remainder expression (`RemExpr`).
*/
class BinaryArithmeticExpr extends BinaryArithmeticOperation, @bin_arith_expr { }
/**
* An addition expression, for example `x + y`.
*/
class AddExpr extends BinaryArithmeticExpr, AddOperation, @add_expr {
override string getOperator() { result = "+" } override string getOperator() { result = "+" }
override string getAPrimaryQlClass() { result = "AddExpr" } override string getAPrimaryQlClass() { result = "AddExpr" }
} }
/** /**
* A subtraction expression, for example `x - y`. * A subtraction operation, for example `x - y`.
*/ */
class SubExpr extends BinaryArithmeticExpr, SubOperation, @sub_expr { class SubExpr extends BinaryArithmeticOperation, SubOperation, @sub_expr {
override string getOperator() { result = "-" } override string getOperator() { result = "-" }
override string getAPrimaryQlClass() { result = "SubExpr" } override string getAPrimaryQlClass() { result = "SubExpr" }
} }
/** /**
* A multiplication expression, for example `x * y`. * A multiplication operation, for example `x * y`.
*/ */
class MulExpr extends BinaryArithmeticExpr, MulOperation, @mul_expr { class MulExpr extends BinaryArithmeticOperation, MulOperation, @mul_expr {
override string getOperator() { result = "*" } override string getOperator() { result = "*" }
override string getAPrimaryQlClass() { result = "MulExpr" } override string getAPrimaryQlClass() { result = "MulExpr" }
} }
/** /**
* A division expression, for example `x / y`. * A division operation, for example `x / y`.
*/ */
class DivExpr extends BinaryArithmeticExpr, DivOperation, @div_expr { class DivExpr extends BinaryArithmeticOperation, DivOperation, @div_expr {
override string getOperator() { result = "/" } override string getOperator() { result = "/" }
override string getAPrimaryQlClass() { result = "DivExpr" } override string getAPrimaryQlClass() { result = "DivExpr" }
} }
/** /**
* A remainder expression, for example `x % y`. * A remainder operation, for example `x % y`.
*/ */
class RemExpr extends BinaryArithmeticExpr, RemOperation, @rem_expr { class RemExpr extends BinaryArithmeticOperation, RemOperation, @rem_expr {
override string getOperator() { result = "%" } override string getOperator() { result = "%" }
override string getAPrimaryQlClass() { result = "RemExpr" } override string getAPrimaryQlClass() { result = "RemExpr" }

View File

@@ -72,9 +72,9 @@ class AssignExpr extends Assignment, @simple_assign_expr {
} }
/** /**
* An assignment operation. Either an arithmetic assignment expression * An assignment operation. Either an arithmetic assignment operation
* (`AssignArithmeticExpr`), a bitwise assignment expression * (`AssignArithmeticOperation`), a bitwise assignment operation
* (`AssignBitwiseExpr`), an event assignment (`AddOrRemoveEventExpr`), or * (`AssignBitwiseOperation`), an event assignment (`AddOrRemoveEventExpr`), or
* a null-coalescing assignment (`AssignCoalesceExpr`). * a null-coalescing assignment (`AssignCoalesceExpr`).
*/ */
class AssignOperation extends Assignment, @assign_op_expr { class AssignOperation extends Assignment, @assign_op_expr {
@@ -94,147 +94,134 @@ class AssignOperation extends Assignment, @assign_op_expr {
} }
/** /**
* A compound assignment expression that invokes an operator. * A compound assignment operation that invokes an operator.
* *
* (1) `x += y` invokes the compound assignment operator `+=` (if it exists). * (1) `x += y` invokes the compound assignment operator `+=` (if it exists).
* (2) `x += y` invokes the operator `+` and assigns `x + y` to `x`. * (2) `x += y` invokes the operator `+` and assigns `x + y` to `x`.
* *
* Either an arithmetic assignment expression (`AssignArithmeticExpr`) or a bitwise * Either an arithmetic assignment operation (`AssignArithmeticOperation`) or a bitwise
* assignment expression (`AssignBitwiseExpr`). * assignment operation (`AssignBitwiseOperation`).
*/ */
class AssignCallExpr extends AssignOperation, OperatorCall, QualifiableExpr, @assign_op_call_expr { class AssignCallOperation extends AssignOperation, OperatorCall, QualifiableExpr,
@assign_op_call_expr
{
override string toString() { result = AssignOperation.super.toString() } override string toString() { result = AssignOperation.super.toString() }
} }
/** /**
* DEPRECATED: Use `AssignCallExpr` instead. * An arithmetic assignment operation. Either an addition assignment operation
*/ * (`AssignAddExpr`), a subtraction assignment operation (`AssignSubExpr`), a
deprecated class AssignCallOperation = AssignCallExpr; * multiplication assignment operation (`AssignMulExpr`), a division assignment
* operation (`AssignDivExpr`), or a remainder assignment operation
/**
* An arithmetic assignment expression. Either an addition assignment expression
* (`AssignAddExpr`), a subtraction assignment expression (`AssignSubExpr`), a
* multiplication assignment expression (`AssignMulExpr`), a division assignment
* expression (`AssignDivExpr`), or a remainder assignment expression
* (`AssignRemExpr`). * (`AssignRemExpr`).
*/ */
class AssignArithmeticExpr extends AssignCallExpr, @assign_arith_expr { } class AssignArithmeticOperation extends AssignCallOperation, @assign_arith_expr { }
/** /**
* DEPRECATED: Use `AssignArithmeticExpr` instead. * An addition assignment operation, for example `x += y`.
*/ */
deprecated class AssignArithmeticOperation = AssignArithmeticExpr; class AssignAddExpr extends AssignArithmeticOperation, AddOperation, @assign_add_expr {
/**
* An addition assignment expression, for example `x += y`.
*/
class AssignAddExpr extends AssignArithmeticExpr, AddOperation, @assign_add_expr {
override string getOperator() { result = "+=" } override string getOperator() { result = "+=" }
override string getAPrimaryQlClass() { result = "AssignAddExpr" } override string getAPrimaryQlClass() { result = "AssignAddExpr" }
} }
/** /**
* A subtraction assignment expression, for example `x -= y`. * A subtraction assignment operation, for example `x -= y`.
*/ */
class AssignSubExpr extends AssignArithmeticExpr, SubOperation, @assign_sub_expr { class AssignSubExpr extends AssignArithmeticOperation, SubOperation, @assign_sub_expr {
override string getOperator() { result = "-=" } override string getOperator() { result = "-=" }
override string getAPrimaryQlClass() { result = "AssignSubExpr" } override string getAPrimaryQlClass() { result = "AssignSubExpr" }
} }
/** /**
* A multiplication assignment expression, for example `x *= y`. * An multiplication assignment operation, for example `x *= y`.
*/ */
class AssignMulExpr extends AssignArithmeticExpr, MulOperation, @assign_mul_expr { class AssignMulExpr extends AssignArithmeticOperation, MulOperation, @assign_mul_expr {
override string getOperator() { result = "*=" } override string getOperator() { result = "*=" }
override string getAPrimaryQlClass() { result = "AssignMulExpr" } override string getAPrimaryQlClass() { result = "AssignMulExpr" }
} }
/** /**
* A division assignment expression, for example `x /= y`. * An division assignment operation, for example `x /= y`.
*/ */
class AssignDivExpr extends AssignArithmeticExpr, DivOperation, @assign_div_expr { class AssignDivExpr extends AssignArithmeticOperation, DivOperation, @assign_div_expr {
override string getOperator() { result = "/=" } override string getOperator() { result = "/=" }
override string getAPrimaryQlClass() { result = "AssignDivExpr" } override string getAPrimaryQlClass() { result = "AssignDivExpr" }
} }
/** /**
* A remainder assignment expression, for example `x %= y`. * A remainder assignment operation, for example `x %= y`.
*/ */
class AssignRemExpr extends AssignArithmeticExpr, RemOperation, @assign_rem_expr { class AssignRemExpr extends AssignArithmeticOperation, RemOperation, @assign_rem_expr {
override string getOperator() { result = "%=" } override string getOperator() { result = "%=" }
override string getAPrimaryQlClass() { result = "AssignRemExpr" } override string getAPrimaryQlClass() { result = "AssignRemExpr" }
} }
/** /**
* A bitwise assignment expression. Either a bitwise-and assignment * A bitwise assignment operation. Either a bitwise-and assignment
* expression (`AssignAndExpr`), a bitwise-or assignment * operation (`AssignAndExpr`), a bitwise-or assignment
* expression (`AssignOrExpr`), a bitwise exclusive-or assignment * operation (`AssignOrExpr`), a bitwise exclusive-or assignment
* expression (`AssignXorExpr`), a left-shift assignment * operation (`AssignXorExpr`), a left-shift assignment
* expression (`AssignLeftShiftExpr`), or a right-shift assignment * operation (`AssignLeftShiftExpr`), or a right-shift assignment
* expression (`AssignRightShiftExpr`), or an unsigned right-shift assignment * operation (`AssignRightShiftExpr`), or an unsigned right-shift assignment
* expression (`AssignUnsignedRightShiftExpr`). * operation (`AssignUnsignedRightShiftExpr`).
*/ */
class AssignBitwiseExpr extends AssignCallExpr, @assign_bitwise_expr { } class AssignBitwiseOperation extends AssignCallOperation, @assign_bitwise_expr { }
/** /**
* DEPRECATED: Use `AssignBitwiseExpr` instead. * A bitwise-and assignment operation, for example `x &= y`.
*/ */
deprecated class AssignBitwiseOperation = AssignBitwiseExpr; class AssignAndExpr extends AssignBitwiseOperation, BitwiseAndOperation, @assign_and_expr {
/**
* A bitwise-and assignment expression, for example `x &= y`.
*/
class AssignAndExpr extends AssignBitwiseExpr, BitwiseAndOperation, @assign_and_expr {
override string getOperator() { result = "&=" } override string getOperator() { result = "&=" }
override string getAPrimaryQlClass() { result = "AssignAndExpr" } override string getAPrimaryQlClass() { result = "AssignAndExpr" }
} }
/** /**
* A bitwise-or assignment expression, for example `x |= y`. * A bitwise-or assignment operation, for example `x |= y`.
*/ */
class AssignOrExpr extends AssignBitwiseExpr, BitwiseOrOperation, @assign_or_expr { class AssignOrExpr extends AssignBitwiseOperation, BitwiseOrOperation, @assign_or_expr {
override string getOperator() { result = "|=" } override string getOperator() { result = "|=" }
override string getAPrimaryQlClass() { result = "AssignOrExpr" } override string getAPrimaryQlClass() { result = "AssignOrExpr" }
} }
/** /**
* A bitwise exclusive-or assignment expression, for example `x ^= y`. * A bitwise exclusive-or assignment operation, for example `x ^= y`.
*/ */
class AssignXorExpr extends AssignBitwiseExpr, BitwiseXorOperation, @assign_xor_expr { class AssignXorExpr extends AssignBitwiseOperation, BitwiseXorOperation, @assign_xor_expr {
override string getOperator() { result = "^=" } override string getOperator() { result = "^=" }
override string getAPrimaryQlClass() { result = "AssignXorExpr" } override string getAPrimaryQlClass() { result = "AssignXorExpr" }
} }
/** /**
* A left-shift assignment expression, for example `x <<= y`. * A left-shift assignment operation, for example `x <<= y`.
*/ */
class AssignLeftShiftExpr extends AssignBitwiseExpr, LeftShiftOperation, @assign_lshift_expr { class AssignLeftShiftExpr extends AssignBitwiseOperation, LeftShiftOperation, @assign_lshift_expr {
override string getOperator() { result = "<<=" } override string getOperator() { result = "<<=" }
override string getAPrimaryQlClass() { result = "AssignLeftShiftExpr" } override string getAPrimaryQlClass() { result = "AssignLeftShiftExpr" }
} }
/** /**
* A right-shift assignment expression, for example `x >>= y`. * A right-shift assignment operation, for example `x >>= y`.
*/ */
class AssignRightShiftExpr extends AssignBitwiseExpr, RightShiftOperation, @assign_rshift_expr { class AssignRightShiftExpr extends AssignBitwiseOperation, RightShiftOperation, @assign_rshift_expr {
override string getOperator() { result = ">>=" } override string getOperator() { result = ">>=" }
override string getAPrimaryQlClass() { result = "AssignRightShiftExpr" } override string getAPrimaryQlClass() { result = "AssignRightShiftExpr" }
} }
/** /**
* An unsigned right-shift assignment expression, for example `x >>>= y`. * An unsigned right-shift assignment operation, for example `x >>>= y`.
*/ */
class AssignUnsignedRightShiftExpr extends AssignBitwiseExpr, UnsignedRightShiftOperation, class AssignUnsignedRightShiftExpr extends AssignBitwiseOperation, UnsignedRightShiftOperation,
@assign_urshift_expr @assign_urshift_expr
{ {
override string getOperator() { result = ">>>=" } override string getOperator() { result = ">>>=" }
@@ -310,10 +297,10 @@ class RemoveEventExpr extends AddOrRemoveEventExpr, @remove_event_expr {
} }
/** /**
* A null-coalescing assignment expression, for example `x ??= y`. * A null-coalescing assignment operation, for example `x ??= y`.
*/ */
class AssignCoalesceExpr extends AssignOperation, NullCoalescingOperation, @assign_coalesce_expr { class AssignCoalesceExpr extends AssignOperation, NullCoalescingOperation, @assign_coalesce_expr {
override string getOperator() { result = "??=" } override string toString() { result = "... ??= ..." }
override string getAPrimaryQlClass() { result = "AssignCoalesceExpr" } override string getAPrimaryQlClass() { result = "AssignCoalesceExpr" }
} }

View File

@@ -10,16 +10,16 @@ import Expr
* A bitwise operation. Either a unary bitwise operation (`UnaryBitwiseOperation`) * A bitwise operation. Either a unary bitwise operation (`UnaryBitwiseOperation`)
* or a binary bitwise operation (`BinaryBitwiseOperation`). * or a binary bitwise operation (`BinaryBitwiseOperation`).
*/ */
class BitwiseOperation extends Operation, @bit_operation { } class BitwiseOperation extends Operation, @bit_expr { }
/** /**
* A unary bitwise operation, that is, a bitwise complement operation * A unary bitwise operation, that is, a bitwise complement operation
* (`ComplementExpr`). * (`ComplementExpr`).
*/ */
class UnaryBitwiseOperation extends BitwiseOperation, UnaryOperation, @un_bit_operation { } class UnaryBitwiseOperation extends BitwiseOperation, UnaryOperation, @un_bit_op_expr { }
/** /**
* A bitwise complement expression, for example `~x`. * A bitwise complement operation, for example `~x`.
*/ */
class ComplementExpr extends UnaryBitwiseOperation, @bit_not_expr { class ComplementExpr extends UnaryBitwiseOperation, @bit_not_expr {
override string getOperator() { result = "~" } override string getOperator() { result = "~" }
@@ -28,101 +28,67 @@ class ComplementExpr extends UnaryBitwiseOperation, @bit_not_expr {
} }
/** /**
* A binary bitwise operation. Either a binary bitwise expression (`BinaryBitwiseExpr`) or * A binary bitwise operation. Either a bitwise-and operation
* a bitwise assignment expression (`AssignBitwiseExpr`). * (`BitwiseAndExpr`), a bitwise-or operation (`BitwiseOrExpr`),
* a bitwise exclusive-or operation (`BitwiseXorExpr`), a left-shift
* operation (`LeftShiftExpr`), a right-shift operation (`RightShiftExpr`),
* or an unsigned right-shift operation (`UnsignedRightShiftExpr`).
*/ */
class BinaryBitwiseOperation extends BitwiseOperation, BinaryOperation, @bin_bit_operation { class BinaryBitwiseOperation extends BitwiseOperation, BinaryOperation, @bin_bit_op_expr {
override string getOperator() { none() } override string getOperator() { none() }
} }
/** /**
* A bitwise-and operation, either `x & y` or `x &= y`. * A left-shift operation, for example `x << y`.
*/ */
class BitwiseAndOperation extends BinaryBitwiseOperation, @and_operation { } class LeftShiftExpr extends BinaryBitwiseOperation, LeftShiftOperation, @lshift_expr {
/**
* A bitwise-or operation, either `x | y` or `x |= y`.
*/
class BitwiseOrOperation extends BinaryBitwiseOperation, @or_operation { }
/**
* A bitwise exclusive-or operation, either `x ^ y` or `x ^= y`.
*/
class BitwiseXorOperation extends BinaryBitwiseOperation, @xor_operation { }
/**
* A left-shift operation, either `x << y` or `x <<= y`.
*/
class LeftShiftOperation extends BinaryBitwiseOperation, @lshift_operation { }
/**
* A right-shift operation, either `x >> y` or `x >>= y`.
*/
class RightShiftOperation extends BinaryBitwiseOperation, @rshift_operation { }
/**
* An unsigned right-shift operation, either `x >>> y` or `x >>>= y`.
*/
class UnsignedRightShiftOperation extends BinaryBitwiseOperation, @urshift_operation { }
/**
* A binary bitwise expression. Either a bitwise-and expression
* (`BitwiseAndExpr`), a bitwise-or expression (`BitwiseOrExpr`),
* a bitwise exclusive-or expression (`BitwiseXorExpr`), a left-shift
* expression (`LeftShiftExpr`), a right-shift expression (`RightShiftExpr`),
* or an unsigned right-shift expression (`UnsignedRightShiftExpr`).
*/
class BinaryBitwiseExpr extends BinaryBitwiseOperation, @bin_bit_expr { }
/**
* A left-shift expression, for example `x << y`.
*/
class LeftShiftExpr extends BinaryBitwiseExpr, LeftShiftOperation, @lshift_expr {
override string getOperator() { result = "<<" } override string getOperator() { result = "<<" }
override string getAPrimaryQlClass() { result = "LeftShiftExpr" } override string getAPrimaryQlClass() { result = "LeftShiftExpr" }
} }
/** /**
* A right-shift expression, for example `x >> y`. * A right-shift operation, for example `x >> y`.
*/ */
class RightShiftExpr extends BinaryBitwiseExpr, RightShiftOperation, @rshift_expr { class RightShiftExpr extends BinaryBitwiseOperation, RightShiftOperation, @rshift_expr {
override string getOperator() { result = ">>" } override string getOperator() { result = ">>" }
override string getAPrimaryQlClass() { result = "RightShiftExpr" } override string getAPrimaryQlClass() { result = "RightShiftExpr" }
} }
/** /**
* An unsigned right-shift expression, for example `x >>> y`. * An unsigned right-shift operation, for example `x >>> y`.
*/ */
class UnsignedRightShiftExpr extends BinaryBitwiseExpr, UnsignedRightShiftOperation, @urshift_expr { class UnsignedRightShiftExpr extends BinaryBitwiseOperation, UnsignedRightShiftOperation,
@urshift_expr
{
override string getOperator() { result = ">>>" } override string getOperator() { result = ">>>" }
override string getAPrimaryQlClass() { result = "UnsignedRightShiftExpr" } override string getAPrimaryQlClass() { result = "UnsignedRightShiftExpr" }
} }
/** /**
* A bitwise-and expression, for example `x & y`. * A bitwise-and operation, for example `x & y`.
*/ */
class BitwiseAndExpr extends BinaryBitwiseExpr, BitwiseAndOperation, @bit_and_expr { class BitwiseAndExpr extends BinaryBitwiseOperation, BitwiseAndOperation, @bit_and_expr {
override string getOperator() { result = "&" } override string getOperator() { result = "&" }
override string getAPrimaryQlClass() { result = "BitwiseAndExpr" } override string getAPrimaryQlClass() { result = "BitwiseAndExpr" }
} }
/** /**
* A bitwise-or expression, for example `x | y`. * A bitwise-or operation, for example `x | y`.
*/ */
class BitwiseOrExpr extends BinaryBitwiseExpr, BitwiseOrOperation, @bit_or_expr { class BitwiseOrExpr extends BinaryBitwiseOperation, BitwiseOrOperation, @bit_or_expr {
override string getOperator() { result = "|" } override string getOperator() { result = "|" }
override string getAPrimaryQlClass() { result = "BitwiseOrExpr" } override string getAPrimaryQlClass() { result = "BitwiseOrExpr" }
} }
/** /**
* A bitwise exclusive-or expression, for example `x ^ y`. * A bitwise exclusive-or operation, for example `x ^ y`.
*/ */
class BitwiseXorExpr extends BinaryBitwiseExpr, BitwiseXorOperation, @bit_xor_expr { class BitwiseXorExpr extends BinaryBitwiseOperation, BitwiseXorOperation, @bit_xor_expr {
override string getOperator() { result = "^" } override string getOperator() { result = "^" }
override string getAPrimaryQlClass() { result = "BitwiseXorExpr" } override string getAPrimaryQlClass() { result = "BitwiseXorExpr" }

View File

@@ -609,7 +609,7 @@ class InstanceMutatorOperatorCall extends MutatorOperatorCall {
* } * }
* ``` * ```
*/ */
class CompoundAssignmentOperatorCall extends AssignCallExpr { class CompoundAssignmentOperatorCall extends AssignCallOperation {
CompoundAssignmentOperatorCall() { this.getTarget() instanceof CompoundAssignmentOperator } CompoundAssignmentOperatorCall() { this.getTarget() instanceof CompoundAssignmentOperator }
override Expr getArgument(int i) { result = this.getChildExpr(i + 1) and i >= 0 } override Expr getArgument(int i) { result = this.getChildExpr(i + 1) and i >= 0 }
@@ -762,12 +762,20 @@ class AccessorCall extends Call, QualifiableExpr, @call_access_expr {
*/ */
class PropertyCall extends AccessorCall, PropertyAccessExpr { class PropertyCall extends AccessorCall, PropertyAccessExpr {
override Accessor getReadTarget() { override Accessor getReadTarget() {
this instanceof AssignableRead and result = this.getProperty().getReadTarget() this instanceof AssignableRead and result = this.getProperty().getGetter()
} }
override Accessor getWriteTarget() { override Accessor getWriteTarget() {
this instanceof AssignableWrite and this instanceof AssignableWrite and
result = this.getProperty().getWriteTarget() exists(Property p | p = this.getProperty() |
result = p.getSetter()
or
result =
any(Getter g |
g = p.getGetter() and
g.getAnnotatedReturnType().isRef()
)
)
} }
override Expr getArgument(int i) { override Expr getArgument(int i) {
@@ -798,12 +806,20 @@ class PropertyCall extends AccessorCall, PropertyAccessExpr {
*/ */
class IndexerCall extends AccessorCall, IndexerAccessExpr { class IndexerCall extends AccessorCall, IndexerAccessExpr {
override Accessor getReadTarget() { override Accessor getReadTarget() {
this instanceof AssignableRead and result = this.getIndexer().getReadTarget() this instanceof AssignableRead and result = this.getIndexer().getGetter()
} }
override Accessor getWriteTarget() { override Accessor getWriteTarget() {
this instanceof AssignableWrite and this instanceof AssignableWrite and
result = this.getIndexer().getWriteTarget() exists(Indexer i | i = this.getIndexer() |
result = i.getSetter()
or
result =
any(Getter g |
g = i.getGetter() and
g.getAnnotatedReturnType().isRef()
)
)
} }
override Expr getArgument(int i) { override Expr getArgument(int i) {

View File

@@ -14,6 +14,7 @@ import Creation
import Dynamic import Dynamic
import Literal import Literal
import LogicalOperation import LogicalOperation
import Operation
import semmle.code.csharp.controlflow.ControlFlowElement import semmle.code.csharp.controlflow.ControlFlowElement
import semmle.code.csharp.Location import semmle.code.csharp.Location
import semmle.code.csharp.Stmt import semmle.code.csharp.Stmt
@@ -211,7 +212,7 @@ class LocalConstantDeclExpr extends LocalVariableDeclExpr {
* (`UnaryOperation`), a binary operation (`BinaryOperation`), or a * (`UnaryOperation`), a binary operation (`BinaryOperation`), or a
* ternary operation (`TernaryOperation`). * ternary operation (`TernaryOperation`).
*/ */
class Operation extends Expr, @operation_expr { class Operation extends Expr, @op_expr {
/** Gets the name of the operator in this operation. */ /** Gets the name of the operator in this operation. */
string getOperator() { none() } string getOperator() { none() }
@@ -226,7 +227,7 @@ class Operation extends Expr, @operation_expr {
* indirection operation (`PointerIndirectionExpr`), an address-of operation * indirection operation (`PointerIndirectionExpr`), an address-of operation
* (`AddressOfExpr`), or a unary logical operation (`UnaryLogicalOperation`). * (`AddressOfExpr`), or a unary logical operation (`UnaryLogicalOperation`).
*/ */
class UnaryOperation extends Operation, @un_operation { class UnaryOperation extends Operation, @un_op {
/** Gets the operand of this unary operation. */ /** Gets the operand of this unary operation. */
Expr getOperand() { result = this.getChild(0) } Expr getOperand() { result = this.getChild(0) }
@@ -240,7 +241,7 @@ class UnaryOperation extends Operation, @un_operation {
* a binary logical operation (`BinaryLogicalOperation`), or an * a binary logical operation (`BinaryLogicalOperation`), or an
* assignment (`Assignment`). * assignment (`Assignment`).
*/ */
class BinaryOperation extends Operation, @bin_operation { class BinaryOperation extends Operation, @bin_op {
/** Gets the left operand of this binary operation. */ /** Gets the left operand of this binary operation. */
Expr getLeftOperand() { result = this.getChild(0) } Expr getLeftOperand() { result = this.getChild(0) }
@@ -263,7 +264,7 @@ class BinaryOperation extends Operation, @bin_operation {
* A ternary operation, that is, a ternary conditional operation * A ternary operation, that is, a ternary conditional operation
* (`ConditionalExpr`). * (`ConditionalExpr`).
*/ */
class TernaryOperation extends Operation, @ternary_operation { } class TernaryOperation extends Operation, @ternary_op { }
/** /**
* A parenthesized expression, for example `(2 + 3)` in * A parenthesized expression, for example `(2 + 3)` in

View File

@@ -11,14 +11,14 @@ import Expr
* a binary logical operation (`BinaryLogicalOperation`), or a ternary logical * a binary logical operation (`BinaryLogicalOperation`), or a ternary logical
* operation (`TernaryLogicalOperation`). * operation (`TernaryLogicalOperation`).
*/ */
class LogicalOperation extends Operation, @log_operation { class LogicalOperation extends Operation, @log_expr {
override string getOperator() { none() } override string getOperator() { none() }
} }
/** /**
* A unary logical operation, that is, a logical 'not' (`LogicalNotExpr`). * A unary logical operation, that is, a logical 'not' (`LogicalNotExpr`).
*/ */
class UnaryLogicalOperation extends LogicalOperation, UnaryOperation, @un_log_operation { } class UnaryLogicalOperation extends LogicalOperation, UnaryOperation, @un_log_op_expr { }
/** /**
* A logical 'not', for example `!String.IsNullOrEmpty(s)`. * A logical 'not', for example `!String.IsNullOrEmpty(s)`.
@@ -31,10 +31,10 @@ class LogicalNotExpr extends UnaryLogicalOperation, @log_not_expr {
/** /**
* A binary logical operation. Either a logical 'and' (`LogicalAndExpr`), * A binary logical operation. Either a logical 'and' (`LogicalAndExpr`),
* a logical 'or' (`LogicalOrExpr`), or a null-coalescing operation * a logical 'or' (`LogicalAndExpr`), or a null-coalescing operation
* (`NullCoalescingOperation`). * (`NullCoalescingExpr`).
*/ */
class BinaryLogicalOperation extends LogicalOperation, BinaryOperation, @bin_log_operation { class BinaryLogicalOperation extends LogicalOperation, BinaryOperation, @bin_log_op_expr {
override string getOperator() { none() } override string getOperator() { none() }
} }
@@ -57,12 +57,7 @@ class LogicalOrExpr extends BinaryLogicalOperation, @log_or_expr {
} }
/** /**
* A null-coalescing operation, either `x ?? y` or `x ??= y`. * A null-coalescing operation, for example `s ?? ""` on line 2 in
*/
class NullCoalescingOperation extends BinaryLogicalOperation, @null_coalescing_operation { }
/**
* A null-coalescing expression, for example `s ?? ""` on line 2 in
* *
* ```csharp * ```csharp
* string NonNullOrEmpty(string s) { * string NonNullOrEmpty(string s) {
@@ -70,7 +65,9 @@ class NullCoalescingOperation extends BinaryLogicalOperation, @null_coalescing_o
* } * }
* ``` * ```
*/ */
class NullCoalescingExpr extends NullCoalescingOperation, @null_coalescing_expr { class NullCoalescingExpr extends BinaryLogicalOperation, NullCoalescingOperation,
@null_coalescing_expr
{
override string getOperator() { result = "??" } override string getOperator() { result = "??" }
override string getAPrimaryQlClass() { result = "NullCoalescingExpr" } override string getAPrimaryQlClass() { result = "NullCoalescingExpr" }
@@ -80,7 +77,7 @@ class NullCoalescingExpr extends NullCoalescingOperation, @null_coalescing_expr
* A ternary logical operation, that is, a ternary conditional expression * A ternary logical operation, that is, a ternary conditional expression
* (`ConditionalExpr`). * (`ConditionalExpr`).
*/ */
class TernaryLogicalOperation extends LogicalOperation, TernaryOperation, @ternary_log_operation { } class TernaryLogicalOperation extends LogicalOperation, TernaryOperation, @ternary_log_op_expr { }
/** /**
* A conditional expression, for example `s != null ? s.Length : -1` * A conditional expression, for example `s != null ? s.Length : -1`

View File

@@ -1,6 +1,71 @@
/** /**
* Provides classes for operations that also have compound assignment forms. * Provides classes for operations that also have compound assignment forms.
*/ */
deprecated module;
import Expr import Expr
/**
* An addition operation, either `x + y` or `x += y`.
*/
class AddOperation extends BinaryOperation, @add_operation { }
/**
* A subtraction operation, either `x - y` or `x -= y`.
*/
class SubOperation extends BinaryOperation, @sub_operation { }
/**
* A multiplication operation, either `x * y` or `x *= y`.
*/
class MulOperation extends BinaryOperation, @mul_operation { }
/**
* A division operation, either `x / y` or `x /= y`.
*/
class DivOperation extends BinaryOperation, @div_operation {
/** Gets the numerator of this division operation. */
Expr getNumerator() { result = this.getLeftOperand() }
/** Gets the denominator of this division operation. */
Expr getDenominator() { result = this.getRightOperand() }
}
/**
* A remainder operation, either `x % y` or `x %= y`.
*/
class RemOperation extends BinaryOperation, @rem_operation { }
/**
* A bitwise-and operation, either `x & y` or `x &= y`.
*/
class BitwiseAndOperation extends BinaryOperation, @and_operation { }
/**
* A bitwise-or operation, either `x | y` or `x |= y`.
*/
class BitwiseOrOperation extends BinaryOperation, @or_operation { }
/**
* A bitwise exclusive-or operation, either `x ^ y` or `x ^= y`.
*/
class BitwiseXorOperation extends BinaryOperation, @xor_operation { }
/**
* A left-shift operation, either `x << y` or `x <<= y`.
*/
class LeftShiftOperation extends BinaryOperation, @lshift_operation { }
/**
* A right-shift operation, either `x >> y` or `x >>= y`.
*/
class RightShiftOperation extends BinaryOperation, @rshift_operation { }
/**
* An unsigned right-shift operation, either `x >>> y` or `x >>>= y`.
*/
class UnsignedRightShiftOperation extends BinaryOperation, @urshift_operation { }
/**
* A null-coalescing operation, either `x ?? y` or `x ??= y`.
*/
class NullCoalescingOperation extends BinaryOperation, @null_coalescing_operation { }

View File

@@ -13,7 +13,6 @@ private import semmle.code.csharp.frameworks.system.web.ui.WebControls
private import semmle.code.csharp.frameworks.WCF private import semmle.code.csharp.frameworks.WCF
private import semmle.code.csharp.frameworks.microsoft.Owin private import semmle.code.csharp.frameworks.microsoft.Owin
private import semmle.code.csharp.frameworks.microsoft.AspNetCore private import semmle.code.csharp.frameworks.microsoft.AspNetCore
private import semmle.code.csharp.frameworks.Razor
private import semmle.code.csharp.dataflow.internal.ExternalFlow private import semmle.code.csharp.dataflow.internal.ExternalFlow
private import semmle.code.csharp.security.dataflow.flowsources.FlowSources private import semmle.code.csharp.security.dataflow.flowsources.FlowSources
@@ -315,22 +314,6 @@ class AspNetCoreActionMethodParameter extends AspNetCoreRemoteFlowSource, DataFl
override string getSourceType() { result = "ASP.NET Core MVC action method parameter" } override string getSourceType() { result = "ASP.NET Core MVC action method parameter" }
} }
/** A parameter to a Razor Page handler method, viewed as a source of remote user input. */
class AspNetCorePageHandlerMethodParameter extends AspNetCoreRemoteFlowSource,
DataFlow::ParameterNode
{
AspNetCorePageHandlerMethodParameter() {
exists(Parameter p |
p = this.getParameter() and
p.fromSource()
|
p = any(PageModelClass pm).getAHandlerMethod().getAParameter()
)
}
override string getSourceType() { result = "ASP.NET Core Razor Page handler method parameter" }
}
private class ExternalRemoteFlowSource extends RemoteFlowSource { private class ExternalRemoteFlowSource extends RemoteFlowSource {
ExternalRemoteFlowSource() { sourceNode(this, "remote") } ExternalRemoteFlowSource() { sourceNode(this, "remote") }

View File

@@ -1254,39 +1254,33 @@ case @expr.kind of
@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; @delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
@bin_arith_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; @bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
@bin_arith_operation = @mul_operation | @div_operation | @rem_operation | @add_operation | @sub_operation; @incr_op_expr = @pre_incr_expr | @post_incr_expr;
@decr_op_expr = @pre_decr_expr | @post_decr_expr;
@mut_op_expr = @incr_op_expr | @decr_op_expr;
@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
@incr_operation = @pre_incr_expr | @post_incr_expr; @ternary_log_op_expr = @conditional_expr;
@decr_operation = @pre_decr_expr | @post_decr_expr; @bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
@mut_operation = @incr_operation | @decr_operation; @un_log_op_expr = @log_not_expr;
@un_arith_operation = @plus_expr | @minus_expr | @mut_operation; @log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
@arith_operation = @bin_arith_operation | @un_arith_operation;
@ternary_log_operation = @conditional_expr; @bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
@bin_log_operation = @log_and_expr | @log_or_expr | @null_coalescing_operation; | @rshift_expr | @urshift_expr;
@un_log_operation = @log_not_expr; @un_bit_op_expr = @bit_not_expr;
@log_operation = @un_log_operation | @bin_log_operation | @ternary_log_operation; @bit_expr = @un_bit_op_expr | @bin_bit_op_expr;
@bin_bit_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
| @rshift_expr | @urshift_expr;
@bin_bit_operation = @and_operation | @or_operation | @xor_operation | @lshift_operation
| @rshift_operation | @urshift_operation;
@un_bit_expr = @bit_not_expr;
@un_bit_operation = @un_bit_expr;
@bit_expr = @un_bit_expr | @bin_bit_expr;
@bit_operation = @un_bit_operation | @bin_bit_operation;
@equality_op_expr = @eq_expr | @ne_expr; @equality_op_expr = @eq_expr | @ne_expr;
@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; @rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr;
@comp_expr = @equality_op_expr | @rel_op_expr; @comp_expr = @equality_op_expr | @rel_op_expr;
@operation_expr = @un_operation | @bin_operation | @ternary_operation; @op_expr = @un_op | @bin_op | @ternary_op;
@ternary_operation = @ternary_log_operation; @ternary_op = @ternary_log_op_expr;
@bin_operation = @assign_expr | @bin_arith_operation | @bin_log_operation | @bin_bit_operation | @comp_expr; @bin_op = @assign_expr | @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
@un_operation = @un_arith_operation | @un_log_operation | @un_bit_operation | @sizeof_expr @un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
| @pointer_indirection_expr | @address_of_expr; | @pointer_indirection_expr | @address_of_expr;
@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; @anonymous_function_expr = @lambda_expr | @anonymous_method_expr;

View File

@@ -1,2 +0,0 @@
description: Restructure and rename types related to operations.
compatibility: full

View File

@@ -63,7 +63,7 @@ module CallTargetStats implements StatsSig {
additional predicate isNotOkCall(Call c) { additional predicate isNotOkCall(Call c) {
not exists(c.getTarget()) and not exists(c.getTarget()) and
not c instanceof DelegateLikeCall and not c instanceof DelegateCall and
not c instanceof DynamicExpr and not c instanceof DynamicExpr and
not isNoSetterPropertyCallInConstructor(c) and not isNoSetterPropertyCallInConstructor(c) and
not isNoSetterPropertyInitialization(c) and not isNoSetterPropertyInitialization(c) and

View File

@@ -1,7 +1,6 @@
binarybitwise binarybitwise
| Operators.cs:7:18:7:25 | ... >>> ... | Operators.cs:7:18:7:19 | access to local variable x1 | Operators.cs:7:25:7:25 | 2 | >>> | UnsignedRightShiftExpr | | Operators.cs:7:18:7:25 | ... >>> ... | Operators.cs:7:18:7:19 | access to local variable x1 | Operators.cs:7:25:7:25 | 2 | >>> | UnsignedRightShiftExpr |
| Operators.cs:10:18:10:25 | ... >>> ... | Operators.cs:10:18:10:19 | access to local variable y1 | Operators.cs:10:25:10:25 | 3 | >>> | UnsignedRightShiftExpr | | Operators.cs:10:18:10:25 | ... >>> ... | Operators.cs:10:18:10:19 | access to local variable y1 | Operators.cs:10:25:10:25 | 3 | >>> | UnsignedRightShiftExpr |
| Operators.cs:13:9:13:16 | ... >>>= ... | Operators.cs:13:9:13:9 | access to local variable z | Operators.cs:13:16:13:16 | 5 | >>>= | AssignUnsignedRightShiftExpr |
assignbitwise assignbitwise
| Operators.cs:13:9:13:16 | ... >>>= ... | Operators.cs:13:9:13:9 | access to local variable z | Operators.cs:13:16:13:16 | 5 | >>>= | AssignUnsignedRightShiftExpr | | Operators.cs:13:9:13:16 | ... >>>= ... | Operators.cs:13:9:13:9 | access to local variable z | Operators.cs:13:16:13:16 | 5 | >>>= | AssignUnsignedRightShiftExpr |
userdefined userdefined

View File

@@ -11,7 +11,7 @@ query predicate binarybitwise(
} }
query predicate assignbitwise( query predicate assignbitwise(
AssignBitwiseExpr op, Expr left, Expr right, string name, string qlclass AssignBitwiseOperation op, Expr left, Expr right, string name, string qlclass
) { ) {
op.getFile().getStem() = "Operators" and op.getFile().getStem() = "Operators" and
left = op.getLeftOperand() and left = op.getLeftOperand() and

View File

@@ -442,31 +442,4 @@ namespace My.Qltest
static void Sink(object o) { } static void Sink(object o) { }
} }
// Test operator overloads
public class N
{
public void operator +=(N y) => throw null;
public void operator checked +=(N y) => throw null;
public void M1(N n)
{
var n0 = new N();
n += n0;
Sink(n);
}
public void M2(N n)
{
var n0 = new N();
checked
{
n += n0;
}
Sink(n);
}
static void Sink(object o) { }
}
} }

View File

@@ -32,16 +32,14 @@ models
| 31 | Summary: My.Qltest; Library; false; GetValue; (); ; Argument[this].SyntheticField[X]; ReturnValue; value; dfc-generated | | 31 | Summary: My.Qltest; Library; false; GetValue; (); ; Argument[this].SyntheticField[X]; ReturnValue; value; dfc-generated |
| 32 | Summary: My.Qltest; Library; false; MixedFlowArgs; (System.Object,System.Object); ; Argument[1]; ReturnValue; value; manual | | 32 | Summary: My.Qltest; Library; false; MixedFlowArgs; (System.Object,System.Object); ; Argument[1]; ReturnValue; value; manual |
| 33 | Summary: My.Qltest; Library; false; SetValue; (System.Object); ; Argument[0]; Argument[this].SyntheticField[X]; value; dfc-generated | | 33 | Summary: My.Qltest; Library; false; SetValue; (System.Object); ; Argument[0]; Argument[this].SyntheticField[X]; value; dfc-generated |
| 34 | Summary: My.Qltest; N; false; op_AdditionAssignment; (My.Qltest.N); ; Argument[0]; Argument[this]; taint; manual | | 34 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; Method1; (System.Object); ; Argument[0]; ReturnValue; value; manual |
| 35 | Summary: My.Qltest; N; false; op_CheckedAdditionAssignment; (My.Qltest.N); ; Argument[0]; Argument[this]; taint; manual | | 35 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; StaticMethod1; (System.Object); ; Argument[0]; ReturnValue; value; manual |
| 36 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; Method1; (System.Object); ; Argument[0]; ReturnValue; value; manual | | 36 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; get_Property1; (System.Object); ; Argument[0].SyntheticField[TestExtensions.Property1]; ReturnValue; value; manual |
| 37 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; StaticMethod1; (System.Object); ; Argument[0]; ReturnValue; value; manual | | 37 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; set_Property1; (System.Object,System.Object); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.Property1]; value; manual |
| 38 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; get_Property1; (System.Object); ; Argument[0].SyntheticField[TestExtensions.Property1]; ReturnValue; value; manual | | 38 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; GenericMethod1; (T); ; Argument[0]; ReturnValue; value; manual |
| 39 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; set_Property1; (System.Object,System.Object); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.Property1]; value; manual | | 39 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; GenericStaticMethod1; (T); ; Argument[0]; ReturnValue; value; manual |
| 40 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; GenericMethod1; (T); ; Argument[0]; ReturnValue; value; manual | | 40 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; get_GenericProperty1; (T); ; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; ReturnValue; value; manual |
| 41 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; GenericStaticMethod1; (T); ; Argument[0]; ReturnValue; value; manual | | 41 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; set_GenericProperty1; (T,T); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; value; manual |
| 42 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; get_GenericProperty1; (T); ; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; ReturnValue; value; manual |
| 43 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; set_GenericProperty1; (T,T); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; value; manual |
edges edges
| ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | ExternalFlow.cs:10:29:10:32 | access to local variable arg1 : Object | provenance | | | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | ExternalFlow.cs:10:29:10:32 | access to local variable arg1 : Object | provenance | |
| ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | provenance | | | ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | provenance | |
@@ -164,77 +162,69 @@ edges
| ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:373:23:373:34 | object creation of type Object : Object | ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:373:23:373:34 | object creation of type Object : Object | ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | ExternalFlow.cs:375:18:375:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | ExternalFlow.cs:375:18:375:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:374:22:374:24 | access to local variable obj : Object | ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | provenance | MaD:36 | | ExternalFlow.cs:374:22:374:24 | access to local variable obj : Object | ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | provenance | MaD:34 |
| ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | ExternalFlow.cs:378:18:378:19 | access to local variable o2 | provenance | | | ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | ExternalFlow.cs:378:18:378:19 | access to local variable o2 | provenance | |
| ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | provenance | | | ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | provenance | |
| ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | provenance | MaD:36 | | ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | provenance | MaD:34 |
| ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:383:23:383:34 | object creation of type Object : Object | ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:383:23:383:34 | object creation of type Object : Object | ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | ExternalFlow.cs:385:18:385:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | ExternalFlow.cs:385:18:385:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | provenance | MaD:37 | | ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | provenance | MaD:35 |
| ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | ExternalFlow.cs:388:18:388:19 | access to local variable o2 | provenance | | | ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | ExternalFlow.cs:388:18:388:19 | access to local variable o2 | provenance | |
| ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | provenance | | | ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | provenance | |
| ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | provenance | MaD:37 | | ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | provenance | MaD:35 |
| ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:393:23:393:34 | object creation of type Object : Object | ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:393:23:393:34 | object creation of type Object : Object | ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | | | ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | |
| ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:39 | | ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:37 |
| ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | ExternalFlow.cs:396:18:396:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | ExternalFlow.cs:396:18:396:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | provenance | MaD:38 | | ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | provenance | MaD:36 |
| ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:401:23:401:34 | object creation of type Object : Object | ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:401:23:401:34 | object creation of type Object : Object | ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | | | ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | |
| ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:39 | | ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:37 |
| ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | ExternalFlow.cs:404:18:404:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | ExternalFlow.cs:404:18:404:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | provenance | MaD:38 | | ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | provenance | MaD:36 |
| ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:409:23:409:34 | object creation of type Object : Object | ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:409:23:409:34 | object creation of type Object : Object | ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | ExternalFlow.cs:411:18:411:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | ExternalFlow.cs:411:18:411:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | provenance | MaD:40 | | ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | provenance | MaD:38 |
| ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | ExternalFlow.cs:414:18:414:19 | access to local variable o2 | provenance | | | ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | ExternalFlow.cs:414:18:414:19 | access to local variable o2 | provenance | |
| ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | provenance | | | ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | provenance | |
| ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | provenance | MaD:40 | | ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | provenance | MaD:38 |
| ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | ExternalFlow.cs:421:18:421:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | ExternalFlow.cs:421:18:421:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | provenance | MaD:41 | | ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | provenance | MaD:39 |
| ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | provenance | | | ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | provenance | |
| ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | provenance | | | ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | provenance | |
| ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | provenance | MaD:41 | | ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | provenance | MaD:39 |
| ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | provenance | | | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | provenance | |
| ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | | | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | |
| ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | provenance | | | ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | provenance | |
| ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:43 | | ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:41 |
| ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | | | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | |
| ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | MaD:42 | | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | MaD:40 |
| ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | | | ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | |
| ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:43 | | ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:41 |
| ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | provenance | MaD:42 | | ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | provenance | MaD:40 |
| ExternalFlow.cs:455:17:455:18 | access to local variable n0 : N | ExternalFlow.cs:456:18:456:19 | access to local variable n0 : N | provenance | |
| ExternalFlow.cs:455:22:455:28 | object creation of type N : N | ExternalFlow.cs:455:17:455:18 | access to local variable n0 : N | provenance | |
| ExternalFlow.cs:456:13:456:13 | [post] access to parameter n : N | ExternalFlow.cs:457:18:457:18 | access to parameter n | provenance | |
| ExternalFlow.cs:456:18:456:19 | access to local variable n0 : N | ExternalFlow.cs:456:13:456:13 | [post] access to parameter n : N | provenance | MaD:34 |
| ExternalFlow.cs:462:17:462:18 | access to local variable n0 : N | ExternalFlow.cs:465:22:465:23 | access to local variable n0 : N | provenance | |
| ExternalFlow.cs:462:22:462:28 | object creation of type N : N | ExternalFlow.cs:462:17:462:18 | access to local variable n0 : N | provenance | |
| ExternalFlow.cs:465:17:465:17 | [post] access to parameter n : N | ExternalFlow.cs:467:18:467:18 | access to parameter n | provenance | |
| ExternalFlow.cs:465:22:465:23 | access to local variable n0 : N | ExternalFlow.cs:465:17:465:17 | [post] access to parameter n : N | provenance | MaD:35 |
nodes nodes
| ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | semmle.label | access to local variable arg1 : Object | | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | semmle.label | access to local variable arg1 : Object |
| ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | | ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
@@ -453,16 +443,6 @@ nodes
| ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | semmle.label | call to extension accessor get_GenericProperty1 : Object | | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | semmle.label | call to extension accessor get_GenericProperty1 : Object |
| ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | semmle.label | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | | ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | semmle.label | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object |
| ExternalFlow.cs:440:18:440:19 | access to local variable o1 | semmle.label | access to local variable o1 | | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | semmle.label | access to local variable o1 |
| ExternalFlow.cs:455:17:455:18 | access to local variable n0 : N | semmle.label | access to local variable n0 : N |
| ExternalFlow.cs:455:22:455:28 | object creation of type N : N | semmle.label | object creation of type N : N |
| ExternalFlow.cs:456:13:456:13 | [post] access to parameter n : N | semmle.label | [post] access to parameter n : N |
| ExternalFlow.cs:456:18:456:19 | access to local variable n0 : N | semmle.label | access to local variable n0 : N |
| ExternalFlow.cs:457:18:457:18 | access to parameter n | semmle.label | access to parameter n |
| ExternalFlow.cs:462:17:462:18 | access to local variable n0 : N | semmle.label | access to local variable n0 : N |
| ExternalFlow.cs:462:22:462:28 | object creation of type N : N | semmle.label | object creation of type N : N |
| ExternalFlow.cs:465:17:465:17 | [post] access to parameter n : N | semmle.label | [post] access to parameter n : N |
| ExternalFlow.cs:465:22:465:23 | access to local variable n0 : N | semmle.label | access to local variable n0 : N |
| ExternalFlow.cs:467:18:467:18 | access to parameter n | semmle.label | access to parameter n |
subpaths subpaths
| ExternalFlow.cs:84:29:84:32 | access to local variable objs : null [element] : Object | ExternalFlow.cs:84:35:84:35 | o : Object | ExternalFlow.cs:84:40:84:40 | access to parameter o : Object | ExternalFlow.cs:84:25:84:41 | call to method Map<Object,Object> : T[] [element] : Object | | ExternalFlow.cs:84:29:84:32 | access to local variable objs : null [element] : Object | ExternalFlow.cs:84:35:84:35 | o : Object | ExternalFlow.cs:84:40:84:40 | access to parameter o : Object | ExternalFlow.cs:84:25:84:41 | call to method Map<Object,Object> : T[] [element] : Object |
invalidModelRow invalidModelRow
@@ -509,5 +489,3 @@ invalidModelRow
| ExternalFlow.cs:424:18:424:19 | access to local variable o2 | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | $@ | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | $@ | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:432:18:432:19 | access to local variable o1 | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | $@ | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | $@ | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:440:18:440:19 | access to local variable o1 | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | $@ | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | $@ | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:457:18:457:18 | access to parameter n | ExternalFlow.cs:455:22:455:28 | object creation of type N : N | ExternalFlow.cs:457:18:457:18 | access to parameter n | $@ | ExternalFlow.cs:455:22:455:28 | object creation of type N : N | object creation of type N : N |
| ExternalFlow.cs:467:18:467:18 | access to parameter n | ExternalFlow.cs:462:22:462:28 | object creation of type N : N | ExternalFlow.cs:467:18:467:18 | access to parameter n | $@ | ExternalFlow.cs:462:22:462:28 | object creation of type N : N | object creation of type N : N |

View File

@@ -53,8 +53,6 @@ extensions:
- ["My.Qltest", "TestExtensions+extension(T)<T>", false, "GenericStaticMethod1", "(T)", "", "Argument[0]", "ReturnValue", "value", "manual"] - ["My.Qltest", "TestExtensions+extension(T)<T>", false, "GenericStaticMethod1", "(T)", "", "Argument[0]", "ReturnValue", "value", "manual"]
- ["My.Qltest", "TestExtensions+extension(T)<T>", false, "get_GenericProperty1", "(T)", "", "Argument[0].SyntheticField[TestExtensions.GenericProperty1]", "ReturnValue", "value", "manual"] - ["My.Qltest", "TestExtensions+extension(T)<T>", false, "get_GenericProperty1", "(T)", "", "Argument[0].SyntheticField[TestExtensions.GenericProperty1]", "ReturnValue", "value", "manual"]
- ["My.Qltest", "TestExtensions+extension(T)<T>", false, "set_GenericProperty1", "(T,T)", "", "Argument[1]", "Argument[0].SyntheticField[TestExtensions.GenericProperty1]", "value", "manual"] - ["My.Qltest", "TestExtensions+extension(T)<T>", false, "set_GenericProperty1", "(T,T)", "", "Argument[1]", "Argument[0].SyntheticField[TestExtensions.GenericProperty1]", "value", "manual"]
- ["My.Qltest", "N", false, "op_AdditionAssignment", "(My.Qltest.N)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["My.Qltest", "N", false, "op_CheckedAdditionAssignment", "(My.Qltest.N)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- addsTo: - addsTo:
pack: codeql/csharp-all pack: codeql/csharp-all

View File

@@ -63,32 +63,4 @@ namespace Testing
{ {
public void MyActionMethod(string param) { } public void MyActionMethod(string param) { }
} }
// Razor Page handler tests
public class MyPageModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
{
// Handler method parameters are remote flow sources
public void OnGet(string id) { }
public void OnPost(string command, int count) { }
public void OnPostAsync(string data) { }
public void OnPut(string value) { }
public void OnDelete(string itemId) { }
// Not a handler method — does not start with "On", so not a flow source
public void GetUser(string userId) { }
// Excluded by [NonHandler] attribute, so not a flow source
[Microsoft.AspNetCore.Mvc.RazorPages.NonHandlerAttribute]
public void OnGetNonHandler(string param) { }
}
// Subclass of a PageModel subclass
public class DerivedPageModel : MyPageModel
{
public void OnPost(string derivedParam) { }
}
} }

View File

@@ -14,10 +14,3 @@ remoteFlowSources
| AspRemoteFlowSource.cs:54:69:54:82 | mapDeleteParam | | AspRemoteFlowSource.cs:54:69:54:82 | mapDeleteParam |
| AspRemoteFlowSource.cs:56:41:56:44 | item | | AspRemoteFlowSource.cs:56:41:56:44 | item |
| AspRemoteFlowSource.cs:64:43:64:47 | param | | AspRemoteFlowSource.cs:64:43:64:47 | param |
| AspRemoteFlowSource.cs:71:34:71:35 | id |
| AspRemoteFlowSource.cs:73:35:73:41 | command |
| AspRemoteFlowSource.cs:73:48:73:52 | count |
| AspRemoteFlowSource.cs:75:40:75:43 | data |
| AspRemoteFlowSource.cs:77:34:77:38 | value |
| AspRemoteFlowSource.cs:79:37:79:42 | itemId |
| AspRemoteFlowSource.cs:92:35:92:46 | derivedParam |

View File

@@ -293,69 +293,3 @@ properties.cs:
# 160| 0: [LocalVariableAccess] access to local variable x # 160| 0: [LocalVariableAccess] access to local variable x
# 160| 1: [PropertyCall] access to property Prop # 160| 1: [PropertyCall] access to property Prop
# 160| -1: [LocalVariableAccess] access to local variable s # 160| -1: [LocalVariableAccess] access to local variable s
# 164| 13: [Class] BaseClass
# 166| 6: [Property] Value
# 166| -1: [TypeMention] int
# 168| 3: [Getter] get_Value
# 168| 4: [BlockStmt] {...}
# 168| 0: [ReturnStmt] return ...;
# 168| 0: [FieldAccess] access to field Value.field
# 169| 4: [Setter] set_Value
#-----| 2: (Parameters)
# 169| 0: [Parameter] value
# 169| 4: [BlockStmt] {...}
# 169| 0: [ExprStmt] ...;
# 169| 0: [AssignExpr] ... = ...
# 169| 0: [FieldAccess] access to field Value.field
# 169| 1: [ParameterAccess] access to parameter value
# 166| 7: [Field] Value.field
# 173| 14: [Class] DerivedClass1
#-----| 3: (Base types)
# 173| 0: [TypeMention] BaseClass
# 175| 6: [Property] Value
# 175| -1: [TypeMention] int
# 177| 3: [Getter] get_Value
# 177| 4: [BlockStmt] {...}
# 177| 0: [ReturnStmt] return ...;
# 177| 0: [IntLiteral] 20
# 181| 15: [Class] DerivedClass2
#-----| 3: (Base types)
# 181| 0: [TypeMention] BaseClass
# 183| 16: [Class] TestPartialPropertyOverride
# 185| 6: [Method] M
# 185| -1: [TypeMention] Void
# 186| 4: [BlockStmt] {...}
# 187| 0: [LocalVariableDeclStmt] ... ...;
# 187| 0: [LocalVariableDeclAndInitExpr] DerivedClass1 d1 = ...
# 187| -1: [TypeMention] DerivedClass1
# 187| 0: [LocalVariableAccess] access to local variable d1
# 187| 1: [ObjectCreation] object creation of type DerivedClass1
# 187| 0: [TypeMention] DerivedClass1
# 188| 1: [ExprStmt] ...;
# 188| 0: [AssignExpr] ... = ...
# 188| 0: [PropertyCall] access to property Value
# 188| -1: [LocalVariableAccess] access to local variable d1
# 188| 1: [IntLiteral] 11
# 189| 2: [LocalVariableDeclStmt] ... ...;
# 189| 0: [LocalVariableDeclAndInitExpr] Int32 test1 = ...
# 189| -1: [TypeMention] int
# 189| 0: [LocalVariableAccess] access to local variable test1
# 189| 1: [PropertyCall] access to property Value
# 189| -1: [LocalVariableAccess] access to local variable d1
# 191| 3: [LocalVariableDeclStmt] ... ...;
# 191| 0: [LocalVariableDeclAndInitExpr] DerivedClass2 d2 = ...
# 191| -1: [TypeMention] DerivedClass2
# 191| 0: [LocalVariableAccess] access to local variable d2
# 191| 1: [ObjectCreation] object creation of type DerivedClass2
# 191| 0: [TypeMention] DerivedClass2
# 192| 4: [ExprStmt] ...;
# 192| 0: [AssignExpr] ... = ...
# 192| 0: [PropertyCall] access to property Value
# 192| -1: [LocalVariableAccess] access to local variable d2
# 192| 1: [IntLiteral] 12
# 193| 5: [LocalVariableDeclStmt] ... ...;
# 193| 0: [LocalVariableDeclAndInitExpr] Int32 test2 = ...
# 193| -1: [TypeMention] int
# 193| 0: [LocalVariableAccess] access to local variable test2
# 193| 1: [PropertyCall] access to property Value
# 193| -1: [LocalVariableAccess] access to local variable d2

View File

@@ -1,5 +1,4 @@
| Prop.field | | Prop.field |
| Value.field |
| caption | | caption |
| next | | next |
| x | | x |

View File

@@ -6,7 +6,3 @@
| properties.cs:71:28:71:28 | Y | properties.cs:83:39:83:44 | access to property Y | properties.cs:74:13:74:15 | set_Y | | properties.cs:71:28:71:28 | Y | properties.cs:83:39:83:44 | access to property Y | properties.cs:74:13:74:15 | set_Y |
| properties.cs:146:24:146:27 | Prop | properties.cs:159:13:159:18 | access to property Prop | properties.cs:148:13:148:15 | get_Prop | | properties.cs:146:24:146:27 | Prop | properties.cs:159:13:159:18 | access to property Prop | properties.cs:148:13:148:15 | get_Prop |
| properties.cs:146:24:146:27 | Prop | properties.cs:160:21:160:26 | access to property Prop | properties.cs:148:13:148:15 | get_Prop | | properties.cs:146:24:146:27 | Prop | properties.cs:160:21:160:26 | access to property Prop | properties.cs:148:13:148:15 | get_Prop |
| properties.cs:166:28:166:32 | Value | properties.cs:192:13:192:20 | access to property Value | properties.cs:169:13:169:15 | set_Value |
| properties.cs:166:28:166:32 | Value | properties.cs:193:25:193:32 | access to property Value | properties.cs:168:13:168:15 | get_Value |
| properties.cs:175:29:175:33 | Value | properties.cs:188:13:188:20 | access to property Value | properties.cs:169:13:169:15 | set_Value |
| properties.cs:175:29:175:33 | Value | properties.cs:189:25:189:32 | access to property Value | properties.cs:177:13:177:15 | get_Value |

View File

@@ -160,37 +160,4 @@ namespace Properties
var x = s.Prop; var x = s.Prop;
} }
} }
public class BaseClass
{
public virtual int Value
{
get { return field; }
set { field = value; }
}
}
public class DerivedClass1 : BaseClass
{
public override int Value
{
get { return 20; }
}
}
public class DerivedClass2 : BaseClass { }
public class TestPartialPropertyOverride
{
public void M()
{
var d1 = new DerivedClass1();
d1.Value = 11;
var test1 = d1.Value;
var d2 = new DerivedClass2();
d2.Value = 12;
var test2 = d2.Value;
}
}
} }

View File

@@ -1,29 +0,0 @@
using System;
public class C
{
public void M(int a, int b)
{
var s = "hello world";
var sub1 = s[1..a];
var sub2 = s[..2];
var sub3 = s[3..];
var sub4 = s[..^4];
var sub5 = s[a..^b];
var sub6 = s[..];
Range range = 1..a;
var sub7 = s[range];
Span<int> sp = null;
var slice1 = sp[5..a];
var slice2 = sp[..6];
var slice3 = sp[7..];
var slice4 = sp[..^8];
var slice5 = sp[a..^b];
var slice6 = sp[..];
Range range2 = 1..a;
var slice7 = sp[range2];
}
}

View File

@@ -1,41 +0,0 @@
methodArguments
| Slice.cs:8:20:8:26 | call to method Substring | Substring(int, int) | 0 | 1 |
| Slice.cs:8:20:8:26 | call to method Substring | Substring(int, int) | 1 | access to parameter a |
| Slice.cs:9:20:9:25 | call to method Substring | Substring(int, int) | 0 | 0 |
| Slice.cs:9:20:9:25 | call to method Substring | Substring(int, int) | 1 | 2 |
| Slice.cs:10:20:10:25 | call to method Substring | Substring(int, int) | 0 | 3 |
| Slice.cs:10:20:10:25 | call to method Substring | Substring(int, int) | 1 | ^0 |
| Slice.cs:11:20:11:26 | call to method Substring | Substring(int, int) | 0 | 0 |
| Slice.cs:11:20:11:26 | call to method Substring | Substring(int, int) | 1 | ^4 |
| Slice.cs:12:20:12:27 | call to method Substring | Substring(int, int) | 0 | access to parameter a |
| Slice.cs:12:20:12:27 | call to method Substring | Substring(int, int) | 1 | ^access to parameter b |
| Slice.cs:13:20:13:24 | call to method Substring | Substring(int, int) | 0 | 0 |
| Slice.cs:13:20:13:24 | call to method Substring | Substring(int, int) | 1 | ^0 |
| Slice.cs:19:22:19:29 | call to method Slice | Slice(int, int) | 0 | 5 |
| Slice.cs:19:22:19:29 | call to method Slice | Slice(int, int) | 1 | access to parameter a |
| Slice.cs:20:22:20:28 | call to method Slice | Slice(int, int) | 0 | 0 |
| Slice.cs:20:22:20:28 | call to method Slice | Slice(int, int) | 1 | 6 |
| Slice.cs:21:22:21:28 | call to method Slice | Slice(int, int) | 0 | 7 |
| Slice.cs:21:22:21:28 | call to method Slice | Slice(int, int) | 1 | ^0 |
| Slice.cs:22:22:22:29 | call to method Slice | Slice(int, int) | 0 | 0 |
| Slice.cs:22:22:22:29 | call to method Slice | Slice(int, int) | 1 | ^8 |
| Slice.cs:23:22:23:30 | call to method Slice | Slice(int, int) | 0 | access to parameter a |
| Slice.cs:23:22:23:30 | call to method Slice | Slice(int, int) | 1 | ^access to parameter b |
| Slice.cs:24:22:24:27 | call to method Slice | Slice(int, int) | 0 | 0 |
| Slice.cs:24:22:24:27 | call to method Slice | Slice(int, int) | 1 | ^0 |
methodCalls
| Slice.cs:3:14:3:14 | call to method <object initializer> | <object initializer>() |
| Slice.cs:8:20:8:26 | call to method Substring | Substring(int, int) |
| Slice.cs:9:20:9:25 | call to method Substring | Substring(int, int) |
| Slice.cs:10:20:10:25 | call to method Substring | Substring(int, int) |
| Slice.cs:11:20:11:26 | call to method Substring | Substring(int, int) |
| Slice.cs:12:20:12:27 | call to method Substring | Substring(int, int) |
| Slice.cs:13:20:13:24 | call to method Substring | Substring(int, int) |
| Slice.cs:16:20:16:27 | call to method Substring | Substring(int, int) |
| Slice.cs:19:22:19:29 | call to method Slice | Slice(int, int) |
| Slice.cs:20:22:20:28 | call to method Slice | Slice(int, int) |
| Slice.cs:21:22:21:28 | call to method Slice | Slice(int, int) |
| Slice.cs:22:22:22:29 | call to method Slice | Slice(int, int) |
| Slice.cs:23:22:23:30 | call to method Slice | Slice(int, int) |
| Slice.cs:24:22:24:27 | call to method Slice | Slice(int, int) |
| Slice.cs:27:22:27:31 | call to method Slice | Slice(int, int) |

View File

@@ -1,17 +0,0 @@
import csharp
private string printExpr(Expr e) {
e = any(IndexExpr index | result = "^" + index.getExpr().toString())
or
not e instanceof IndexExpr and
result = e.toString()
}
query predicate methodArguments(MethodCall mc, string target, int i, string arg) {
target = mc.getTarget().toStringWithTypes() and
arg = printExpr(mc.getArgument(i))
}
query predicate methodCalls(MethodCall mc, string target) {
target = mc.getTarget().toStringWithTypes()
}

View File

@@ -0,0 +1,2 @@
| Quality.cs:26:19:26:26 | access to indexer | Call without target $@. | Quality.cs:26:19:26:26 | access to indexer | access to indexer |
| Quality.cs:29:21:29:27 | access to indexer | Call without target $@. | Quality.cs:29:21:29:27 | access to indexer | access to indexer |

View File

@@ -7,5 +7,7 @@
| Quality.cs:20:13:20:23 | access to property MyProperty6 | Call without target $@. | Quality.cs:20:13:20:23 | access to property MyProperty6 | access to property MyProperty6 | | Quality.cs:20:13:20:23 | access to property MyProperty6 | Call without target $@. | Quality.cs:20:13:20:23 | access to property MyProperty6 | access to property MyProperty6 |
| Quality.cs:23:9:23:14 | access to event Event1 | Call without target $@. | Quality.cs:23:9:23:14 | access to event Event1 | access to event Event1 | | Quality.cs:23:9:23:14 | access to event Event1 | Call without target $@. | Quality.cs:23:9:23:14 | access to event Event1 | access to event Event1 |
| Quality.cs:23:9:23:30 | delegate call | Call without target $@. | Quality.cs:23:9:23:30 | delegate call | delegate call | | Quality.cs:23:9:23:30 | delegate call | Call without target $@. | Quality.cs:23:9:23:30 | delegate call | delegate call |
| Quality.cs:26:19:26:26 | access to indexer | Call without target $@. | Quality.cs:26:19:26:26 | access to indexer | access to indexer |
| Quality.cs:29:21:29:27 | access to indexer | Call without target $@. | Quality.cs:29:21:29:27 | access to indexer | access to indexer |
| Quality.cs:38:16:38:26 | access to property MyProperty2 | Call without target $@. | Quality.cs:38:16:38:26 | access to property MyProperty2 | access to property MyProperty2 | | Quality.cs:38:16:38:26 | access to property MyProperty2 | Call without target $@. | Quality.cs:38:16:38:26 | access to property MyProperty2 | access to property MyProperty2 |
| Quality.cs:50:20:50:26 | object creation of type T | Call without target $@. | Quality.cs:50:20:50:26 | object creation of type T | object creation of type T | | Quality.cs:50:20:50:26 | object creation of type T | Call without target $@. | Quality.cs:50:20:50:26 | object creation of type T | object creation of type T |

View File

@@ -23,10 +23,10 @@ public class Test
Event1.Invoke(this, 5); Event1.Invoke(this, 5);
var str = "abcd"; var str = "abcd";
var sub = str[..3]; var sub = str[..3]; // TODO: this is not an indexer call, but rather a `str.Substring(0, 3)` call.
Span<int> sp = null; Span<int> sp = null;
var slice = sp[..3]; var slice = sp[..3]; // TODO: this is not an indexer call, but rather a `sp.Slice(0, 3)` call.
Span<byte> guidBytes = stackalloc byte[16]; Span<byte> guidBytes = stackalloc byte[16];
guidBytes[08] = 1; guidBytes[08] = 1;

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

@@ -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,15 +2,15 @@ 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.46.0 golang.org/x/tools v0.45.0
) )
require github.com/stretchr/testify v1.11.1 require github.com/stretchr/testify v1.11.1
@@ -18,6 +18,6 @@ require github.com/stretchr/testify v1.11.1
require ( require (
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sync v0.21.0 // indirect golang.org/x/sync v0.20.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

View File

@@ -6,12 +6,12 @@ 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.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/tools v0.46.0 h1:7jTurBkPZu4moS/Uy4OQT1M+QBlsj3wejyZwsT8Z7rk= golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
golang.org/x/tools v0.46.0/go.mod h1:FrD85F8l+NWL+9XWBSyVSHO6Ne4jutsfIFba7AWQ5Ys= golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@@ -1,4 +0,0 @@
---
category: deprecated
---
* `FuncTypeExpr.getResultDecl()` has been deprecated. Use `FuncTypeExpr.getResultDecl(int i)` instead.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* `DataFlow::ResultNode`s are no longer created for returned expressions in functions with named result parameters. In this case there are already result nodes corresponding to `IR::ReadResultInstruction`s at the end of the function body.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* `FuncTypeExpr.getNumResult()` now gets the number of result parameters. It previously got the number of result declarations, which is different when one result declaration declares more than one variable, as in `x, y int`. All uses of it expected the number of result parameters. Its QLDoc has been updated.

View File

@@ -1,8 +0,0 @@
---
category: minorAnalysis
---
* Added models for the `log/slog` package (Go 1.21+). Its logging functions and
`*slog.Logger` methods (`Debug`/`Info`/`Warn`/`Error`, their `Context`
variants, and `Log`/`LogAttrs`) are now recognized as logging sinks, so the
`go/log-injection` and `go/clear-text-logging` queries cover code that logs
through `slog`.

View File

@@ -1,29 +0,0 @@
extensions:
- addsTo:
pack: codeql/go-all
extensible: sinkModel
data:
# Package-level convenience functions (msg string, args ...any).
- ["log/slog", "", False, "Debug", "", "", "Argument[0..1]", "log-injection", "manual"]
- ["log/slog", "", False, "Info", "", "", "Argument[0..1]", "log-injection", "manual"]
- ["log/slog", "", False, "Warn", "", "", "Argument[0..1]", "log-injection", "manual"]
- ["log/slog", "", False, "Error", "", "", "Argument[0..1]", "log-injection", "manual"]
# Context variants (ctx, msg string, args ...any).
- ["log/slog", "", False, "DebugContext", "", "", "Argument[1..2]", "log-injection", "manual"]
- ["log/slog", "", False, "InfoContext", "", "", "Argument[1..2]", "log-injection", "manual"]
- ["log/slog", "", False, "WarnContext", "", "", "Argument[1..2]", "log-injection", "manual"]
- ["log/slog", "", False, "ErrorContext", "", "", "Argument[1..2]", "log-injection", "manual"]
# Log/LogAttrs (ctx, level, msg string, args/attrs ...).
- ["log/slog", "", False, "Log", "", "", "Argument[2..3]", "log-injection", "manual"]
- ["log/slog", "", False, "LogAttrs", "", "", "Argument[2..3]", "log-injection", "manual"]
# Methods on *slog.Logger.
- ["log/slog", "Logger", True, "Debug", "", "", "Argument[0..1]", "log-injection", "manual"]
- ["log/slog", "Logger", True, "Info", "", "", "Argument[0..1]", "log-injection", "manual"]
- ["log/slog", "Logger", True, "Warn", "", "", "Argument[0..1]", "log-injection", "manual"]
- ["log/slog", "Logger", True, "Error", "", "", "Argument[0..1]", "log-injection", "manual"]
- ["log/slog", "Logger", True, "DebugContext", "", "", "Argument[1..2]", "log-injection", "manual"]
- ["log/slog", "Logger", True, "InfoContext", "", "", "Argument[1..2]", "log-injection", "manual"]
- ["log/slog", "Logger", True, "WarnContext", "", "", "Argument[1..2]", "log-injection", "manual"]
- ["log/slog", "Logger", True, "ErrorContext", "", "", "Argument[1..2]", "log-injection", "manual"]
- ["log/slog", "Logger", True, "Log", "", "", "Argument[2..3]", "log-injection", "manual"]
- ["log/slog", "Logger", True, "LogAttrs", "", "", "Argument[2..3]", "log-injection", "manual"]

View File

@@ -1049,29 +1049,17 @@ class FuncTypeExpr extends @functypeexpr, TypeExpr, ScopeNode, FieldParent {
*/ */
int getNumParameter() { result = count(this.getAParameterDecl().getANameExpr()) } int getNumParameter() { result = count(this.getAParameterDecl().getANameExpr()) }
/** /** Gets the `i`th result of this function type (0-based). */
* Gets the `i`th result declaration of this function type (0-based).
*
* Note: `x, y int` is a single `ResultVariableDecl`.
*/
ResultVariableDecl getResultDecl(int i) { result = this.getField(-(i + 1)) } ResultVariableDecl getResultDecl(int i) { result = this.getField(-(i + 1)) }
/** /** Gets a result of this function type. */
* Gets a result declaration of this function type.
*
* Note: `x, y int` is a single `ResultVariableDecl`.
*/
ResultVariableDecl getAResultDecl() { result = this.getResultDecl(_) } ResultVariableDecl getAResultDecl() { result = this.getResultDecl(_) }
/** Gets the number of result parameters of this function type. */ /** Gets the number of results of this function type. */
int getNumResult() { result = count(this.getAResultDecl().getANameExpr()) } int getNumResult() { result = count(this.getAResultDecl()) }
/** /** Gets the result of this function type, if there is only one. */
* DEPRECATED: Use `getResultDecl(int i)` instead. ResultVariableDecl getResultDecl() { this.getNumResult() = 1 and result = this.getAResultDecl() }
*/
deprecated ResultVariableDecl getResultDecl() {
this.getNumResult() = 1 and result = this.getAResultDecl()
}
override string toString() { result = "function type" } override string toString() { result = "function type" }

View File

@@ -923,20 +923,15 @@ module Public {
/** /**
* A node whose value is returned as a result from a function. * A node whose value is returned as a result from a function.
* *
* If the function declares named result variables, this is a node representing * This can either be a node corresponding to an expression in a return statement,
* the current value of one of those variables at function exit. Otherwise, this * or a node representing the current value of a named result variable at the exit
* is a node corresponding to an expression in a return statement. * of the function.
*/ */
class ResultNode extends InstructionNode { class ResultNode extends InstructionNode {
int i; int i;
ResultNode() { ResultNode() {
exists(FuncDef fd | exists(FuncDef fd |
// If the function has named result variables, then the
// `IR::ReadResultInstruction` nodes at the end of the function are
// the correct result nodes. Otherwise, the returned expressions are
// the result nodes.
not exists(fd.getAResultVar()) and
exists(IR::ReturnInstruction ret | ret.getRoot() = fd | insn = ret.getResult(i)) exists(IR::ReturnInstruction ret | ret.getRoot() = fd | insn = ret.getResult(i))
or or
insn.(IR::ReadResultInstruction).reads(fd.getResultVar(i)) insn.(IR::ReadResultInstruction).reads(fd.getResultVar(i))

View File

@@ -55,7 +55,7 @@ class SyncFileFun extends Method {
/** /**
* Holds if a `call` to a function is "unhandled". That is, it is either * Holds if a `call` to a function is "unhandled". That is, it is either
* deferred or used as an expression statement, so that its result is discarded. * deferred or its result is not assigned to anything.
* *
* TODO: maybe we should check that something is actually done with the result * TODO: maybe we should check that something is actually done with the result
*/ */
@@ -77,6 +77,7 @@ predicate isWritableFileHandle(DataFlow::Node source, DataFlow::CallNode call) {
// get the flags expression used for opening the file // get the flags expression used for opening the file
call.getArgument(1) = flags and call.getArgument(1) = flags and
// extract individual flags from the argument // extract individual flags from the argument
// flag = flag.getAChild*() and
flag = getConstants(flags.asExpr()) and flag = getConstants(flags.asExpr()) and
// check for one which signals that the handle will be writable // check for one which signals that the handle will be writable
// note that we are underestimating here, since the flags may be // note that we are underestimating here, since the flags may be
@@ -86,18 +87,27 @@ predicate isWritableFileHandle(DataFlow::Node source, DataFlow::CallNode call) {
} }
/** /**
* Holds if `postDominator` post-dominates `node` in the control-flow graph. That is, * Holds if `os.File.Close` is called on `sink`.
* every path from `node` to the exit of the enclosing function passes through
* `postDominator`.
*/ */
pragma[inline] predicate isCloseSink(DataFlow::Node sink, DataFlow::CallNode closeCall) {
predicate postDominatesNode(ControlFlow::Node postDominator, ControlFlow::Node node) { // find calls to the os.File.Close function
exists(ReachableBasicBlock pdbb, ReachableBasicBlock nbb, int i, int j | closeCall = any(CloseFileFun f).getACall() and
postDominator = pdbb.getNode(i) and node = nbb.getNode(j) // that are unhandled
| unhandledCall(closeCall) and
pdbb.strictlyPostDominates(nbb) // where the function is called on the sink
or closeCall.getReceiver() = sink and
pdbb = nbb and i >= j // and check that it is not dominated by a call to `os.File.Sync`.
// TODO: fix this logic when `closeCall` is in a defer statement.
not exists(IR::Instruction syncInstr, DataFlow::Node syncReceiver, DataFlow::CallNode syncCall |
// match the instruction corresponding to an `os.File.Sync` call with the predecessor
syncCall.asInstruction() = syncInstr and
// check that the call to `os.File.Sync` is handled
isHandledSync(syncReceiver, syncCall) and
// find a predecessor to `closeCall` in the control flow graph which dominates the call to
// `os.File.Close`
syncInstr.dominatesNode(closeCall.asInstruction()) and
// check that `os.File.Sync` is called on the same object as `os.File.Close`
exists(DataFlow::SsaNode ssa | ssa.getAUse() = sink and ssa.getAUse() = syncReceiver)
) )
} }
@@ -117,39 +127,7 @@ predicate isHandledSync(DataFlow::Node sink, DataFlow::CallNode syncCall) {
module UnhandledFileCloseConfig implements DataFlow::ConfigSig { module UnhandledFileCloseConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { isWritableFileHandle(source, _) } predicate isSource(DataFlow::Node source) { isWritableFileHandle(source, _) }
predicate isSink(DataFlow::Node sink) { predicate isSink(DataFlow::Node sink) { isCloseSink(sink, _) }
exists(DataFlow::CallNode closeCall |
// `closeCall` is an unhandled call to `os.File.Close` on `sink`
closeCall = any(CloseFileFun f).getACall() and
unhandledCall(closeCall) and
closeCall.getReceiver() = sink
|
// `closeCall` is not guaranteed to be preceded during
// execution by a handled call to `os.File.Sync` on the same file handle.
not exists(DataFlow::Node syncReceiver, DataFlow::CallNode syncCall |
// check that the call to `os.File.Sync` is handled
isHandledSync(syncReceiver, syncCall) and
// check that `os.File.Sync` is called on the same object as `os.File.Close`
exists(DataFlow::SsaNode ssa | ssa.getAUse() = sink and ssa.getAUse() = syncReceiver)
|
if exists(DeferStmt defer | defer.getCall() = closeCall.asExpr())
then
// When the call to `os.File.Close` is deferred it runs when the enclosing function
// returns, but the receiver of the deferred call is evaluated where the `defer`
// statement appears. It is therefore enough for the handled call to `os.File.Sync`
// to post-dominate that point, since that guarantees `os.File.Sync` runs before the
// deferred `os.File.Close` on every path on which the `os.File.Close` is registered.
// We cannot reuse the domination check below because the control-flow graph splices
// the deferred call in at the function exit, where it may be reachable along paths
// that do not pass through the call to `os.File.Sync`.
postDominatesNode(syncCall.asInstruction(), sink.asInstruction())
else
// Otherwise the call to `os.File.Close` is executed where it appears, so we require
// the handled call to `os.File.Sync` to dominate it.
syncCall.asInstruction().dominatesNode(closeCall.asInstruction())
)
)
}
predicate observeDiffInformedIncrementalMode() { any() } predicate observeDiffInformedIncrementalMode() { any() }
@@ -170,12 +148,14 @@ import UnhandledFileCloseFlow::PathGraph
from from
UnhandledFileCloseFlow::PathNode source, DataFlow::CallNode openCall, UnhandledFileCloseFlow::PathNode source, DataFlow::CallNode openCall,
UnhandledFileCloseFlow::PathNode sink UnhandledFileCloseFlow::PathNode sink, DataFlow::CallNode closeCall
where where
// find data flow from an `os.OpenFile` call to an `os.File.Close` call // find data flow from an `os.OpenFile` call to an `os.File.Close` call
// where the handle is writable // where the handle is writable
UnhandledFileCloseFlow::flowPath(source, sink) and UnhandledFileCloseFlow::flowPath(source, sink) and
isWritableFileHandle(source.getNode(), openCall) isWritableFileHandle(source.getNode(), openCall) and
// get the `CallNode` corresponding to the sink
isCloseSink(sink.getNode(), closeCall)
select sink, source, sink, select sink, source, sink,
"File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly.", "File handle may be writable as a result of data flow from a $@ and closing it may result in data loss upon failure, which is not handled explicitly.",
openCall, openCall.toString() openCall, openCall.toString()

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The query `go/unhandled-writable-file-close` ("Writable file handle closed without error handling") now produces fewer false positives. A deferred call to `Close` that is preceded on every execution path by a handled call to `Sync` on the same file handle is no longer flagged.

View File

@@ -1,4 +1,4 @@
/** /*
* @name Web Cache Deception * @name Web Cache Deception
* @description A caching system has been detected on the application and is vulnerable to web cache deception. By manipulating the URL it is possible to force the application to cache pages that are only accessible by an authenticated user. Once cached, these pages can be accessed by an unauthenticated user. * @description A caching system has been detected on the application and is vulnerable to web cache deception. By manipulating the URL it is possible to force the application to cache pages that are only accessible by an authenticated user. Once cached, these pages can be accessed by an unauthenticated user.
* @kind problem * @kind problem

View File

@@ -54,31 +54,31 @@ func main() {}
// bad is an example of a bad implementation // bad is an example of a bad implementation
func (ld *Ldap) bad(req *http.Request) { func (ld *Ldap) bad(req *http.Request) {
// ... // ...
untrusted := req.UserAgent() // $ Source untrusted := req.UserAgent()
goldap.NewSearchRequest( goldap.NewSearchRequest(
untrusted, // $ Alert // BAD: untrusted dn untrusted, // BAD: untrusted dn
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false, goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson))"+untrusted, // $ Alert // BAD: untrusted filter "(&(objectClass=organizationalPerson))"+untrusted, // BAD: untrusted filter
[]string{"dn", "cn", untrusted}, // $ Alert // BAD: untrusted attribute []string{"dn", "cn", untrusted}, // BAD: untrusted attribute
nil, nil,
) )
goldapv3.NewSearchRequest( goldapv3.NewSearchRequest(
untrusted, // $ Alert // BAD: untrusted dn untrusted, // BAD: untrusted dn
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false, goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson))"+untrusted, // $ Alert // BAD: untrusted filter "(&(objectClass=organizationalPerson))"+untrusted, // BAD: untrusted filter
[]string{"dn", "cn", untrusted}, // $ Alert // BAD: untrusted attribute []string{"dn", "cn", untrusted}, // BAD: untrusted attribute
nil, nil,
) )
gopkgldapv2.NewSearchRequest( gopkgldapv2.NewSearchRequest(
untrusted, // $ Alert // BAD: untrusted dn untrusted, // BAD: untrusted dn
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false, goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson))"+untrusted, // $ Alert // BAD: untrusted filter "(&(objectClass=organizationalPerson))"+untrusted, // BAD: untrusted filter
[]string{"dn", "cn", untrusted}, // $ Alert // BAD: untrusted attribute []string{"dn", "cn", untrusted}, // BAD: untrusted attribute
nil, nil,
) )
client := &ldapclient.LDAPClient{} client := &ldapclient.LDAPClient{}
client.Authenticate(untrusted, "123456") // $ Alert // BAD: untrusted filter client.Authenticate(untrusted, "123456") // BAD: untrusted filter
client.GetGroupsOfUser(untrusted) // $ Alert // BAD: untrusted filter client.GetGroupsOfUser(untrusted) // BAD: untrusted filter
// ... // ...
} }

View File

@@ -1,4 +1,2 @@
query: experimental/CWE-090/LDAPInjection.ql query: experimental/CWE-090/LDAPInjection.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,4 +1,2 @@
query: experimental/CWE-203/Timing.ql query: experimental/CWE-203/Timing.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -12,9 +12,9 @@ func bad(w http.ResponseWriter, req *http.Request) (interface{}, error) {
secret := "MySuperSecretPasscode" secret := "MySuperSecretPasscode"
secretHeader := "X-Secret" secretHeader := "X-Secret"
headerSecret := req.Header.Get(secretHeader) // $ Source headerSecret := req.Header.Get(secretHeader)
secretStr := string(secret) secretStr := string(secret)
if len(headerSecret) != 0 && headerSecret != secretStr { // $ Alert if len(headerSecret) != 0 && headerSecret != secretStr {
return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret) return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret)
} }
return nil, nil return nil, nil
@@ -25,9 +25,9 @@ func bad2(w http.ResponseWriter, req *http.Request) (interface{}, error) {
secret := "MySuperSecretPasscode" secret := "MySuperSecretPasscode"
secretHeader := "X-Secret" secretHeader := "X-Secret"
headerSecret := req.Header.Get(secretHeader) // $ Source headerSecret := req.Header.Get(secretHeader)
secretStr := string(secret) secretStr := string(secret)
if len(headerSecret) != 0 && strings.Compare(headerSecret, secretStr) != 0 { // $ Alert if len(headerSecret) != 0 && strings.Compare(headerSecret, secretStr) != 0 {
return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret) return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret)
} }
return nil, nil return nil, nil
@@ -38,8 +38,8 @@ func bad4(w http.ResponseWriter, req *http.Request) (interface{}, error) {
secret := "MySuperSecretPasscode" secret := "MySuperSecretPasscode"
secretHeader := "X-Secret" secretHeader := "X-Secret"
headerSecret := req.Header.Get(secretHeader) // $ Source headerSecret := req.Header.Get(secretHeader)
if len(secret) != 0 && headerSecret != "SecretStringLiteral" { // $ Alert if len(secret) != 0 && headerSecret != "SecretStringLiteral" {
return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret) return nil, fmt.Errorf("header %s=%s did not match expected secret", secretHeader, headerSecret)
} }
return nil, nil return nil, nil

View File

@@ -1,2 +1 @@
query: experimental/CWE-285/PamAuthBypass.ql experimental/CWE-285/PamAuthBypass.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -9,7 +9,7 @@ import (
func bad() error { func bad() error {
t, _ := pam.StartFunc("", "", func(s pam.Style, msg string) (string, error) { t, _ := pam.StartFunc("", "", func(s pam.Style, msg string) (string, error) {
return "", nil return "", nil
}) // $ Alert })
return t.Authenticate(0) return t.Authenticate(0)
} }

View File

@@ -15,7 +15,7 @@ func bad(w http.ResponseWriter, req *http.Request) (interface{}, error) {
ldapServer := "ldap.example.com" ldapServer := "ldap.example.com"
ldapPort := 389 ldapPort := 389
bindDN := "cn=admin,dc=example,dc=com" bindDN := "cn=admin,dc=example,dc=com"
bindPassword := req.URL.Query()["password"][0] // $ Source bindPassword := req.URL.Query()["password"][0]
// Connect to the LDAP server // Connect to the LDAP server
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
@@ -25,7 +25,7 @@ func bad(w http.ResponseWriter, req *http.Request) (interface{}, error) {
defer l.Close() defer l.Close()
// BAD: user input is not sanetized // BAD: user input is not sanetized
err = l.Bind(bindDN, bindPassword) // $ Alert err = l.Bind(bindDN, bindPassword)
if err != nil { if err != nil {
return fmt.Errorf("LDAP bind failed: %v", err), err return fmt.Errorf("LDAP bind failed: %v", err), err
} }
@@ -84,7 +84,7 @@ func bad2(req *http.Request) {
ldapPort := 389 ldapPort := 389
bindDN := "cn=admin,dc=example,dc=com" bindDN := "cn=admin,dc=example,dc=com"
// BAD : empty password // BAD : empty password
bindPassword := "" // $ Source bindPassword := ""
// Connect to the LDAP server // Connect to the LDAP server
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort)) l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
@@ -94,7 +94,7 @@ func bad2(req *http.Request) {
defer l.Close() defer l.Close()
// BAD : bindPassword is empty // BAD : bindPassword is empty
err = l.Bind(bindDN, bindPassword) // $ Alert err = l.Bind(bindDN, bindPassword)
if err != nil { if err != nil {
log.Fatalf("LDAP bind failed: %v", err) log.Fatalf("LDAP bind failed: %v", err)
} }

View File

@@ -1,4 +1,2 @@
query: experimental/CWE-287/ImproperLdapAuth.ql query: experimental/CWE-287/ImproperLdapAuth.ql
postprocess: postprocess: utils/test/PrettyPrintModels.ql
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,6 +1,3 @@
#select
| go-jose.v3.go:24:32:24:37 | JwtKey | go-jose.v3.go:13:21:13:33 | "AllYourBase" | go-jose.v3.go:24:32:24:37 | JwtKey | This $@. | go-jose.v3.go:13:21:13:33 | "AllYourBase" | Constant Key is used as JWT Secret key |
| golang-jwt-v5.go:27:9:27:15 | JwtKey1 | golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | golang-jwt-v5.go:27:9:27:15 | JwtKey1 | This $@. | golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | Constant Key is used as JWT Secret key |
edges edges
| go-jose.v3.go:13:14:13:34 | type conversion | go-jose.v3.go:24:32:24:37 | JwtKey | provenance | | | go-jose.v3.go:13:14:13:34 | type conversion | go-jose.v3.go:24:32:24:37 | JwtKey | provenance | |
| go-jose.v3.go:13:21:13:33 | "AllYourBase" | go-jose.v3.go:13:14:13:34 | type conversion | provenance | | | go-jose.v3.go:13:21:13:33 | "AllYourBase" | go-jose.v3.go:13:14:13:34 | type conversion | provenance | |
@@ -14,3 +11,6 @@ nodes
| golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | semmle.label | "AllYourBase" | | golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | semmle.label | "AllYourBase" |
| golang-jwt-v5.go:27:9:27:15 | JwtKey1 | semmle.label | JwtKey1 | | golang-jwt-v5.go:27:9:27:15 | JwtKey1 | semmle.label | JwtKey1 |
subpaths subpaths
#select
| go-jose.v3.go:24:32:24:37 | JwtKey | go-jose.v3.go:13:21:13:33 | "AllYourBase" | go-jose.v3.go:24:32:24:37 | JwtKey | This $@. | go-jose.v3.go:13:21:13:33 | "AllYourBase" | Constant Key is used as JWT Secret key |
| golang-jwt-v5.go:27:9:27:15 | JwtKey1 | golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | golang-jwt-v5.go:27:9:27:15 | JwtKey1 | This $@. | golang-jwt-v5.go:19:22:19:34 | "AllYourBase" | Constant Key is used as JWT Secret key |

View File

@@ -1,2 +1 @@
query: experimental/CWE-321-V2/HardCodedKeys.ql experimental/CWE-321-V2/HardCodedKeys.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

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