mirror of
https://github.com/github/codeql.git
synced 2026-06-08 22:48:54 +02:00
Compare commits
2 Commits
z80coder/q
...
esbena/atm
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3248fc2e1b | ||
|
|
55c35659b5 |
@@ -10,16 +10,7 @@
|
||||
"javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml",
|
||||
"misc/legacy-support/*/qlpack.yml",
|
||||
"misc/suite-helpers/qlpack.yml",
|
||||
"ruby/extractor-pack/codeql-extractor.yml",
|
||||
"ruby/ql/consistency-queries/qlpack.yml",
|
||||
"ql/ql/consistency-queries/qlpack.yml",
|
||||
"ql/extractor-pack/codeql-extractor.yml"
|
||||
],
|
||||
"versionPolicies": {
|
||||
"default": {
|
||||
"requireChangeNotes": true,
|
||||
"committedPrereleaseSuffix": "dev",
|
||||
"committedVersion": "nextPatchRelease"
|
||||
}
|
||||
}
|
||||
}
|
||||
"ruby/extractor-pack/codeql-extractor.yml"
|
||||
]
|
||||
}
|
||||
152
.github/workflows/ql-for-ql-build.yml
vendored
152
.github/workflows/ql-for-ql-build.yml
vendored
@@ -1,152 +0,0 @@
|
||||
name: Run QL for QL
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
queries:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@esbena/ql
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
- name: Get CodeQL version
|
||||
id: get-codeql-version
|
||||
run: |
|
||||
echo "::set-output name=version::$("${CODEQL}" --version | head -n 1 | rev | cut -d " " -f 1 | rev)"
|
||||
shell: bash
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
- name: Cache queries
|
||||
id: cache-queries
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ runner.temp }}/query-pack.zip
|
||||
key: queries-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}
|
||||
- name: Build query pack
|
||||
if: steps.cache-queries.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd ql/ql/src
|
||||
"${CODEQL}" pack create
|
||||
cd .codeql/pack/codeql/ql-all/0.0.0
|
||||
zip "${PACKZIP}" -r .
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
PACKZIP: ${{ runner.temp }}/query-pack.zip
|
||||
- name: Upload query pack
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: query-pack-zip
|
||||
path: ${{ runner.temp }}/query-pack.zip
|
||||
|
||||
extractors:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
ql/target
|
||||
key: ${{ runner.os }}-rust-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Check formatting
|
||||
run: cd ql; cargo fmt --all -- --check
|
||||
- name: Build
|
||||
run: cd ql; cargo build --verbose
|
||||
- name: Run tests
|
||||
run: cd ql; cargo test --verbose
|
||||
- name: Release build
|
||||
run: cd ql; cargo build --release
|
||||
- name: Generate dbscheme
|
||||
run: ql/target/release/ql-generator --dbscheme ql/ql/src/ql.dbscheme --library ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: extractor-ubuntu-latest
|
||||
path: |
|
||||
ql/target/release/ql-extractor
|
||||
ql/target/release/ql-extractor.exe
|
||||
retention-days: 1
|
||||
package:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
needs:
|
||||
- extractors
|
||||
- queries
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: query-pack-zip
|
||||
path: query-pack-zip
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: extractor-ubuntu-latest
|
||||
path: linux64
|
||||
- run: |
|
||||
unzip query-pack-zip/*.zip -d pack
|
||||
cp -r ql/codeql-extractor.yml ql/tools ql/ql/src/ql.dbscheme.stats pack/
|
||||
mkdir -p pack/tools/linux64
|
||||
if [[ -f linux64/ql-extractor ]]; then
|
||||
cp linux64/ql-extractor pack/tools/linux64/extractor
|
||||
chmod +x pack/tools/linux64/extractor
|
||||
fi
|
||||
cd pack
|
||||
zip -rq ../codeql-ql.zip .
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: codeql-ql-pack
|
||||
path: codeql-ql.zip
|
||||
retention-days: 1
|
||||
analyze:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
needs:
|
||||
- package
|
||||
|
||||
steps:
|
||||
- name: Download pack
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: codeql-ql-pack
|
||||
path: ${{ runner.temp }}/codeql-ql-pack-artifact
|
||||
|
||||
- name: Prepare pack
|
||||
run: |
|
||||
unzip "${PACK_ARTIFACT}/*.zip" -d "${PACK}"
|
||||
env:
|
||||
PACK_ARTIFACT: ${{ runner.temp }}/codeql-ql-pack-artifact
|
||||
PACK: ${{ runner.temp }}/pack
|
||||
- name: Hack codeql-action options
|
||||
run: |
|
||||
JSON=$(jq -nc --arg pack "${PACK}" '.resolve.queries=["--search-path", $pack] | .resolve.extractor=["--search-path", $pack] | .database.init=["--search-path", $pack]')
|
||||
echo "CODEQL_ACTION_EXTRA_OPTIONS=${JSON}" >> ${GITHUB_ENV}
|
||||
env:
|
||||
PACK: ${{ runner.temp }}/pack
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@esbena/ql
|
||||
with:
|
||||
languages: ql
|
||||
db-location: ${{ runner.temp }}/db
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@esbena/ql
|
||||
|
||||
84
.github/workflows/ql-for-ql-dataset_measure.yml
vendored
84
.github/workflows/ql-for-ql-dataset_measure.yml
vendored
@@ -1,84 +0,0 @@
|
||||
name: Collect database stats for QL for QL
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- ql/ql/src/ql.dbscheme
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- ql/ql/src/ql.dbscheme
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
measure:
|
||||
env:
|
||||
CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
|
||||
strategy:
|
||||
matrix:
|
||||
repo:
|
||||
- github/codeql
|
||||
- github/codeql-go
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@esbena/ql
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
ql/target
|
||||
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Build Extractor
|
||||
run: cd ql; env "PATH=$PATH:`dirname ${CODEQL}`" ./create-extractor-pack.sh
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
- name: Checkout ${{ matrix.repo }}
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: ${{ matrix.repo }}
|
||||
path: ${{ github.workspace }}/repo
|
||||
- name: Create database
|
||||
run: |
|
||||
"${CODEQL}" database create \
|
||||
--search-path "ql/extractor-pack" \
|
||||
--threads 4 \
|
||||
--language ql --source-root "${{ github.workspace }}/repo" \
|
||||
"${{ runner.temp }}/database"
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
- name: Measure database
|
||||
run: |
|
||||
mkdir -p "stats/${{ matrix.repo }}"
|
||||
"${CODEQL}" dataset measure --threads 4 --output "stats/${{ matrix.repo }}/stats.xml" "${{ runner.temp }}/database/db-ql"
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: measurements
|
||||
path: stats
|
||||
retention-days: 1
|
||||
|
||||
merge:
|
||||
runs-on: ubuntu-latest
|
||||
needs: measure
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: measurements
|
||||
path: stats
|
||||
- run: |
|
||||
python -m pip install --user lxml
|
||||
find stats -name 'stats.xml' -print0 | sort -z | xargs -0 python ql/scripts/merge_stats.py --output ql/ql/src/ql.dbscheme.stats --normalise ql_tokeninfo
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ql.dbscheme.stats
|
||||
path: ql/ql/src/ql.dbscheme.stats
|
||||
52
.github/workflows/ql-for-ql-tests.yml
vendored
52
.github/workflows/ql-for-ql-tests.yml
vendored
@@ -1,52 +0,0 @@
|
||||
name: Run QL for QL Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- ql/*
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- ql/*
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
qltest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@esbena/ql
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
ql/target
|
||||
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Build extractor
|
||||
run: |
|
||||
cd ql;
|
||||
codeqlpath=$(dirname ${{ steps.find-codeql.outputs.codeql-path }});
|
||||
env "PATH=$PATH:$codeqlpath" ./create-extractor-pack.sh
|
||||
- name: Run QL tests
|
||||
run: |
|
||||
"${CODEQL}" test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}/ql/extractor-pack" --consistency-queries ql/ql/consistency-queries ql/ql/test
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
- name: Check QL formatting
|
||||
run: |
|
||||
find ql/ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 "${CODEQL}" query format --check-only
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
- name: Check QL compilation
|
||||
run: |
|
||||
"${CODEQL}" query compile --check-only --threads=4 --warnings=error --search-path "${{ github.workspace }}/ql/extractor-pack" "ql/ql/src" "ql/ql/examples"
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
@@ -25,6 +25,3 @@
|
||||
/docs/codeql-for-visual-studio-code/ @github/codeql-vscode-reviewers
|
||||
/docs/ql-language-reference/ @github/codeql-frontend-reviewers
|
||||
/docs/query-*-style-guide.md @github/codeql-analysis-reviewers
|
||||
|
||||
# QL for QL reviewers
|
||||
/ql/ @erik-krogh @tausbn
|
||||
@@ -17,7 +17,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.Build" Version="16.9.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
## 0.0.4
|
||||
|
||||
### New Features
|
||||
|
||||
* The QL library `semmle.code.cpp.commons.Exclusions` now contains a predicate
|
||||
`isFromSystemMacroDefinition` for identifying code that originates from a
|
||||
macro outside the project being analyzed.
|
||||
@@ -1,7 +0,0 @@
|
||||
## 0.0.4
|
||||
|
||||
### New Features
|
||||
|
||||
* The QL library `semmle.code.cpp.commons.Exclusions` now contains a predicate
|
||||
`isFromSystemMacroDefinition` for identifying code that originates from a
|
||||
macro outside the project being analyzed.
|
||||
@@ -1,2 +0,0 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.4
|
||||
@@ -1,8 +1,7 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.0.5-dev
|
||||
groups: cpp
|
||||
version: 0.0.2
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
library: true
|
||||
dependencies:
|
||||
codeql/cpp-upgrades: ^0.0.3
|
||||
codeql/cpp-upgrades: 0.0.2
|
||||
|
||||
@@ -9,83 +9,6 @@ import semmle.code.cpp.models.interfaces.FormattingFunction
|
||||
private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||
|
||||
private newtype TBufferWriteEstimationReason =
|
||||
TNoSpecifiedEstimateReason() or
|
||||
TTypeBoundsAnalysis() or
|
||||
TValueFlowAnalysis()
|
||||
|
||||
/**
|
||||
* A reason for a specific buffer write size estimate.
|
||||
*/
|
||||
abstract class BufferWriteEstimationReason extends TBufferWriteEstimationReason {
|
||||
/**
|
||||
* Returns the name of the concrete class.
|
||||
*/
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Returns a human readable representation of this reason.
|
||||
*/
|
||||
abstract string getDescription();
|
||||
|
||||
/**
|
||||
* Combine estimate reasons. Used to give a reason for the size of a format string
|
||||
* conversion given reasons coming from its individual specifiers.
|
||||
*/
|
||||
abstract BufferWriteEstimationReason combineWith(BufferWriteEstimationReason other);
|
||||
}
|
||||
|
||||
/**
|
||||
* No particular reason given. This is currently used for backward compatibility so that
|
||||
* classes derived from BufferWrite and overriding `getMaxData/0` still work with the
|
||||
* queries as intended.
|
||||
*/
|
||||
class NoSpecifiedEstimateReason extends BufferWriteEstimationReason, TNoSpecifiedEstimateReason {
|
||||
override string toString() { result = "NoSpecifiedEstimateReason" }
|
||||
|
||||
override string getDescription() { result = "no reason specified" }
|
||||
|
||||
override BufferWriteEstimationReason combineWith(BufferWriteEstimationReason other) {
|
||||
// this reason should not be used in format specifiers, so it should not be combined
|
||||
// with other reasons
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The estimation comes from rough bounds just based on the type (e.g.
|
||||
* `0 <= x < 2^32` for an unsigned 32 bit integer).
|
||||
*/
|
||||
class TypeBoundsAnalysis extends BufferWriteEstimationReason, TTypeBoundsAnalysis {
|
||||
override string toString() { result = "TypeBoundsAnalysis" }
|
||||
|
||||
override string getDescription() { result = "based on type bounds" }
|
||||
|
||||
override BufferWriteEstimationReason combineWith(BufferWriteEstimationReason other) {
|
||||
other != TNoSpecifiedEstimateReason() and result = TTypeBoundsAnalysis()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The estimation comes from non trivial bounds found via actual flow analysis.
|
||||
* For example
|
||||
* ```
|
||||
* unsigned u = x;
|
||||
* if (u < 1000) {
|
||||
* //... <- estimation done here based on u
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class ValueFlowAnalysis extends BufferWriteEstimationReason, TValueFlowAnalysis {
|
||||
override string toString() { result = "ValueFlowAnalysis" }
|
||||
|
||||
override string getDescription() { result = "based on flow analysis of value bounds" }
|
||||
|
||||
override BufferWriteEstimationReason combineWith(BufferWriteEstimationReason other) {
|
||||
other != TNoSpecifiedEstimateReason() and result = other
|
||||
}
|
||||
}
|
||||
|
||||
class PrintfFormatAttribute extends FormatAttribute {
|
||||
PrintfFormatAttribute() { this.getArchetype() = ["printf", "__printf__"] }
|
||||
}
|
||||
@@ -1067,14 +990,7 @@ class FormatLiteral extends Literal {
|
||||
* conversion specifier of this format string; has no result if this cannot
|
||||
* be determined.
|
||||
*/
|
||||
int getMaxConvertedLength(int n) { result = max(getMaxConvertedLength(n, _)) }
|
||||
|
||||
/**
|
||||
* Gets the maximum length of the string that can be produced by the nth
|
||||
* conversion specifier of this format string, specifying the estimation reason;
|
||||
* has no result if this cannot be determined.
|
||||
*/
|
||||
int getMaxConvertedLength(int n, BufferWriteEstimationReason reason) {
|
||||
int getMaxConvertedLength(int n) {
|
||||
exists(int len |
|
||||
(
|
||||
(
|
||||
@@ -1086,12 +1002,10 @@ class FormatLiteral extends Literal {
|
||||
) and
|
||||
(
|
||||
this.getConversionChar(n) = "%" and
|
||||
len = 1 and
|
||||
reason = TValueFlowAnalysis()
|
||||
len = 1
|
||||
or
|
||||
this.getConversionChar(n).toLowerCase() = "c" and
|
||||
len = 1 and
|
||||
reason = TValueFlowAnalysis() // e.g. 'a'
|
||||
len = 1 // e.g. 'a'
|
||||
or
|
||||
this.getConversionChar(n).toLowerCase() = "f" and
|
||||
exists(int dot, int afterdot |
|
||||
@@ -1105,8 +1019,7 @@ class FormatLiteral extends Literal {
|
||||
afterdot = 6
|
||||
) and
|
||||
len = 1 + 309 + dot + afterdot
|
||||
) and
|
||||
reason = TTypeBoundsAnalysis() // e.g. -1e308="-100000"...
|
||||
) // e.g. -1e308="-100000"...
|
||||
or
|
||||
this.getConversionChar(n).toLowerCase() = "e" and
|
||||
exists(int dot, int afterdot |
|
||||
@@ -1120,8 +1033,7 @@ class FormatLiteral extends Literal {
|
||||
afterdot = 6
|
||||
) and
|
||||
len = 1 + 1 + dot + afterdot + 1 + 1 + 3
|
||||
) and
|
||||
reason = TTypeBoundsAnalysis() // -1e308="-1.000000e+308"
|
||||
) // -1e308="-1.000000e+308"
|
||||
or
|
||||
this.getConversionChar(n).toLowerCase() = "g" and
|
||||
exists(int dot, int afterdot |
|
||||
@@ -1144,80 +1056,67 @@ class FormatLiteral extends Literal {
|
||||
// (e.g. 123456, 0.000123456 are just OK)
|
||||
// so case %f can be at most P characters + 4 zeroes, sign, dot = P + 6
|
||||
len = (afterdot.maximum(1) + 6).maximum(1 + 1 + dot + afterdot + 1 + 1 + 3)
|
||||
) and
|
||||
reason = TTypeBoundsAnalysis() // (e.g. "-1.59203e-319")
|
||||
) // (e.g. "-1.59203e-319")
|
||||
or
|
||||
this.getConversionChar(n).toLowerCase() = ["d", "i"] and
|
||||
// e.g. -2^31 = "-2147483648"
|
||||
exists(float typeBasedBound, float valueBasedBound |
|
||||
// The first case handles length sub-specifiers
|
||||
// Subtract one in the exponent because one bit is for the sign.
|
||||
// Add 1 to account for the possible sign in the output.
|
||||
typeBasedBound =
|
||||
1 + lengthInBase10(2.pow(this.getIntegralDisplayType(n).getSize() * 8 - 1)) and
|
||||
// The second case uses range analysis to deduce a length that's shorter than the length
|
||||
// of the number -2^31.
|
||||
exists(Expr arg, float lower, float upper, float typeLower, float typeUpper |
|
||||
arg = this.getUse().getConversionArgument(n) and
|
||||
lower = lowerBound(arg.getFullyConverted()) and
|
||||
upper = upperBound(arg.getFullyConverted()) and
|
||||
typeLower = exprMinVal(arg.getFullyConverted()) and
|
||||
typeUpper = exprMaxVal(arg.getFullyConverted())
|
||||
|
|
||||
valueBasedBound =
|
||||
max(int cand |
|
||||
// Include the sign bit in the length if it can be negative
|
||||
(
|
||||
if lower < 0
|
||||
then cand = 1 + lengthInBase10(lower.abs())
|
||||
else cand = lengthInBase10(lower)
|
||||
len =
|
||||
min(float cand |
|
||||
// The first case handles length sub-specifiers
|
||||
// Subtract one in the exponent because one bit is for the sign.
|
||||
// Add 1 to account for the possible sign in the output.
|
||||
cand = 1 + lengthInBase10(2.pow(this.getIntegralDisplayType(n).getSize() * 8 - 1))
|
||||
or
|
||||
// The second case uses range analysis to deduce a length that's shorter than the length
|
||||
// of the number -2^31.
|
||||
exists(Expr arg, float lower, float upper |
|
||||
arg = this.getUse().getConversionArgument(n) and
|
||||
lower = lowerBound(arg.getFullyConverted()) and
|
||||
upper = upperBound(arg.getFullyConverted())
|
||||
|
|
||||
cand =
|
||||
max(int cand0 |
|
||||
// Include the sign bit in the length if it can be negative
|
||||
(
|
||||
if lower < 0
|
||||
then cand0 = 1 + lengthInBase10(lower.abs())
|
||||
else cand0 = lengthInBase10(lower)
|
||||
)
|
||||
or
|
||||
(
|
||||
if upper < 0
|
||||
then cand0 = 1 + lengthInBase10(upper.abs())
|
||||
else cand0 = lengthInBase10(upper)
|
||||
)
|
||||
)
|
||||
or
|
||||
(
|
||||
if upper < 0
|
||||
then cand = 1 + lengthInBase10(upper.abs())
|
||||
else cand = lengthInBase10(upper)
|
||||
)
|
||||
) and
|
||||
(
|
||||
if lower > typeLower or upper < typeUpper
|
||||
then reason = TValueFlowAnalysis()
|
||||
else reason = TTypeBoundsAnalysis()
|
||||
)
|
||||
) and
|
||||
len = valueBasedBound.minimum(typeBasedBound)
|
||||
)
|
||||
)
|
||||
or
|
||||
this.getConversionChar(n).toLowerCase() = "u" and
|
||||
// e.g. 2^32 - 1 = "4294967295"
|
||||
exists(float typeBasedBound, float valueBasedBound |
|
||||
// The first case handles length sub-specifiers
|
||||
typeBasedBound = lengthInBase10(2.pow(this.getIntegralDisplayType(n).getSize() * 8) - 1) and
|
||||
// The second case uses range analysis to deduce a length that's shorter than
|
||||
// the length of the number 2^31 - 1.
|
||||
exists(Expr arg, float lower, float upper, float typeLower, float typeUpper |
|
||||
arg = this.getUse().getConversionArgument(n) and
|
||||
lower = lowerBound(arg.getFullyConverted()) and
|
||||
upper = upperBound(arg.getFullyConverted()) and
|
||||
typeLower = exprMinVal(arg.getFullyConverted()) and
|
||||
typeUpper = exprMaxVal(arg.getFullyConverted())
|
||||
|
|
||||
valueBasedBound =
|
||||
lengthInBase10(max(float cand |
|
||||
len =
|
||||
min(float cand |
|
||||
// The first case handles length sub-specifiers
|
||||
cand = 2.pow(this.getIntegralDisplayType(n).getSize() * 8)
|
||||
or
|
||||
// The second case uses range analysis to deduce a length that's shorter than
|
||||
// the length of the number 2^31 - 1.
|
||||
exists(Expr arg, float lower |
|
||||
arg = this.getUse().getConversionArgument(n) and
|
||||
lower = lowerBound(arg.getFullyConverted())
|
||||
|
|
||||
cand =
|
||||
max(float cand0 |
|
||||
// If lower can be negative we use `(unsigned)-1` as the candidate value.
|
||||
lower < 0 and
|
||||
cand = 2.pow(any(IntType t | t.isUnsigned()).getSize() * 8)
|
||||
cand0 = 2.pow(any(IntType t | t.isUnsigned()).getSize() * 8)
|
||||
or
|
||||
cand = upper
|
||||
)) and
|
||||
(
|
||||
if lower > typeLower or upper < typeUpper
|
||||
then reason = TValueFlowAnalysis()
|
||||
else reason = TTypeBoundsAnalysis()
|
||||
cand0 = upperBound(arg.getFullyConverted())
|
||||
)
|
||||
)
|
||||
) and
|
||||
len = valueBasedBound.minimum(typeBasedBound)
|
||||
)
|
||||
|
|
||||
lengthInBase10(cand)
|
||||
)
|
||||
or
|
||||
this.getConversionChar(n).toLowerCase() = "x" and
|
||||
// e.g. "12345678"
|
||||
@@ -1236,8 +1135,7 @@ class FormatLiteral extends Literal {
|
||||
(
|
||||
if this.hasAlternateFlag(n) then len = 2 + baseLen else len = baseLen // "0x"
|
||||
)
|
||||
) and
|
||||
reason = TTypeBoundsAnalysis()
|
||||
)
|
||||
or
|
||||
this.getConversionChar(n).toLowerCase() = "p" and
|
||||
exists(PointerType ptrType, int baseLen |
|
||||
@@ -1246,8 +1144,7 @@ class FormatLiteral extends Literal {
|
||||
(
|
||||
if this.hasAlternateFlag(n) then len = 2 + baseLen else len = baseLen // "0x"
|
||||
)
|
||||
) and
|
||||
reason = TValueFlowAnalysis()
|
||||
)
|
||||
or
|
||||
this.getConversionChar(n).toLowerCase() = "o" and
|
||||
// e.g. 2^32 - 1 = "37777777777"
|
||||
@@ -1266,16 +1163,14 @@ class FormatLiteral extends Literal {
|
||||
(
|
||||
if this.hasAlternateFlag(n) then len = 1 + baseLen else len = baseLen // "0"
|
||||
)
|
||||
) and
|
||||
reason = TTypeBoundsAnalysis()
|
||||
)
|
||||
or
|
||||
this.getConversionChar(n).toLowerCase() = "s" and
|
||||
len =
|
||||
min(int v |
|
||||
v = this.getPrecision(n) or
|
||||
v = this.getUse().getFormatArgument(n).(AnalysedString).getMaxLength() - 1 // (don't count null terminator)
|
||||
) and
|
||||
reason = TValueFlowAnalysis()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1287,19 +1182,10 @@ class FormatLiteral extends Literal {
|
||||
* determining whether a buffer overflow is caused by long float to string
|
||||
* conversions.
|
||||
*/
|
||||
int getMaxConvertedLengthLimited(int n) { result = max(getMaxConvertedLengthLimited(n, _)) }
|
||||
|
||||
/**
|
||||
* Gets the maximum length of the string that can be produced by the nth
|
||||
* conversion specifier of this format string, specifying the reason for the
|
||||
* estimation, except that float to string conversions are assumed to be 8
|
||||
* characters. This is helpful for determining whether a buffer overflow is
|
||||
* caused by long float to string conversions.
|
||||
*/
|
||||
int getMaxConvertedLengthLimited(int n, BufferWriteEstimationReason reason) {
|
||||
int getMaxConvertedLengthLimited(int n) {
|
||||
if this.getConversionChar(n).toLowerCase() = "f"
|
||||
then result = this.getMaxConvertedLength(n, reason).minimum(8)
|
||||
else result = this.getMaxConvertedLength(n, reason)
|
||||
then result = this.getMaxConvertedLength(n).minimum(8)
|
||||
else result = this.getMaxConvertedLength(n)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1339,35 +1225,29 @@ class FormatLiteral extends Literal {
|
||||
)
|
||||
}
|
||||
|
||||
private int getMaxConvertedLengthAfter(int n, BufferWriteEstimationReason reason) {
|
||||
private int getMaxConvertedLengthAfter(int n) {
|
||||
if n = this.getNumConvSpec()
|
||||
then result = this.getConstantSuffix().length() + 1 and reason = TValueFlowAnalysis()
|
||||
then result = this.getConstantSuffix().length() + 1
|
||||
else
|
||||
exists(BufferWriteEstimationReason headReason, BufferWriteEstimationReason tailReason |
|
||||
result =
|
||||
this.getConstantPart(n).length() + this.getMaxConvertedLength(n, headReason) +
|
||||
this.getMaxConvertedLengthAfter(n + 1, tailReason) and
|
||||
reason = headReason.combineWith(tailReason)
|
||||
)
|
||||
result =
|
||||
this.getConstantPart(n).length() + this.getMaxConvertedLength(n) +
|
||||
this.getMaxConvertedLengthAfter(n + 1)
|
||||
}
|
||||
|
||||
private int getMaxConvertedLengthAfterLimited(int n, BufferWriteEstimationReason reason) {
|
||||
private int getMaxConvertedLengthAfterLimited(int n) {
|
||||
if n = this.getNumConvSpec()
|
||||
then result = this.getConstantSuffix().length() + 1 and reason = TValueFlowAnalysis()
|
||||
then result = this.getConstantSuffix().length() + 1
|
||||
else
|
||||
exists(BufferWriteEstimationReason headReason, BufferWriteEstimationReason tailReason |
|
||||
result =
|
||||
this.getConstantPart(n).length() + this.getMaxConvertedLengthLimited(n, headReason) +
|
||||
this.getMaxConvertedLengthAfterLimited(n + 1, tailReason) and
|
||||
reason = headReason.combineWith(tailReason)
|
||||
)
|
||||
result =
|
||||
this.getConstantPart(n).length() + this.getMaxConvertedLengthLimited(n) +
|
||||
this.getMaxConvertedLengthAfterLimited(n + 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum length of the string that can be produced by this format
|
||||
* string. Has no result if this cannot be determined.
|
||||
*/
|
||||
int getMaxConvertedLength() { result = this.getMaxConvertedLengthAfter(0, _) }
|
||||
int getMaxConvertedLength() { result = this.getMaxConvertedLengthAfter(0) }
|
||||
|
||||
/**
|
||||
* Gets the maximum length of the string that can be produced by this format
|
||||
@@ -1375,24 +1255,5 @@ class FormatLiteral extends Literal {
|
||||
* characters. This is helpful for determining whether a buffer overflow
|
||||
* is caused by long float to string conversions.
|
||||
*/
|
||||
int getMaxConvertedLengthLimited() { result = this.getMaxConvertedLengthAfterLimited(0, _) }
|
||||
|
||||
/**
|
||||
* Gets the maximum length of the string that can be produced by this format
|
||||
* string, specifying the reason for the estimate. Has no result if no estimate
|
||||
* can be found.
|
||||
*/
|
||||
int getMaxConvertedLengthWithReason(BufferWriteEstimationReason reason) {
|
||||
result = this.getMaxConvertedLengthAfter(0, reason)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum length of the string that can be produced by this format
|
||||
* string, specifying the reason for the estimate, except that float to string
|
||||
* conversions are assumed to be 8 characters. This is helpful for determining
|
||||
* whether a buffer overflow is caused by long float to string conversions.
|
||||
*/
|
||||
int getMaxConvertedLengthLimitedWithReason(BufferWriteEstimationReason reason) {
|
||||
result = this.getMaxConvertedLengthAfterLimited(0, reason)
|
||||
}
|
||||
int getMaxConvertedLengthLimited() { result = this.getMaxConvertedLengthAfterLimited(0) }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.dataflow.internal.DataFlowUtil
|
||||
|
||||
/**
|
||||
* Gets a function that might be called by `call`.
|
||||
@@ -65,17 +63,3 @@ predicate mayBenefitFromCallContext(Call call, Function f) { none() }
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
*/
|
||||
Function viableImplInCallContext(Call call, Call ctx) { none() }
|
||||
|
||||
/** A parameter position represented by an integer. */
|
||||
class ParameterPosition extends int {
|
||||
ParameterPosition() { any(ParameterNode p).isParameterOf(_, this) }
|
||||
}
|
||||
|
||||
/** An argument position represented by an integer. */
|
||||
class ArgumentPosition extends int {
|
||||
ArgumentPosition() { any(ArgumentNode a).argumentOf(_, this) }
|
||||
}
|
||||
|
||||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
pragma[inline]
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1447,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2142,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2908,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2992,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3639,40 +3639,39 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, pos)
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3687,9 +3686,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3713,7 +3712,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4442,25 +4441,24 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4469,9 +4467,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4635,23 +4633,22 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = ppos and
|
||||
p.getPosition() = pos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4664,7 +4661,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1447,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2142,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2908,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2992,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3639,40 +3639,39 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, pos)
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3687,9 +3686,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3713,7 +3712,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4442,25 +4441,24 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4469,9 +4467,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4635,23 +4633,22 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = ppos and
|
||||
p.getPosition() = pos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4664,7 +4661,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1447,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2142,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2908,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2992,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3639,40 +3639,39 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, pos)
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3687,9 +3686,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3713,7 +3712,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4442,25 +4441,24 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4469,9 +4467,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4635,23 +4633,22 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = ppos and
|
||||
p.getPosition() = pos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4664,7 +4661,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1447,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2142,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2908,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2992,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3639,40 +3639,39 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, pos)
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3687,9 +3686,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3713,7 +3712,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4442,25 +4441,24 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4469,9 +4467,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4635,23 +4633,22 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = ppos and
|
||||
p.getPosition() = pos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4664,7 +4661,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -62,18 +62,6 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
||||
tupleLimit = 1000
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `arg` is an argument of `call` with an argument position that matches
|
||||
* parameter position `ppos`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate argumentPositionMatch(DataFlowCall call, ArgNode arg, ParameterPosition ppos) {
|
||||
exists(ArgumentPosition apos |
|
||||
arg.argumentOf(call, apos) and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
|
||||
* currently excludes read-steps, store-steps, and flow-through.
|
||||
@@ -83,27 +71,25 @@ predicate argumentPositionMatch(DataFlowCall call, ArgNode arg, ParameterPositio
|
||||
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
|
||||
*/
|
||||
private module LambdaFlow {
|
||||
pragma[noinline]
|
||||
private predicate viableParamNonLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||
p.isParameterOf(viableCallable(call), ppos)
|
||||
private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate viableParamLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), ppos)
|
||||
private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), i)
|
||||
}
|
||||
|
||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParamNonLambda(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos)
|
||||
exists(int i |
|
||||
viableParamNonLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParamLambda(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos)
|
||||
exists(int i |
|
||||
viableParamLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -336,7 +322,7 @@ private module Cached {
|
||||
or
|
||||
exists(ArgNode arg |
|
||||
result.(PostUpdateNode).getPreUpdateNode() = arg and
|
||||
arg.argumentOf(call, k.(ParamUpdateReturnKind).getAMatchingArgumentPosition())
|
||||
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -344,7 +330,7 @@ private module Cached {
|
||||
predicate returnNodeExt(Node n, ReturnKindExt k) {
|
||||
k = TValueReturn(n.(ReturnNode).getKind())
|
||||
or
|
||||
exists(ParamNode p, ParameterPosition pos |
|
||||
exists(ParamNode p, int pos |
|
||||
parameterValueFlowsToPreUpdate(p, n) and
|
||||
p.isParameterOf(_, pos) and
|
||||
k = TParamUpdate(pos)
|
||||
@@ -366,13 +352,11 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate parameterNode(Node p, DataFlowCallable c, ParameterPosition pos) {
|
||||
isParameterNode(p, c, pos)
|
||||
}
|
||||
predicate parameterNode(Node p, DataFlowCallable c, int pos) { isParameterNode(p, c, pos) }
|
||||
|
||||
cached
|
||||
predicate argumentNode(Node n, DataFlowCall call, ArgumentPosition pos) {
|
||||
isArgumentNode(n, call, pos)
|
||||
predicate argumentNode(Node n, DataFlowCall call, int pos) {
|
||||
n.(ArgumentNode).argumentOf(call, pos)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -390,12 +374,12 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p` is the parameter of a viable dispatch target of `call`,
|
||||
* and `p` has position `ppos`.
|
||||
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
|
||||
* The instance parameter is considered to have index `-1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate viableParam(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||
p.isParameterOf(viableCallableExt(call), ppos)
|
||||
private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallableExt(call), i)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -404,9 +388,9 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParam(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
exists(int i |
|
||||
viableParam(call, i, p) and
|
||||
arg.argumentOf(call, i) and
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
)
|
||||
}
|
||||
@@ -878,7 +862,7 @@ private module Cached {
|
||||
cached
|
||||
newtype TReturnKindExt =
|
||||
TValueReturn(ReturnKind kind) or
|
||||
TParamUpdate(ParameterPosition pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
||||
TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
||||
|
||||
cached
|
||||
newtype TBooleanOption =
|
||||
@@ -1070,9 +1054,9 @@ class ParamNode extends Node {
|
||||
|
||||
/**
|
||||
* Holds if this node is the parameter of callable `c` at the specified
|
||||
* position.
|
||||
* (zero-based) position.
|
||||
*/
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { parameterNode(this, c, pos) }
|
||||
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
|
||||
}
|
||||
|
||||
/** A data-flow node that represents a call argument. */
|
||||
@@ -1080,9 +1064,7 @@ class ArgNode extends Node {
|
||||
ArgNode() { argumentNode(this, _, _) }
|
||||
|
||||
/** Holds if this argument occurs at the given position in the given call. */
|
||||
final predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
argumentNode(this, call, pos)
|
||||
}
|
||||
final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1128,14 +1110,11 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
|
||||
}
|
||||
|
||||
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
|
||||
private ParameterPosition pos;
|
||||
private int pos;
|
||||
|
||||
ParamUpdateReturnKind() { this = TParamUpdate(pos) }
|
||||
|
||||
ParameterPosition getPosition() { result = pos }
|
||||
|
||||
pragma[nomagic]
|
||||
ArgumentPosition getAMatchingArgumentPosition() { parameterMatch(pos, result) }
|
||||
int getPosition() { result = pos }
|
||||
|
||||
override string toString() { result = "param update " + pos }
|
||||
}
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1447,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2142,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2908,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2992,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3639,40 +3639,39 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, pos)
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3687,9 +3686,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3713,7 +3712,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4442,25 +4441,24 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4469,9 +4467,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4635,23 +4633,22 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = ppos and
|
||||
p.getPosition() = pos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4664,7 +4661,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -8,14 +8,7 @@ private import DataFlowImplConsistency
|
||||
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
|
||||
|
||||
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
|
||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
|
||||
p.isParameterOf(c, pos)
|
||||
}
|
||||
|
||||
/** Holds if `arg` is an `ArgumentNode` of `c` with position `pos`. */
|
||||
predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) {
|
||||
arg.argumentOf(c, pos)
|
||||
}
|
||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) { p.isParameterOf(c, pos) }
|
||||
|
||||
/** Gets the instance argument of a non-static call. */
|
||||
private Node getInstanceArgument(Call call) {
|
||||
|
||||
@@ -2,7 +2,6 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
|
||||
/**
|
||||
@@ -267,17 +266,3 @@ Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) {
|
||||
result = ctx.getArgument(i).getUnconvertedResultExpression().(FunctionAccess).getTarget()
|
||||
)
|
||||
}
|
||||
|
||||
/** A parameter position represented by an integer. */
|
||||
class ParameterPosition extends int {
|
||||
ParameterPosition() { any(ParameterNode p).isParameterOf(_, this) }
|
||||
}
|
||||
|
||||
/** An argument position represented by an integer. */
|
||||
class ArgumentPosition extends int {
|
||||
ArgumentPosition() { any(ArgumentNode a).argumentOf(_, this) }
|
||||
}
|
||||
|
||||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
pragma[inline]
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1447,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2142,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2908,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2992,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3639,40 +3639,39 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, pos)
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3687,9 +3686,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3713,7 +3712,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4442,25 +4441,24 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4469,9 +4467,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4635,23 +4633,22 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = ppos and
|
||||
p.getPosition() = pos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4664,7 +4661,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1447,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2142,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2908,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2992,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3639,40 +3639,39 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, pos)
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3687,9 +3686,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3713,7 +3712,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4442,25 +4441,24 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4469,9 +4467,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4635,23 +4633,22 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = ppos and
|
||||
p.getPosition() = pos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4664,7 +4661,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1447,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2142,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2908,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2992,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3639,40 +3639,39 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, pos)
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3687,9 +3686,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3713,7 +3712,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4442,25 +4441,24 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4469,9 +4467,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4635,23 +4633,22 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = ppos and
|
||||
p.getPosition() = pos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4664,7 +4661,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1447,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2142,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2908,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2992,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3639,40 +3639,39 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, pos)
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3687,9 +3686,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3713,7 +3712,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4442,25 +4441,24 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4469,9 +4467,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4635,23 +4633,22 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = ppos and
|
||||
p.getPosition() = pos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4664,7 +4661,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -62,18 +62,6 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
||||
tupleLimit = 1000
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `arg` is an argument of `call` with an argument position that matches
|
||||
* parameter position `ppos`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate argumentPositionMatch(DataFlowCall call, ArgNode arg, ParameterPosition ppos) {
|
||||
exists(ArgumentPosition apos |
|
||||
arg.argumentOf(call, apos) and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
|
||||
* currently excludes read-steps, store-steps, and flow-through.
|
||||
@@ -83,27 +71,25 @@ predicate argumentPositionMatch(DataFlowCall call, ArgNode arg, ParameterPositio
|
||||
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
|
||||
*/
|
||||
private module LambdaFlow {
|
||||
pragma[noinline]
|
||||
private predicate viableParamNonLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||
p.isParameterOf(viableCallable(call), ppos)
|
||||
private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate viableParamLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), ppos)
|
||||
private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), i)
|
||||
}
|
||||
|
||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParamNonLambda(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos)
|
||||
exists(int i |
|
||||
viableParamNonLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParamLambda(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos)
|
||||
exists(int i |
|
||||
viableParamLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -336,7 +322,7 @@ private module Cached {
|
||||
or
|
||||
exists(ArgNode arg |
|
||||
result.(PostUpdateNode).getPreUpdateNode() = arg and
|
||||
arg.argumentOf(call, k.(ParamUpdateReturnKind).getAMatchingArgumentPosition())
|
||||
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -344,7 +330,7 @@ private module Cached {
|
||||
predicate returnNodeExt(Node n, ReturnKindExt k) {
|
||||
k = TValueReturn(n.(ReturnNode).getKind())
|
||||
or
|
||||
exists(ParamNode p, ParameterPosition pos |
|
||||
exists(ParamNode p, int pos |
|
||||
parameterValueFlowsToPreUpdate(p, n) and
|
||||
p.isParameterOf(_, pos) and
|
||||
k = TParamUpdate(pos)
|
||||
@@ -366,13 +352,11 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate parameterNode(Node p, DataFlowCallable c, ParameterPosition pos) {
|
||||
isParameterNode(p, c, pos)
|
||||
}
|
||||
predicate parameterNode(Node p, DataFlowCallable c, int pos) { isParameterNode(p, c, pos) }
|
||||
|
||||
cached
|
||||
predicate argumentNode(Node n, DataFlowCall call, ArgumentPosition pos) {
|
||||
isArgumentNode(n, call, pos)
|
||||
predicate argumentNode(Node n, DataFlowCall call, int pos) {
|
||||
n.(ArgumentNode).argumentOf(call, pos)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -390,12 +374,12 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p` is the parameter of a viable dispatch target of `call`,
|
||||
* and `p` has position `ppos`.
|
||||
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
|
||||
* The instance parameter is considered to have index `-1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate viableParam(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||
p.isParameterOf(viableCallableExt(call), ppos)
|
||||
private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallableExt(call), i)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -404,9 +388,9 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParam(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
exists(int i |
|
||||
viableParam(call, i, p) and
|
||||
arg.argumentOf(call, i) and
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
)
|
||||
}
|
||||
@@ -878,7 +862,7 @@ private module Cached {
|
||||
cached
|
||||
newtype TReturnKindExt =
|
||||
TValueReturn(ReturnKind kind) or
|
||||
TParamUpdate(ParameterPosition pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
||||
TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
||||
|
||||
cached
|
||||
newtype TBooleanOption =
|
||||
@@ -1070,9 +1054,9 @@ class ParamNode extends Node {
|
||||
|
||||
/**
|
||||
* Holds if this node is the parameter of callable `c` at the specified
|
||||
* position.
|
||||
* (zero-based) position.
|
||||
*/
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { parameterNode(this, c, pos) }
|
||||
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
|
||||
}
|
||||
|
||||
/** A data-flow node that represents a call argument. */
|
||||
@@ -1080,9 +1064,7 @@ class ArgNode extends Node {
|
||||
ArgNode() { argumentNode(this, _, _) }
|
||||
|
||||
/** Holds if this argument occurs at the given position in the given call. */
|
||||
final predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
argumentNode(this, call, pos)
|
||||
}
|
||||
final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1128,14 +1110,11 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
|
||||
}
|
||||
|
||||
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
|
||||
private ParameterPosition pos;
|
||||
private int pos;
|
||||
|
||||
ParamUpdateReturnKind() { this = TParamUpdate(pos) }
|
||||
|
||||
ParameterPosition getPosition() { result = pos }
|
||||
|
||||
pragma[nomagic]
|
||||
ArgumentPosition getAMatchingArgumentPosition() { parameterMatch(pos, result) }
|
||||
int getPosition() { result = pos }
|
||||
|
||||
override string toString() { result = "param update " + pos }
|
||||
}
|
||||
|
||||
@@ -8,14 +8,7 @@ private import DataFlowImplConsistency
|
||||
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
|
||||
|
||||
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
|
||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
|
||||
p.isParameterOf(c, pos)
|
||||
}
|
||||
|
||||
/** Holds if `arg` is an `ArgumentNode` of `c` with position `pos`. */
|
||||
predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) {
|
||||
arg.argumentOf(c, pos)
|
||||
}
|
||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) { p.isParameterOf(c, pos) }
|
||||
|
||||
/**
|
||||
* A data flow node that occurs as the argument of a call and is passed as-is
|
||||
|
||||
@@ -71,30 +71,13 @@ abstract class BufferWrite extends Expr {
|
||||
*/
|
||||
int getMaxData() { none() }
|
||||
|
||||
/**
|
||||
* Gets an upper bound to the amount of data that's being written (if one
|
||||
* can be found), specifying the reason for the estimation.
|
||||
*/
|
||||
int getMaxData(BufferWriteEstimationReason reason) {
|
||||
reason instanceof NoSpecifiedEstimateReason and result = getMaxData()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an upper bound to the amount of data that's being written (if one
|
||||
* can be found), except that float to string conversions are assumed to be
|
||||
* much smaller (8 bytes) than their true maximum length. This can be
|
||||
* helpful in determining the cause of a buffer overflow issue.
|
||||
*/
|
||||
int getMaxDataLimited() { result = getMaxData() }
|
||||
|
||||
/**
|
||||
* Gets an upper bound to the amount of data that's being written (if one
|
||||
* can be found), specifying the reason for the estimation, except that
|
||||
* float to string conversions are assumed to be much smaller (8 bytes)
|
||||
* than their true maximum length. This can be helpful in determining the
|
||||
* cause of a buffer overflow issue.
|
||||
*/
|
||||
int getMaxDataLimited(BufferWriteEstimationReason reason) { result = getMaxData(reason) }
|
||||
int getMaxDataLimited() { result = this.getMaxData() }
|
||||
|
||||
/**
|
||||
* Gets the size of a single character of the type this
|
||||
@@ -152,16 +135,10 @@ class StrCopyBW extends BufferWriteCall {
|
||||
result = this.getArgument(this.getParamSize()).getValue().toInt() * this.getCharSize()
|
||||
}
|
||||
|
||||
private int getMaxDataImpl(BufferWriteEstimationReason reason) {
|
||||
// when result exists, it is an exact flow analysis
|
||||
reason instanceof ValueFlowAnalysis and
|
||||
override int getMaxData() {
|
||||
result =
|
||||
this.getArgument(this.getParamSrc()).(AnalysedString).getMaxLength() * this.getCharSize()
|
||||
}
|
||||
|
||||
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
|
||||
|
||||
override int getMaxData() { result = max(getMaxDataImpl(_)) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,16 +173,10 @@ class StrCatBW extends BufferWriteCall {
|
||||
result = this.getArgument(this.getParamSize()).getValue().toInt() * this.getCharSize()
|
||||
}
|
||||
|
||||
private int getMaxDataImpl(BufferWriteEstimationReason reason) {
|
||||
// when result exists, it is an exact flow analysis
|
||||
reason instanceof ValueFlowAnalysis and
|
||||
override int getMaxData() {
|
||||
result =
|
||||
this.getArgument(this.getParamSrc()).(AnalysedString).getMaxLength() * this.getCharSize()
|
||||
}
|
||||
|
||||
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
|
||||
|
||||
override int getMaxData() { result = max(getMaxDataImpl(_)) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,29 +233,19 @@ class SprintfBW extends BufferWriteCall {
|
||||
|
||||
override Expr getDest() { result = this.getArgument(f.getOutputParameterIndex(false)) }
|
||||
|
||||
private int getMaxDataImpl(BufferWriteEstimationReason reason) {
|
||||
override int getMaxData() {
|
||||
exists(FormatLiteral fl |
|
||||
fl = this.(FormattingFunctionCall).getFormat() and
|
||||
result = fl.getMaxConvertedLengthWithReason(reason) * this.getCharSize()
|
||||
result = fl.getMaxConvertedLength() * this.getCharSize()
|
||||
)
|
||||
}
|
||||
|
||||
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
|
||||
|
||||
override int getMaxData() { result = max(getMaxDataImpl(_)) }
|
||||
|
||||
private int getMaxDataLimitedImpl(BufferWriteEstimationReason reason) {
|
||||
override int getMaxDataLimited() {
|
||||
exists(FormatLiteral fl |
|
||||
fl = this.(FormattingFunctionCall).getFormat() and
|
||||
result = fl.getMaxConvertedLengthLimitedWithReason(reason) * this.getCharSize()
|
||||
result = fl.getMaxConvertedLengthLimited() * this.getCharSize()
|
||||
)
|
||||
}
|
||||
|
||||
override int getMaxDataLimited(BufferWriteEstimationReason reason) {
|
||||
result = getMaxDataLimitedImpl(reason)
|
||||
}
|
||||
|
||||
override int getMaxDataLimited() { result = max(getMaxDataLimitedImpl(_)) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -375,29 +336,19 @@ class SnprintfBW extends BufferWriteCall {
|
||||
result = this.getArgument(this.getParamSize()).getValue().toInt() * this.getCharSize()
|
||||
}
|
||||
|
||||
private int getMaxDataImpl(BufferWriteEstimationReason reason) {
|
||||
override int getMaxData() {
|
||||
exists(FormatLiteral fl |
|
||||
fl = this.(FormattingFunctionCall).getFormat() and
|
||||
result = fl.getMaxConvertedLengthWithReason(reason) * this.getCharSize()
|
||||
result = fl.getMaxConvertedLength() * this.getCharSize()
|
||||
)
|
||||
}
|
||||
|
||||
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
|
||||
|
||||
override int getMaxData() { result = max(getMaxDataImpl(_)) }
|
||||
|
||||
private int getMaxDataLimitedImpl(BufferWriteEstimationReason reason) {
|
||||
override int getMaxDataLimited() {
|
||||
exists(FormatLiteral fl |
|
||||
fl = this.(FormattingFunctionCall).getFormat() and
|
||||
result = fl.getMaxConvertedLengthLimitedWithReason(reason) * this.getCharSize()
|
||||
result = fl.getMaxConvertedLengthLimited() * this.getCharSize()
|
||||
)
|
||||
}
|
||||
|
||||
override int getMaxDataLimited(BufferWriteEstimationReason reason) {
|
||||
result = getMaxDataLimitedImpl(reason)
|
||||
}
|
||||
|
||||
override int getMaxDataLimited() { result = max(getMaxDataLimitedImpl(_)) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -485,9 +436,7 @@ class ScanfBW extends BufferWrite {
|
||||
|
||||
override Expr getDest() { result = this }
|
||||
|
||||
private int getMaxDataImpl(BufferWriteEstimationReason reason) {
|
||||
// when this returns, it is based on exact flow analysis
|
||||
reason instanceof ValueFlowAnalysis and
|
||||
override int getMaxData() {
|
||||
exists(ScanfFunctionCall fc, ScanfFormatLiteral fl, int arg |
|
||||
this = fc.getArgument(arg) and
|
||||
fl = fc.getFormat() and
|
||||
@@ -495,10 +444,6 @@ class ScanfBW extends BufferWrite {
|
||||
)
|
||||
}
|
||||
|
||||
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
|
||||
|
||||
override int getMaxData() { result = max(getMaxDataImpl(_)) }
|
||||
|
||||
override string getBWDesc() {
|
||||
exists(FunctionCall fc |
|
||||
this = fc.getArgument(_) and
|
||||
@@ -529,14 +474,8 @@ class RealpathBW extends BufferWriteCall {
|
||||
|
||||
override Expr getASource() { result = this.getArgument(0) }
|
||||
|
||||
private int getMaxDataImpl(BufferWriteEstimationReason reason) {
|
||||
// although there may be some unknown invariants guaranteeing that a real path is shorter than PATH_MAX, we can consider providing less than PATH_MAX a problem with high precision
|
||||
reason instanceof ValueFlowAnalysis and
|
||||
override int getMaxData() {
|
||||
result = path_max() and
|
||||
this = this // Suppress a compiler warning
|
||||
}
|
||||
|
||||
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
|
||||
|
||||
override int getMaxData() { result = max(getMaxDataImpl(_)) }
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
## 0.0.4
|
||||
|
||||
### New Queries
|
||||
|
||||
* A new query `cpp/non-https-url` has been added for C/C++. The query flags uses of `http` URLs that might be better replaced with `https`.
|
||||
@@ -85,8 +85,7 @@ private predicate cancelingSubExprs(ComparisonOperation cmp, VariableAccess a1,
|
||||
exists(Variable v |
|
||||
exists(float m | m < 0 and cmpLinearSubVariable(cmp, v, a1, m)) and
|
||||
exists(float m | m > 0 and cmpLinearSubVariable(cmp, v, a2, m))
|
||||
) and
|
||||
not any(ClassTemplateInstantiation inst).getATemplateArgument() = cmp.getParent*()
|
||||
)
|
||||
}
|
||||
|
||||
from ComparisonOperation cmp, VariableAccess a1, VariableAccess a2
|
||||
|
||||
@@ -29,9 +29,7 @@ predicate pointlessSelfComparison(ComparisonOperation cmp) {
|
||||
not exists(lhs.getQualifier()) and // Avoid structure fields
|
||||
not exists(rhs.getQualifier()) and // Avoid structure fields
|
||||
not convertedExprMightOverflow(lhs) and
|
||||
not convertedExprMightOverflow(rhs) and
|
||||
// Don't warn if the comparison is part of a template argument.
|
||||
not any(ClassTemplateInstantiation inst).getATemplateArgument() = cmp.getParent*()
|
||||
not convertedExprMightOverflow(rhs)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -21,15 +21,14 @@ import semmle.code.cpp.commons.Alloc
|
||||
* See CWE-120/UnboundedWrite.ql for a summary of CWE-120 alert cases.
|
||||
*/
|
||||
|
||||
from BufferWrite bw, Expr dest, int destSize, int estimated
|
||||
from BufferWrite bw, Expr dest, int destSize
|
||||
where
|
||||
not bw.hasExplicitLimit() and // has no explicit size limit
|
||||
dest = bw.getDest() and
|
||||
destSize = getBufferSize(dest, _) and
|
||||
estimated = bw.getMaxDataLimited(_) and
|
||||
// we can deduce that too much data may be copied (even without
|
||||
// long '%f' conversions)
|
||||
estimated > destSize
|
||||
bw.getMaxDataLimited() > destSize
|
||||
select bw,
|
||||
"This '" + bw.getBWDesc() + "' operation requires " + estimated +
|
||||
"This '" + bw.getBWDesc() + "' operation requires " + bw.getMaxData() +
|
||||
" bytes but the destination is only " + destSize + " bytes."
|
||||
|
||||
@@ -21,15 +21,14 @@ import semmle.code.cpp.security.BufferWrite
|
||||
* See CWE-120/UnboundedWrite.ql for a summary of CWE-120 alert cases.
|
||||
*/
|
||||
|
||||
from BufferWrite bw, int destSize, int estimated, BufferWriteEstimationReason reason
|
||||
from BufferWrite bw, int destSize
|
||||
where
|
||||
not bw.hasExplicitLimit() and
|
||||
// has no explicit size limit
|
||||
destSize = getBufferSize(bw.getDest(), _) and
|
||||
estimated = bw.getMaxData(reason) and
|
||||
estimated > destSize and
|
||||
bw.getMaxData() > destSize and
|
||||
// and we can deduce that too much data may be copied
|
||||
bw.getMaxDataLimited(reason) <= destSize // but it would fit without long '%f' conversions
|
||||
bw.getMaxDataLimited() <= destSize // but it would fit without long '%f' conversions
|
||||
select bw,
|
||||
"This '" + bw.getBWDesc() + "' operation may require " + estimated +
|
||||
"This '" + bw.getBWDesc() + "' operation may require " + bw.getMaxData() +
|
||||
" bytes because of float conversions, but the target is only " + destSize + " bytes."
|
||||
|
||||
@@ -44,7 +44,7 @@ import TaintedWithPath
|
||||
|
||||
predicate isUnboundedWrite(BufferWrite bw) {
|
||||
not bw.hasExplicitLimit() and // has no explicit size limit
|
||||
not exists(bw.getMaxData(_)) // and we can't deduce an upper bound to the amount copied
|
||||
not exists(bw.getMaxData()) // and we can't deduce an upper bound to the amount copied
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -28,11 +28,6 @@ class PrivateHostName extends string {
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate privateHostNameFlowsToExpr(Expr e) {
|
||||
TaintTracking::localExprTaint(any(StringLiteral p | p.getValue() instanceof PrivateHostName), e)
|
||||
}
|
||||
|
||||
/**
|
||||
* A string containing an HTTP URL not in a private domain.
|
||||
*/
|
||||
@@ -43,9 +38,11 @@ class HttpStringLiteral extends StringLiteral {
|
||||
or
|
||||
exists(string tail |
|
||||
tail = s.regexpCapture("http://(.*)", 1) and not tail instanceof PrivateHostName
|
||||
)
|
||||
) and
|
||||
not privateHostNameFlowsToExpr(this.getParent*())
|
||||
) and
|
||||
not TaintTracking::localExprTaint(any(StringLiteral p |
|
||||
p.getValue() instanceof PrivateHostName
|
||||
), this.getParent*())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
## 0.0.4
|
||||
|
||||
### New Queries
|
||||
|
||||
* A new query `cpp/non-https-url` has been added for C/C++. The query flags uses of `http` URLs that might be better replaced with `https`.
|
||||
@@ -1,2 +0,0 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.4
|
||||
@@ -1,6 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.0.5-dev
|
||||
groups: cpp
|
||||
version: 0.0.2
|
||||
dependencies:
|
||||
codeql/cpp-all: "*"
|
||||
codeql/suite-helpers: "*"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-tests
|
||||
groups: [cpp, test]
|
||||
version: 0.0.2
|
||||
dependencies:
|
||||
codeql/cpp-all: "*"
|
||||
codeql/cpp-queries: "*"
|
||||
|
||||
@@ -20,22 +20,3 @@ bool compareValues() {
|
||||
bool callCompareValues() {
|
||||
return compareValues<C1, C2> || compareValues<C1, C1>();
|
||||
}
|
||||
|
||||
template <bool C, typename T = void>
|
||||
struct enable_if {};
|
||||
|
||||
template <typename T>
|
||||
struct enable_if<true, T> { typedef T type; };
|
||||
|
||||
template<typename T1, typename T2>
|
||||
typename enable_if<T1::value <= T2::value, bool>::type constant_comparison() {
|
||||
return true;
|
||||
}
|
||||
|
||||
struct Value0 {
|
||||
const static int value = 0;
|
||||
};
|
||||
|
||||
void instantiation_with_pointless_comparison() {
|
||||
constant_comparison<Value0, Value0>(); // GOOD
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
# This directory has its own qlpack for reasons detailed in commit 2550788598010fa2117274607c9d58f64f997f34
|
||||
name: codeql/cpp-tests-cwe-190-tainted
|
||||
groups: [cpp, test]
|
||||
version: 0.0.2
|
||||
dependencies:
|
||||
codeql/cpp-all: "*"
|
||||
codeql/cpp-queries: "*"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
## 0.0.4
|
||||
@@ -1 +0,0 @@
|
||||
## 0.0.4
|
||||
@@ -1,2 +0,0 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.4
|
||||
@@ -1,5 +1,4 @@
|
||||
name: codeql/cpp-upgrades
|
||||
groups: cpp
|
||||
upgrades: .
|
||||
version: 0.0.5-dev
|
||||
version: 0.0.2
|
||||
library: true
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.FileSystem" Version="4.3.0"/>
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0"/>
|
||||
<PackageReference Include="xunit" Version="2.4.1"/>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Autobuild.CSharp\Semmle.Autobuild.CSharp.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Autobuild.CSharp\Semmle.Autobuild.CSharp.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,25 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Autobuild.CSharp</AssemblyName>
|
||||
<RootNamespace>Semmle.Autobuild.CSharp</RootNamespace>
|
||||
<ApplicationIcon/>
|
||||
<OutputType>Exe</OutputType>
|
||||
<StartupObject/>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="16.11.0"/>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\extractor\Semmle.Util\Semmle.Util.csproj"/>
|
||||
<ProjectReference Include="..\..\extractor\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Autobuild.CSharp</AssemblyName>
|
||||
<RootNamespace>Semmle.Autobuild.CSharp</RootNamespace>
|
||||
<ApplicationIcon />
|
||||
<OutputType>Exe</OutputType>
|
||||
<StartupObject />
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="16.9.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\extractor\Semmle.Util\Semmle.Util.csproj" />
|
||||
<ProjectReference Include="..\..\extractor\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Autobuild.Shared</AssemblyName>
|
||||
<RootNamespace>Semmle.Autobuild.Shared</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="16.11.0"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\extractor\Semmle.Util\Semmle.Util.csproj"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Autobuild.Shared</AssemblyName>
|
||||
<RootNamespace>Semmle.Autobuild.Shared</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="16.9.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\extractor\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package,sink,source,summary,sink:code,sink:html,sink:remote,sink:sql,sink:xss,source:local,summary:taint,summary:value
|
||||
Dapper,55,,,,,,55,,,,
|
||||
Microsoft.ApplicationBlocks.Data,28,,,,,,28,,,,
|
||||
MySql.Data.MySqlClient,48,,,,,,48,,,,
|
||||
Newtonsoft.Json,,,73,,,,,,,73,
|
||||
ServiceStack,194,,7,27,,75,92,,,7,
|
||||
System,28,3,1221,,4,,23,1,3,611,610
|
||||
package,sink,source,summary,sink:code,sink:html,sink:remote,sink:sql,sink:xss,source:local,summary:taint
|
||||
Dapper,55,,,,,,55,,,
|
||||
Microsoft.ApplicationBlocks.Data,28,,,,,,28,,,
|
||||
MySql.Data.MySqlClient,48,,,,,,48,,,
|
||||
ServiceStack,194,,7,27,,75,92,,,7
|
||||
System,28,3,25,,4,,23,1,3,25
|
||||
|
||||
|
@@ -8,7 +8,7 @@ C# framework & library support
|
||||
|
||||
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
|
||||
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
|
||||
System,"``System.*``, ``System``",3,1221,28,5
|
||||
Others,"``Dapper``, ``Microsoft.ApplicationBlocks.Data``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``",,73,131,
|
||||
Totals,,3,1301,353,5
|
||||
System,"``System.*``, ``System``",3,25,28,5
|
||||
Others,"``Dapper``, ``Microsoft.ApplicationBlocks.Data``, ``MySql.Data.MySqlClient``",,,131,
|
||||
Totals,,3,32,353,5
|
||||
|
||||
|
||||
@@ -26,9 +26,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.DiaSymReader" Version="1.3.0" />
|
||||
<PackageReference Include="Microsoft.DiaSymReader.Native" Version="1.7.0" />
|
||||
<PackageReference Include="Microsoft.DiaSymReader.PortablePdb" Version="1.6.0"><IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.DiaSymReader.PortablePdb" Version="1.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,28 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Extraction.CSharp.Standalone</AssemblyName>
|
||||
<RootNamespace>Semmle.Extraction.CSharp.Standalone</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors/>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="16.11.0"/>
|
||||
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0"/>
|
||||
<PackageReference Include="System.Net.Primitives" Version="4.3.1"/>
|
||||
<PackageReference Include="System.Security.Principal" Version="4.3.0"/>
|
||||
<PackageReference Include="System.Threading.ThreadPool" Version="4.3.0"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Extraction.CSharp.Standalone</AssemblyName>
|
||||
<RootNamespace>Semmle.Extraction.CSharp.Standalone</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="16.9.0" />
|
||||
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
|
||||
<PackageReference Include="System.Net.Primitives" Version="4.3.1" />
|
||||
<PackageReference Include="System.Security.Principal" Version="4.3.0" />
|
||||
<PackageReference Include="System.Threading.ThreadPool" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
private void VisitParameter(ParameterSyntax p)
|
||||
{
|
||||
var symbol = Context.GetModel(p).GetDeclaredSymbol(p)!;
|
||||
Context.CacheLambdaParameterSymbol(symbol, p);
|
||||
Parameter.Create(Context, symbol, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,17 +55,11 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
public static Parameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter? original = null)
|
||||
{
|
||||
var cachedSymbol = cx.GetPossiblyCachedParameterSymbol(param);
|
||||
return ParameterFactory.Instance.CreateEntity(cx, cachedSymbol, (cachedSymbol, parent, original));
|
||||
}
|
||||
public static Parameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter? original = null) =>
|
||||
ParameterFactory.Instance.CreateEntity(cx, param, (param, parent, original));
|
||||
|
||||
public static Parameter Create(Context cx, IParameterSymbol param)
|
||||
{
|
||||
var cachedSymbol = cx.GetPossiblyCachedParameterSymbol(param);
|
||||
return ParameterFactory.Instance.CreateEntity(cx, cachedSymbol, (cachedSymbol, null, null));
|
||||
}
|
||||
public static Parameter Create(Context cx, IParameterSymbol param) =>
|
||||
ParameterFactory.Instance.CreateEntity(cx, param, (param, null, null));
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Semmle.Extraction.CSharp.Populators;
|
||||
using Semmle.Extraction.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -35,7 +36,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
if (Symbol.TypeKind == TypeKind.Error)
|
||||
{
|
||||
UnknownType.Create(Context); // make sure this exists so we can use it in `TypeRef::getReferencedType`
|
||||
Context.Extractor.MissingType(Symbol.ToString()!, Context.FromSource);
|
||||
return;
|
||||
}
|
||||
@@ -48,7 +48,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
if (Symbol.IsBoundNullable())
|
||||
{
|
||||
// An instance of Nullable<T>
|
||||
trapFile.nullable_underlying_type(this, TypeArguments[0].TypeRef);
|
||||
trapFile.nullable_underlying_type(this, Create(Context, Symbol.TypeArguments[0]).TypeRef);
|
||||
}
|
||||
else if (Symbol.IsReallyUnbound())
|
||||
{
|
||||
@@ -67,7 +67,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
: Type.Create(Context, Symbol.ConstructedFrom);
|
||||
trapFile.constructed_generic(this, unbound.TypeRef);
|
||||
|
||||
for (var i = 0; i < TypeArguments.Length; ++i)
|
||||
for (var i = 0; i < Symbol.TypeArguments.Length; ++i)
|
||||
{
|
||||
trapFile.type_arguments(TypeArguments[i].TypeRef, i, this);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Util;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -23,9 +24,9 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
symbol.ContainingType is not null && ConstructedOrParentIsConstructed(symbol.ContainingType);
|
||||
}
|
||||
|
||||
public Kinds.TypeKind GetTypeKind(Context cx, bool constructUnderlyingTupleType)
|
||||
private static Kinds.TypeKind GetClassType(Context cx, ITypeSymbol t, bool constructUnderlyingTupleType)
|
||||
{
|
||||
switch (Symbol.SpecialType)
|
||||
switch (t.SpecialType)
|
||||
{
|
||||
case SpecialType.System_Int32: return Kinds.TypeKind.INT;
|
||||
case SpecialType.System_UInt32: return Kinds.TypeKind.UINT;
|
||||
@@ -43,14 +44,14 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
case SpecialType.System_Single: return Kinds.TypeKind.FLOAT;
|
||||
case SpecialType.System_IntPtr: return Kinds.TypeKind.INT_PTR;
|
||||
default:
|
||||
if (Symbol.IsBoundNullable())
|
||||
if (t.IsBoundNullable())
|
||||
return Kinds.TypeKind.NULLABLE;
|
||||
|
||||
switch (Symbol.TypeKind)
|
||||
switch (t.TypeKind)
|
||||
{
|
||||
case TypeKind.Class: return Kinds.TypeKind.CLASS;
|
||||
case TypeKind.Struct:
|
||||
return ((INamedTypeSymbol)Symbol).IsTupleType && !constructUnderlyingTupleType
|
||||
return ((INamedTypeSymbol)t).IsTupleType && !constructUnderlyingTupleType
|
||||
? Kinds.TypeKind.TUPLE
|
||||
: Kinds.TypeKind.STRUCT;
|
||||
case TypeKind.Interface: return Kinds.TypeKind.INTERFACE;
|
||||
@@ -61,7 +62,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
case TypeKind.FunctionPointer: return Kinds.TypeKind.FUNCTION_POINTER;
|
||||
case TypeKind.Error: return Kinds.TypeKind.UNKNOWN;
|
||||
default:
|
||||
cx.ModelError(Symbol, $"Unhandled type kind '{Symbol.TypeKind}'");
|
||||
cx.ModelError(t, $"Unhandled type kind '{t.TypeKind}'");
|
||||
return Kinds.TypeKind.UNKNOWN;
|
||||
}
|
||||
}
|
||||
@@ -75,7 +76,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
trapFile.Write("types(");
|
||||
trapFile.WriteColumn(this);
|
||||
trapFile.Write(',');
|
||||
trapFile.WriteColumn((int)GetTypeKind(Context, constructUnderlyingTupleType));
|
||||
trapFile.WriteColumn((int)GetClassType(Context, Symbol, constructUnderlyingTupleType));
|
||||
trapFile.Write(",\"");
|
||||
Symbol.BuildDisplayName(Context, trapFile, constructUnderlyingTupleType);
|
||||
trapFile.WriteLine("\")");
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
internal class UnknownType : Type
|
||||
{
|
||||
private UnknownType(Context cx)
|
||||
: base(cx, null) { }
|
||||
|
||||
public override void Populate(TextWriter trapFile)
|
||||
{
|
||||
trapFile.types(this, Kinds.TypeKind.UNKNOWN, "<unknown type>");
|
||||
}
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
trapFile.Write("<unknown>;type");
|
||||
}
|
||||
|
||||
public override bool NeedsPopulation => true;
|
||||
|
||||
public override int GetHashCode() => 98744554;
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is not null && obj.GetType() == typeof(UnknownType);
|
||||
}
|
||||
|
||||
public static Type Create(Context cx) => UnknownTypeFactory.Instance.CreateEntity(cx, typeof(UnknownType), null);
|
||||
|
||||
private class UnknownTypeFactory : CachedEntityFactory<ITypeSymbol?, UnknownType>
|
||||
{
|
||||
public static UnknownTypeFactory Instance { get; } = new UnknownTypeFactory();
|
||||
|
||||
public override UnknownType Create(Context cx, ITypeSymbol? init) => new UnknownType(cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,56 +18,18 @@ namespace Semmle.Extraction.CSharp
|
||||
/// </summary>
|
||||
public SemanticModel GetModel(SyntaxNode node)
|
||||
{
|
||||
if (node.SyntaxTree == SourceTree)
|
||||
// todo: when this context belongs to a SourceScope, the syntax tree can be retrieved from the scope, and
|
||||
// the node parameter could be removed. Is there any case when we pass in a node that's not from the current
|
||||
// tree?
|
||||
if (cachedModel is null || node.SyntaxTree != cachedModel.SyntaxTree)
|
||||
{
|
||||
if (cachedModelForTree is null)
|
||||
{
|
||||
cachedModelForTree = Compilation.GetSemanticModel(node.SyntaxTree);
|
||||
}
|
||||
|
||||
return cachedModelForTree;
|
||||
cachedModel = Compilation.GetSemanticModel(node.SyntaxTree);
|
||||
}
|
||||
|
||||
if (cachedModelForOtherTrees is null || node.SyntaxTree != cachedModelForOtherTrees.SyntaxTree)
|
||||
{
|
||||
cachedModelForOtherTrees = Compilation.GetSemanticModel(node.SyntaxTree);
|
||||
}
|
||||
|
||||
return cachedModelForOtherTrees;
|
||||
return cachedModel;
|
||||
}
|
||||
|
||||
private SemanticModel? cachedModelForTree;
|
||||
private SemanticModel? cachedModelForOtherTrees;
|
||||
|
||||
// The below is a workaround to the bug reported in https://github.com/dotnet/roslyn/issues/58226
|
||||
// Lambda parameters that are equal according to `SymbolEqualityComparer.Default`, might have different
|
||||
// hash-codes, and as a result might not be found in `symbolEntityCache` by hash-code lookup.
|
||||
internal IParameterSymbol GetPossiblyCachedParameterSymbol(IParameterSymbol param)
|
||||
{
|
||||
if ((param.ContainingSymbol as IMethodSymbol)?.MethodKind != MethodKind.AnonymousFunction)
|
||||
{
|
||||
return param;
|
||||
}
|
||||
|
||||
foreach (var sr in param.DeclaringSyntaxReferences)
|
||||
{
|
||||
var syntax = sr.GetSyntax();
|
||||
if (lambdaParameterCache.TryGetValue(syntax, out var cached) &&
|
||||
SymbolEqualityComparer.Default.Equals(param, cached))
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
internal void CacheLambdaParameterSymbol(IParameterSymbol param, SyntaxNode syntax)
|
||||
{
|
||||
lambdaParameterCache[syntax] = param;
|
||||
}
|
||||
|
||||
private readonly Dictionary<SyntaxNode, IParameterSymbol> lambdaParameterCache = new Dictionary<SyntaxNode, IParameterSymbol>();
|
||||
private SemanticModel? cachedModel;
|
||||
|
||||
/// <summary>
|
||||
/// The current compilation unit.
|
||||
|
||||
@@ -1,24 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Extraction.CSharp</AssemblyName>
|
||||
<RootNamespace>Semmle.Extraction.CSharp</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CIL\Semmle.Extraction.CIL.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1"/>
|
||||
<PackageReference Include="Microsoft.Build" Version="16.11.0"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Extraction.CSharp</AssemblyName>
|
||||
<RootNamespace>Semmle.Extraction.CSharp</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CIL\Semmle.Extraction.CIL.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" />
|
||||
<PackageReference Include="Microsoft.Build" Version="16.9.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.FileSystem" Version="4.3.0"/>
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0"/>
|
||||
<PackageReference Include="xunit" Version="2.4.1"/>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp.Standalone\Semmle.Extraction.CSharp.Standalone.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp.Standalone\Semmle.Extraction.CSharp.Standalone.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,24 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Extraction</AssemblyName>
|
||||
<RootNamespace>Semmle.Extraction</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<CodeAnalysisRuleSet>Semmle.Extraction.ruleset</CodeAnalysisRuleSet>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DefineConstants>TRACE;DEBUG;DEBUG_LABELS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.0.1"/>
|
||||
<PackageReference Include="GitInfo" Version="2.2.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Extraction</AssemblyName>
|
||||
<RootNamespace>Semmle.Extraction</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<CodeAnalysisRuleSet>Semmle.Extraction.ruleset</CodeAnalysisRuleSet>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DefineConstants>TRACE;DEBUG;DEBUG_LABELS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.9.0" />
|
||||
<PackageReference Include="GitInfo" Version="2.1.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="xunit" Version="2.4.1"/>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
## 0.0.4
|
||||
@@ -1 +0,0 @@
|
||||
## 0.0.4
|
||||
@@ -1,2 +0,0 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.4
|
||||
@@ -2,5 +2,40 @@
|
||||
* The default C# QL library.
|
||||
*/
|
||||
|
||||
// Do not add other imports here; add to `semmle.code.csharp.internal.csharp` instead
|
||||
import semmle.code.csharp.internal.csharp
|
||||
import Customizations
|
||||
import semmle.code.csharp.Attribute
|
||||
import semmle.code.csharp.Callable
|
||||
import semmle.code.csharp.Comments
|
||||
import semmle.code.csharp.Element
|
||||
import semmle.code.csharp.Event
|
||||
import semmle.code.csharp.File
|
||||
import semmle.code.csharp.Generics
|
||||
import semmle.code.csharp.Location
|
||||
import semmle.code.csharp.Member
|
||||
import semmle.code.csharp.Namespace
|
||||
import semmle.code.csharp.AnnotatedType
|
||||
import semmle.code.csharp.Property
|
||||
import semmle.code.csharp.Stmt
|
||||
import semmle.code.csharp.Type
|
||||
import semmle.code.csharp.Using
|
||||
import semmle.code.csharp.Variable
|
||||
import semmle.code.csharp.XML
|
||||
import semmle.code.csharp.Preprocessor
|
||||
import semmle.code.csharp.exprs.Access
|
||||
import semmle.code.csharp.exprs.ArithmeticOperation
|
||||
import semmle.code.csharp.exprs.Assignment
|
||||
import semmle.code.csharp.exprs.BitwiseOperation
|
||||
import semmle.code.csharp.exprs.Call
|
||||
import semmle.code.csharp.exprs.ComparisonOperation
|
||||
import semmle.code.csharp.exprs.Creation
|
||||
import semmle.code.csharp.exprs.Dynamic
|
||||
import semmle.code.csharp.exprs.Expr
|
||||
import semmle.code.csharp.exprs.Literal
|
||||
import semmle.code.csharp.exprs.LogicalOperation
|
||||
import semmle.code.csharp.controlflow.ControlFlowGraph
|
||||
import semmle.code.csharp.dataflow.DataFlow
|
||||
import semmle.code.csharp.dataflow.TaintTracking
|
||||
import semmle.code.csharp.dataflow.SSA
|
||||
|
||||
/** Whether the source was extracted without a build command. */
|
||||
predicate extractionIsStandalone() { exists(SourceFile f | f.extractedStandalone()) }
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
name: codeql/csharp-all
|
||||
version: 0.0.5-dev
|
||||
groups: csharp
|
||||
version: 0.0.2
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
library: true
|
||||
dependencies:
|
||||
codeql/csharp-upgrades: ^0.0.3
|
||||
codeql/csharp-upgrades: 0.0.2
|
||||
|
||||
@@ -25,7 +25,7 @@ private module Cached {
|
||||
cached
|
||||
predicate alwaysThrowsException(Method m, Type t) {
|
||||
alwaysThrowsMethod(m) and
|
||||
forex(Throw ex | ex = m.getImplementation().getAnInstruction() | t = ex.getExceptionType())
|
||||
forex(Throw ex | ex = m.getImplementation().getAnInstruction() | t = ex.getExpr().getType())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -612,7 +612,7 @@ class ExprMissingType extends InstructionViolation {
|
||||
not instruction instanceof Opcodes::Ldvirtftn and
|
||||
not instruction instanceof Opcodes::Arglist and
|
||||
not instruction instanceof Opcodes::Refanytype and
|
||||
instruction.getPushCount() >= 1 and
|
||||
instruction.getPushCount() = 1 and
|
||||
count(instruction.getType()) != 1
|
||||
}
|
||||
|
||||
|
||||
@@ -56,32 +56,6 @@ class ControlFlowNode extends @cil_controlflow_node {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the `i`th operand. Unlike `getOperand(i).getType()`, this
|
||||
* predicate takes into account when there are multiple possible operands with
|
||||
* different types.
|
||||
*/
|
||||
Type getOperandType(int i) {
|
||||
strictcount(this.getOperand(i)) = 1 and
|
||||
result = this.getOperand(i).getType()
|
||||
or
|
||||
strictcount(this.getOperand(i)) = 2 and
|
||||
exists(ControlFlowNode op1, ControlFlowNode op2, Type t2 |
|
||||
op1 = this.getOperand(i) and
|
||||
op2 = this.getOperand(i) and
|
||||
op1 != op2 and
|
||||
result = op1.getType() and
|
||||
t2 = op2.getType()
|
||||
|
|
||||
result = t2
|
||||
or
|
||||
result.(PrimitiveType).getUnderlyingType().getConversionIndex() >
|
||||
t2.(PrimitiveType).getUnderlyingType().getConversionIndex()
|
||||
or
|
||||
op2 instanceof NullLiteral
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets an operand of this instruction, if any. */
|
||||
ControlFlowNode getAnOperand() { result = this.getOperand(_) }
|
||||
|
||||
@@ -128,12 +102,7 @@ class ControlFlowNode extends @cil_controlflow_node {
|
||||
/** Gets the method containing this control flow node. */
|
||||
MethodImplementation getImplementation() { none() }
|
||||
|
||||
/**
|
||||
* Gets the type of the item pushed onto the stack, if any.
|
||||
*
|
||||
* If called via `ControlFlowNode::getOperand(i).getType()`, consider using
|
||||
* `ControlFlowNode::getOperandType(i)` instead.
|
||||
*/
|
||||
/** Gets the type of the item pushed onto the stack, if any. */
|
||||
cached
|
||||
Type getType() { none() }
|
||||
|
||||
|
||||
@@ -73,8 +73,8 @@ class ComparisonOperation extends BinaryExpr, @cil_comparison_operation {
|
||||
class BinaryArithmeticExpr extends BinaryExpr, @cil_binary_arithmetic_operation {
|
||||
override Type getType() {
|
||||
exists(Type t0, Type t1 |
|
||||
t0 = this.getOperandType(0).getUnderlyingType() and
|
||||
t1 = this.getOperandType(1).getUnderlyingType()
|
||||
t0 = this.getOperand(0).getType().getUnderlyingType() and
|
||||
t1 = this.getOperand(1).getType().getUnderlyingType()
|
||||
|
|
||||
t0 = t1 and result = t0
|
||||
or
|
||||
@@ -242,9 +242,6 @@ class Return extends Instruction, @cil_ret {
|
||||
class Throw extends Instruction, DotNet::Throw, @cil_throw_any {
|
||||
override Expr getExpr() { result = this.getOperand(0) }
|
||||
|
||||
/** Gets the type of the exception being thrown. */
|
||||
Type getExceptionType() { result = this.getOperandType(0) }
|
||||
|
||||
override predicate canFlowNext() { none() }
|
||||
}
|
||||
|
||||
|
||||
@@ -199,9 +199,9 @@ module Opcodes {
|
||||
override string getOpcodeName() { result = "neg" }
|
||||
|
||||
override NumericType getType() {
|
||||
result = this.getOperandType(0)
|
||||
result = this.getOperand().getType()
|
||||
or
|
||||
this.getOperandType(0) instanceof Enum and result instanceof IntType
|
||||
this.getOperand().getType() instanceof Enum and result instanceof IntType
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ module Opcodes {
|
||||
|
||||
override int getPushCount() { result = 2 } // This is the only instruction that pushes 2 items
|
||||
|
||||
override Type getType() { result = this.getOperandType(0) }
|
||||
override Type getType() { result = this.getOperand(0).getType() }
|
||||
}
|
||||
|
||||
/** A `ret` instruction. */
|
||||
@@ -887,7 +887,7 @@ module Opcodes {
|
||||
class Ldelem_ref extends ReadArrayElement, @cil_ldelem_ref {
|
||||
override string getOpcodeName() { result = "ldelem.ref" }
|
||||
|
||||
override Type getType() { result = this.getOperandType(1) }
|
||||
override Type getType() { result = this.getArray().getType() }
|
||||
}
|
||||
|
||||
/** An `ldelema` instruction. */
|
||||
|
||||
@@ -205,7 +205,7 @@ private class RefArg extends AssignableAccess {
|
||||
*/
|
||||
predicate isAnalyzable(Parameter p) {
|
||||
exists(Callable callable | callable = this.getUnboundDeclarationTarget(p) |
|
||||
not callable.(Overridable).isOverridableOrImplementable() and
|
||||
not callable.(Virtualizable).isOverridableOrImplementable() and
|
||||
callable.hasBody()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Provides logic for determining interface member implementations.
|
||||
*
|
||||
* Do not use the predicates in this library directly; use the methods
|
||||
* of the class `Overridable` instead.
|
||||
* of the class `Virtualizable` instead.
|
||||
*/
|
||||
|
||||
import csharp
|
||||
@@ -35,26 +35,7 @@ private import Conversion
|
||||
* `implements(A.M, I.M, B)` and `implements(C.M, I.M, C)`.
|
||||
*/
|
||||
cached
|
||||
predicate implements(Overridable m1, Overridable m2, ValueOrRefType t) {
|
||||
implementsVirtualizable(m1, m2, t)
|
||||
or
|
||||
exists(DeclarationWithAccessors d1, DeclarationWithAccessors d2, int kind |
|
||||
implementsVirtualizable(d1, d2, t) and
|
||||
hasAccessor(d1, m1, pragma[only_bind_into](kind)) and
|
||||
hasAccessor(d2, m2, pragma[only_bind_into](kind))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasAccessor(DeclarationWithAccessors d, Accessor a, int kind) {
|
||||
a = d.getAnAccessor() and
|
||||
(
|
||||
accessors(a, kind, _, _, _) or
|
||||
event_accessors(a, kind, _, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate implementsVirtualizable(Virtualizable m1, Virtualizable m2, ValueOrRefType t) {
|
||||
predicate implements(Virtualizable m1, Virtualizable m2, ValueOrRefType t) {
|
||||
exists(Interface i |
|
||||
i = m2.getDeclaringType() and
|
||||
t.getABaseInterface+() = i and
|
||||
|
||||
@@ -180,15 +180,29 @@ class Member extends DotNet::Member, Modifiable, @member {
|
||||
override predicate isStatic() { Modifiable.super.isStatic() }
|
||||
}
|
||||
|
||||
private class TOverridable = @virtualizable or @callable_accessor;
|
||||
|
||||
/**
|
||||
* A declaration that can be overridden or implemented. That is, a method,
|
||||
* a property, an indexer, an event, or an accessor.
|
||||
* A member where the `virtual` modifier is valid. That is, a method,
|
||||
* a property, an indexer, or an event.
|
||||
*
|
||||
* Unlike `Virtualizable`, this class includes accessors.
|
||||
* Equivalently, these are the members that can be defined in an interface.
|
||||
*/
|
||||
class Overridable extends Declaration, TOverridable {
|
||||
class Virtualizable extends Member, @virtualizable {
|
||||
/** Holds if this member has the modifier `override`. */
|
||||
predicate isOverride() { this.hasModifier("override") }
|
||||
|
||||
/** Holds if this member is `virtual`. */
|
||||
predicate isVirtual() { this.hasModifier("virtual") }
|
||||
|
||||
override predicate isPublic() {
|
||||
Member.super.isPublic() or
|
||||
this.implementsExplicitInterface()
|
||||
}
|
||||
|
||||
override predicate isPrivate() {
|
||||
super.isPrivate() and
|
||||
not this.implementsExplicitInterface()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets any interface this member explicitly implements; this only applies
|
||||
* to members that can be declared on an interface, i.e. methods, properties,
|
||||
@@ -202,10 +216,19 @@ class Overridable extends Declaration, TOverridable {
|
||||
predicate implementsExplicitInterface() { exists(this.getExplicitlyImplementedInterface()) }
|
||||
|
||||
/** Holds if this member can be overridden or implemented. */
|
||||
predicate isOverridableOrImplementable() { none() }
|
||||
predicate isOverridableOrImplementable() {
|
||||
not this.isSealed() and
|
||||
not this.getDeclaringType().isSealed() and
|
||||
(
|
||||
this.isVirtual() or
|
||||
this.isOverride() or
|
||||
this.isAbstract() or
|
||||
this.getDeclaringType() instanceof Interface
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the member that is immediately overridden by this member, if any. */
|
||||
Overridable getOverridee() {
|
||||
Virtualizable getOverridee() {
|
||||
overrides(this, result)
|
||||
or
|
||||
// For accessors (which are `Callable`s), the extractor generates entries
|
||||
@@ -219,7 +242,7 @@ class Overridable extends Declaration, TOverridable {
|
||||
}
|
||||
|
||||
/** Gets a member that immediately overrides this member, if any. */
|
||||
Overridable getAnOverrider() { this = result.getOverridee() }
|
||||
Virtualizable getAnOverrider() { this = result.getOverridee() }
|
||||
|
||||
/** Holds if this member is overridden by some other member. */
|
||||
predicate isOverridden() { exists(this.getAnOverrider()) }
|
||||
@@ -250,10 +273,10 @@ class Overridable extends Declaration, TOverridable {
|
||||
* `A.M.getImplementee(B) = I.M` and
|
||||
* `C.M.getImplementee(C) = I.M`.
|
||||
*/
|
||||
Overridable getImplementee(ValueOrRefType t) { implements(this, result, t) }
|
||||
Virtualizable getImplementee(ValueOrRefType t) { implements(this, result, t) }
|
||||
|
||||
/** Gets the interface member that is immediately implemented by this member, if any. */
|
||||
Overridable getImplementee() { result = this.getImplementee(_) }
|
||||
Virtualizable getImplementee() { result = this.getImplementee(_) }
|
||||
|
||||
/**
|
||||
* Gets a member that immediately implements this interface member, if any.
|
||||
@@ -278,10 +301,10 @@ class Overridable extends Declaration, TOverridable {
|
||||
* `I.M.getAnImplementor(B) = A.M` and
|
||||
* `I.M.getAnImplementor(C) = C.M`.
|
||||
*/
|
||||
Overridable getAnImplementor(ValueOrRefType t) { this = result.getImplementee(t) }
|
||||
Virtualizable getAnImplementor(ValueOrRefType t) { this = result.getImplementee(t) }
|
||||
|
||||
/** Gets a member that immediately implements this interface member, if any. */
|
||||
Overridable getAnImplementor() { this = result.getImplementee() }
|
||||
Virtualizable getAnImplementor() { this = result.getImplementee() }
|
||||
|
||||
/**
|
||||
* Gets an interface member that is (transitively) implemented by this
|
||||
@@ -311,8 +334,8 @@ class Overridable extends Declaration, TOverridable {
|
||||
* - If this member is `D.M` then `I.M = getAnUltimateImplementee()`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
Overridable getAnUltimateImplementee() {
|
||||
exists(Overridable implementation, ValueOrRefType implementationType |
|
||||
Virtualizable getAnUltimateImplementee() {
|
||||
exists(Virtualizable implementation, ValueOrRefType implementationType |
|
||||
implements(implementation, result, implementationType)
|
||||
|
|
||||
this = implementation
|
||||
@@ -331,7 +354,7 @@ class Overridable extends Declaration, TOverridable {
|
||||
* Note that this is generally *not* equivalent with
|
||||
* `getImplementor().getAnOverrider*()` (see `getImplementee`).
|
||||
*/
|
||||
Overridable getAnUltimateImplementor() { this = result.getAnUltimateImplementee() }
|
||||
Virtualizable getAnUltimateImplementor() { this = result.getAnUltimateImplementee() }
|
||||
|
||||
/** Holds if this interface member is implemented by some other member. */
|
||||
predicate isImplemented() { exists(this.getAnImplementor()) }
|
||||
@@ -339,59 +362,14 @@ class Overridable extends Declaration, TOverridable {
|
||||
/** Holds if this member implements (transitively) an interface member. */
|
||||
predicate implements() { exists(this.getAnUltimateImplementee()) }
|
||||
|
||||
/**
|
||||
* Holds if this member overrides or implements (transitively)
|
||||
* `that` member.
|
||||
*/
|
||||
predicate overridesOrImplements(Overridable that) {
|
||||
this.getOverridee+() = that or
|
||||
this.getAnUltimateImplementee() = that
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this member overrides or implements (reflexively, transitively)
|
||||
* `that` member.
|
||||
*/
|
||||
predicate overridesOrImplementsOrEquals(Overridable that) {
|
||||
predicate overridesOrImplementsOrEquals(Virtualizable that) {
|
||||
this = that or
|
||||
this.overridesOrImplements(that)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A member where the `virtual` modifier is valid. That is, a method,
|
||||
* a property, an indexer, or an event.
|
||||
*
|
||||
* Equivalently, these are the members that can be defined in an interface.
|
||||
*
|
||||
* Unlike `Overridable`, this class excludes accessors.
|
||||
*/
|
||||
class Virtualizable extends Overridable, Member, @virtualizable {
|
||||
/** Holds if this member has the modifier `override`. */
|
||||
predicate isOverride() { this.hasModifier("override") }
|
||||
|
||||
/** Holds if this member is `virtual`. */
|
||||
predicate isVirtual() { this.hasModifier("virtual") }
|
||||
|
||||
override predicate isPublic() {
|
||||
Member.super.isPublic() or
|
||||
this.implementsExplicitInterface()
|
||||
}
|
||||
|
||||
override predicate isPrivate() {
|
||||
super.isPrivate() and
|
||||
not this.implementsExplicitInterface()
|
||||
}
|
||||
|
||||
override predicate isOverridableOrImplementable() {
|
||||
not this.isSealed() and
|
||||
not this.getDeclaringType().isSealed() and
|
||||
(
|
||||
this.isVirtual() or
|
||||
this.isOverride() or
|
||||
this.isAbstract() or
|
||||
this.getDeclaringType() instanceof Interface
|
||||
)
|
||||
this.getOverridee+() = that or
|
||||
this.getAnUltimateImplementee() = that
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -315,7 +315,7 @@ class Indexer extends DeclarationWithGetSetAccessors, Parameterizable, @indexer
|
||||
* An accessor. Either a getter (`Getter`), a setter (`Setter`), or event
|
||||
* accessor (`EventAccessor`).
|
||||
*/
|
||||
class Accessor extends Callable, Modifiable, Attributable, Overridable, @callable_accessor {
|
||||
class Accessor extends Callable, Modifiable, Attributable, @callable_accessor {
|
||||
override ValueOrRefType getDeclaringType() { result = this.getDeclaration().getDeclaringType() }
|
||||
|
||||
/** Gets the assembly name of this accessor. */
|
||||
@@ -376,10 +376,6 @@ class Accessor extends Callable, Modifiable, Attributable, Overridable, @callabl
|
||||
not (result instanceof AccessModifier and exists(this.getAnAccessModifier()))
|
||||
}
|
||||
|
||||
override predicate isOverridableOrImplementable() {
|
||||
this.getDeclaration().isOverridableOrImplementable()
|
||||
}
|
||||
|
||||
override Accessor getUnboundDeclaration() { accessors(this, _, _, _, result) }
|
||||
|
||||
override Location getALocation() { accessor_location(this, result) }
|
||||
|
||||
@@ -75,7 +75,7 @@ class BlockStmt extends Stmt, @block_stmt {
|
||||
|
||||
/** Holds if this block is the container of the global statements. */
|
||||
predicate isGlobalStatementContainer() {
|
||||
this.getEnclosingCallable().hasQualifiedName("Program.<Main>$")
|
||||
this.getEnclosingCallable().hasQualifiedName("<Program>$.<Main>$")
|
||||
}
|
||||
|
||||
override Stmt stripSingletonBlocks() {
|
||||
|
||||
@@ -12,12 +12,7 @@ private class TypeRef extends @typeref {
|
||||
|
||||
string toString() { result = this.getName() }
|
||||
|
||||
Type getReferencedType() {
|
||||
typeref_type(this, result)
|
||||
or
|
||||
not typeref_type(this, _) and
|
||||
result instanceof UnknownType
|
||||
}
|
||||
Type getReferencedType() { typeref_type(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,7 +8,7 @@ class MainMethod extends Method {
|
||||
(
|
||||
this.hasName("Main")
|
||||
or
|
||||
this.hasQualifiedName("Program.<Main>$")
|
||||
this.hasQualifiedName("<Program>$", "<Main>$")
|
||||
) and
|
||||
this.isStatic() and
|
||||
(this.getReturnType() instanceof VoidType or this.getReturnType() instanceof IntType) and
|
||||
|
||||
@@ -241,7 +241,7 @@ module ControlFlow {
|
||||
predicate isBranch() { strictcount(this.getASuccessor()) > 1 }
|
||||
|
||||
/** Gets the enclosing callable of this control flow node. */
|
||||
final Callable getEnclosingCallable() { result = getNodeCfgScope(this) }
|
||||
Callable getEnclosingCallable() { none() }
|
||||
}
|
||||
|
||||
/** Provides different types of control flow nodes. */
|
||||
@@ -253,6 +253,8 @@ module ControlFlow {
|
||||
|
||||
override BasicBlocks::EntryBlock getBasicBlock() { result = Node.super.getBasicBlock() }
|
||||
|
||||
override Callable getEnclosingCallable() { result = this.getCallable() }
|
||||
|
||||
private Assignable getAssignable() { this = TEntryNode(result) }
|
||||
|
||||
override Location getLocation() {
|
||||
@@ -281,6 +283,8 @@ module ControlFlow {
|
||||
result = Node.super.getBasicBlock()
|
||||
}
|
||||
|
||||
override Callable getEnclosingCallable() { result = this.getCallable() }
|
||||
|
||||
override Location getLocation() { result = scope.getLocation() }
|
||||
|
||||
override string toString() {
|
||||
@@ -305,6 +309,8 @@ module ControlFlow {
|
||||
|
||||
override BasicBlocks::ExitBlock getBasicBlock() { result = Node.super.getBasicBlock() }
|
||||
|
||||
override Callable getEnclosingCallable() { result = this.getCallable() }
|
||||
|
||||
override Location getLocation() { result = scope.getLocation() }
|
||||
|
||||
override string toString() { result = "exit " + scope }
|
||||
@@ -321,7 +327,14 @@ module ControlFlow {
|
||||
private Splits splits;
|
||||
private ControlFlowElement cfe;
|
||||
|
||||
ElementNode() { this = TElementNode(_, cfe, splits) }
|
||||
ElementNode() { this = TElementNode(cfe, splits) }
|
||||
|
||||
override Callable getEnclosingCallable() {
|
||||
result = cfe.getEnclosingCallable()
|
||||
or
|
||||
result =
|
||||
this.getASplit().(Splitting::InitializerSplitting::InitializerSplit).getConstructor()
|
||||
}
|
||||
|
||||
override ControlFlowElement getElement() { result = cfe }
|
||||
|
||||
|
||||
@@ -1086,7 +1086,7 @@ module Internal {
|
||||
*/
|
||||
private Callable customNullCheck(Parameter p, BooleanValue retVal, boolean isNull) {
|
||||
result.getReturnType() instanceof BoolType and
|
||||
not result.(Overridable).isOverridableOrImplementable() and
|
||||
not result.(Virtualizable).isOverridableOrImplementable() and
|
||||
p.getCallable() = result and
|
||||
not p.isParams() and
|
||||
p.getType() = any(Type t | t instanceof RefType or t instanceof NullableType) and
|
||||
|
||||
@@ -342,7 +342,7 @@ private predicate succExitSplits(
|
||||
ControlFlowElement pred, Splits predSplits, CfgScope succ, SuccessorType t
|
||||
) {
|
||||
exists(Reachability::SameSplitsBlock b, Completion c | pred = b.getAnElement() |
|
||||
b.isReachable(succ, predSplits) and
|
||||
b.isReachable(predSplits) and
|
||||
t = getAMatchingSuccessorType(c) and
|
||||
scopeLast(succ, pred, c) and
|
||||
forall(SplitImpl predSplit | predSplit = predSplits.getASplit() |
|
||||
@@ -399,7 +399,7 @@ private module SuccSplits {
|
||||
ControlFlowElement succ, Completion c
|
||||
) {
|
||||
pred = b.getAnElement() and
|
||||
b.isReachable(_, predSplits) and
|
||||
b.isReachable(predSplits) and
|
||||
succ(pred, succ, c)
|
||||
}
|
||||
|
||||
@@ -728,12 +728,12 @@ private module Reachability {
|
||||
* Holds if the elements of this block are reachable from a callable entry
|
||||
* point, with the splits `splits`.
|
||||
*/
|
||||
predicate isReachable(CfgScope scope, Splits splits) {
|
||||
predicate isReachable(Splits splits) {
|
||||
// Base case
|
||||
succEntrySplits(scope, this, splits, _)
|
||||
succEntrySplits(_, this, splits, _)
|
||||
or
|
||||
// Recursive case
|
||||
exists(SameSplitsBlock pred, Splits predSplits | pred.isReachable(scope, predSplits) |
|
||||
exists(SameSplitsBlock pred, Splits predSplits | pred.isReachable(predSplits) |
|
||||
this = pred.getASuccessor(predSplits, splits)
|
||||
)
|
||||
}
|
||||
@@ -791,20 +791,18 @@ private module Cached {
|
||||
newtype TCfgNode =
|
||||
TEntryNode(CfgScope scope) { succEntrySplits(scope, _, _, _) } or
|
||||
TAnnotatedExitNode(CfgScope scope, boolean normal) {
|
||||
exists(Reachability::SameSplitsBlock b, SuccessorType t | b.isReachable(scope, _) |
|
||||
exists(Reachability::SameSplitsBlock b, SuccessorType t | b.isReachable(_) |
|
||||
succExitSplits(b.getAnElement(), _, scope, t) and
|
||||
if isAbnormalExitType(t) then normal = false else normal = true
|
||||
)
|
||||
} or
|
||||
TExitNode(CfgScope scope) {
|
||||
exists(Reachability::SameSplitsBlock b | b.isReachable(scope, _) |
|
||||
exists(Reachability::SameSplitsBlock b | b.isReachable(_) |
|
||||
succExitSplits(b.getAnElement(), _, scope, _)
|
||||
)
|
||||
} or
|
||||
TElementNode(CfgScope scope, ControlFlowElement cfe, Splits splits) {
|
||||
exists(Reachability::SameSplitsBlock b | b.isReachable(scope, splits) |
|
||||
cfe = b.getAnElement()
|
||||
)
|
||||
TElementNode(ControlFlowElement cfe, Splits splits) {
|
||||
exists(Reachability::SameSplitsBlock b | b.isReachable(splits) | cfe = b.getAnElement())
|
||||
}
|
||||
|
||||
/** Gets a successor node of a given flow type, if any. */
|
||||
@@ -812,24 +810,24 @@ private module Cached {
|
||||
TCfgNode getASuccessor(TCfgNode pred, SuccessorType t) {
|
||||
// Callable entry node -> callable body
|
||||
exists(ControlFlowElement succElement, Splits succSplits, CfgScope scope |
|
||||
result = TElementNode(scope, succElement, succSplits) and
|
||||
result = TElementNode(succElement, succSplits) and
|
||||
pred = TEntryNode(scope) and
|
||||
succEntrySplits(scope, succElement, succSplits, t)
|
||||
)
|
||||
or
|
||||
exists(CfgScope scope, ControlFlowElement predElement, Splits predSplits |
|
||||
pred = TElementNode(pragma[only_bind_into](scope), predElement, predSplits)
|
||||
exists(ControlFlowElement predElement, Splits predSplits |
|
||||
pred = TElementNode(predElement, predSplits)
|
||||
|
|
||||
// Element node -> callable exit (annotated)
|
||||
exists(boolean normal |
|
||||
result = TAnnotatedExitNode(pragma[only_bind_into](scope), normal) and
|
||||
exists(CfgScope scope, boolean normal |
|
||||
result = TAnnotatedExitNode(scope, normal) and
|
||||
succExitSplits(predElement, predSplits, scope, t) and
|
||||
if isAbnormalExitType(t) then normal = false else normal = true
|
||||
)
|
||||
or
|
||||
// Element node -> element node
|
||||
exists(ControlFlowElement succElement, Splits succSplits, Completion c |
|
||||
result = TElementNode(pragma[only_bind_into](scope), succElement, succSplits)
|
||||
result = TElementNode(succElement, succSplits)
|
||||
|
|
||||
succSplits(predElement, predSplits, succElement, succSplits, c) and
|
||||
t = getAMatchingSuccessorType(c)
|
||||
@@ -855,23 +853,6 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
ControlFlowElement getAControlFlowExitNode(ControlFlowElement cfe) { last(cfe, result, _) }
|
||||
|
||||
/**
|
||||
* Gets the CFG scope of node `n`. Unlike `getCfgScope`, this predicate
|
||||
* is calculated based on reachability from an entry node, and it may
|
||||
* yield different results for AST elements that are split into multiple
|
||||
* scopes.
|
||||
*/
|
||||
cached
|
||||
CfgScope getNodeCfgScope(TCfgNode n) {
|
||||
n = TEntryNode(result)
|
||||
or
|
||||
n = TAnnotatedExitNode(result, _)
|
||||
or
|
||||
n = TExitNode(result)
|
||||
or
|
||||
n = TElementNode(result, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
@@ -957,45 +938,14 @@ module Consistency {
|
||||
not split.hasEntry(pred, succ, c)
|
||||
}
|
||||
|
||||
private class SimpleSuccessorType extends SuccessorType {
|
||||
SimpleSuccessorType() {
|
||||
this = getAMatchingSuccessorType(any(Completion c | completionIsSimple(c)))
|
||||
}
|
||||
}
|
||||
|
||||
private class NormalSuccessorType extends SuccessorType {
|
||||
NormalSuccessorType() {
|
||||
this = getAMatchingSuccessorType(any(Completion c | completionIsNormal(c)))
|
||||
}
|
||||
}
|
||||
|
||||
query predicate multipleSuccessors(Node node, SuccessorType t, Node successor) {
|
||||
not node instanceof TEntryNode and
|
||||
strictcount(getASuccessor(node, t)) > 1 and
|
||||
successor = getASuccessor(node, t) and
|
||||
// allow for functions with multiple bodies
|
||||
not (t instanceof SimpleSuccessorType and node instanceof TEntryNode)
|
||||
}
|
||||
|
||||
query predicate simpleAndNormalSuccessors(
|
||||
Node node, NormalSuccessorType t1, SimpleSuccessorType t2, Node succ1, Node succ2
|
||||
) {
|
||||
t1 != t2 and
|
||||
succ1 = getASuccessor(node, t1) and
|
||||
succ2 = getASuccessor(node, t2)
|
||||
successor = getASuccessor(node, t)
|
||||
}
|
||||
|
||||
query predicate deadEnd(Node node) {
|
||||
not node instanceof TExitNode and
|
||||
not exists(getASuccessor(node, _))
|
||||
}
|
||||
|
||||
query predicate nonUniqueSplitKind(SplitImpl split, SplitKind sk) {
|
||||
sk = split.getKind() and
|
||||
strictcount(split.getKind()) > 1
|
||||
}
|
||||
|
||||
query predicate nonUniqueListOrder(SplitKind sk, int ord) {
|
||||
ord = sk.getListOrder() and
|
||||
strictcount(sk.getListOrder()) > 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ module InitializerSplitting {
|
||||
*
|
||||
* respectively.
|
||||
*/
|
||||
private class InitializerSplit extends Split, TInitializerSplit {
|
||||
class InitializerSplit extends Split, TInitializerSplit {
|
||||
private Constructor c;
|
||||
|
||||
InitializerSplit() { this = TInitializerSplit(c) }
|
||||
|
||||
@@ -78,6 +78,7 @@ private import internal.DataFlowPublic
|
||||
private import internal.FlowSummaryImpl::Public
|
||||
private import internal.FlowSummaryImpl::Private::External
|
||||
private import internal.FlowSummaryImplSpecific
|
||||
private import semmle.code.csharp.dispatch.OverridableCallable
|
||||
|
||||
/**
|
||||
* A module importing the frameworks that provide external flow data,
|
||||
@@ -91,17 +92,6 @@ private module Frameworks {
|
||||
private import semmle.code.csharp.frameworks.ServiceStack
|
||||
private import semmle.code.csharp.frameworks.Sql
|
||||
private import semmle.code.csharp.frameworks.EntityFramework
|
||||
private import semmle.code.csharp.frameworks.system.Text
|
||||
private import semmle.code.csharp.frameworks.system.Net
|
||||
private import semmle.code.csharp.frameworks.system.Web
|
||||
private import semmle.code.csharp.frameworks.system.collections.Generic
|
||||
private import semmle.code.csharp.frameworks.system.web.ui.WebControls
|
||||
private import semmle.code.csharp.frameworks.JsonNET
|
||||
private import semmle.code.csharp.frameworks.system.IO
|
||||
private import semmle.code.csharp.frameworks.system.io.Compression
|
||||
private import semmle.code.csharp.frameworks.system.Xml
|
||||
private import semmle.code.csharp.frameworks.system.threading.Tasks
|
||||
private import semmle.code.csharp.frameworks.system.runtime.CompilerServices
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -272,7 +262,7 @@ module CsvValidation {
|
||||
not name.regexpMatch("[a-zA-Z0-9_<>,]*") and
|
||||
msg = "Dubious member name \"" + name + "\" in " + pred + " model."
|
||||
or
|
||||
not signature.regexpMatch("|\\([a-zA-Z0-9_<>\\.\\+\\*,\\[\\]]*\\)") and
|
||||
not signature.regexpMatch("|\\([a-zA-Z0-9_<>\\.\\+,\\[\\]]*\\)") and
|
||||
msg = "Dubious signature \"" + signature + "\" in " + pred + " model."
|
||||
or
|
||||
not ext.regexpMatch("|Attribute") and
|
||||
@@ -358,17 +348,16 @@ private class UnboundValueOrRefType extends ValueOrRefType {
|
||||
}
|
||||
}
|
||||
|
||||
/** An unbound callable. */
|
||||
class UnboundCallable extends Callable {
|
||||
private class UnboundCallable extends Callable {
|
||||
UnboundCallable() { this.isUnboundDeclaration() }
|
||||
|
||||
/**
|
||||
* Holds if this unbound callable overrides or implements (transitively)
|
||||
* `that` unbound callable.
|
||||
*/
|
||||
predicate overridesOrImplementsUnbound(UnboundCallable that) {
|
||||
exists(Callable c |
|
||||
this.(Overridable).overridesOrImplements(c) and
|
||||
this.(Virtualizable).overridesOrImplementsOrEquals(c) or
|
||||
this = c.(OverridableCallable).getAnUltimateImplementor() or
|
||||
this = c.(OverridableCallable).getAnOverrider+()
|
||||
|
|
||||
this != c and
|
||||
that = c.getUnboundDeclaration()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
|
||||
import csharp
|
||||
private import internal.FlowSummaryImpl as Impl
|
||||
private import internal.DataFlowDispatch as DataFlowDispatch
|
||||
|
||||
class ParameterPosition = DataFlowDispatch::ParameterPosition;
|
||||
|
||||
class ArgumentPosition = DataFlowDispatch::ArgumentPosition;
|
||||
private import internal.DataFlowDispatch
|
||||
|
||||
// import all instances below
|
||||
private module Summaries {
|
||||
@@ -18,27 +14,7 @@ class SummaryComponent = Impl::Public::SummaryComponent;
|
||||
|
||||
/** Provides predicates for constructing summary components. */
|
||||
module SummaryComponent {
|
||||
private import Impl::Public::SummaryComponent as SummaryComponentInternal
|
||||
|
||||
predicate content = SummaryComponentInternal::content/1;
|
||||
|
||||
/** Gets a summary component for parameter `i`. */
|
||||
SummaryComponent parameter(int i) {
|
||||
exists(ArgumentPosition pos |
|
||||
result = SummaryComponentInternal::parameter(pos) and
|
||||
i = pos.getPosition()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a summary component for argument `i`. */
|
||||
SummaryComponent argument(int i) {
|
||||
exists(ParameterPosition pos |
|
||||
result = SummaryComponentInternal::argument(pos) and
|
||||
i = pos.getPosition()
|
||||
)
|
||||
}
|
||||
|
||||
predicate return = SummaryComponentInternal::return/1;
|
||||
import Impl::Public::SummaryComponent
|
||||
|
||||
/** Gets a summary component that represents a qualifier. */
|
||||
SummaryComponent qualifier() { result = argument(-1) }
|
||||
@@ -57,14 +33,14 @@ module SummaryComponent {
|
||||
}
|
||||
|
||||
/** Gets a summary component that represents the return value of a call. */
|
||||
SummaryComponent return() { result = return(any(DataFlowDispatch::NormalReturnKind rk)) }
|
||||
SummaryComponent return() { result = return(any(NormalReturnKind rk)) }
|
||||
|
||||
/** Gets a summary component that represents a jump to `c`. */
|
||||
SummaryComponent jump(Callable c) {
|
||||
result =
|
||||
return(any(DataFlowDispatch::JumpReturnKind jrk |
|
||||
return(any(JumpReturnKind jrk |
|
||||
jrk.getTarget() = c.getUnboundDeclaration() and
|
||||
jrk.getTargetReturnKind() instanceof DataFlowDispatch::NormalReturnKind
|
||||
jrk.getTargetReturnKind() instanceof NormalReturnKind
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -73,16 +49,7 @@ class SummaryComponentStack = Impl::Public::SummaryComponentStack;
|
||||
|
||||
/** Provides predicates for constructing stacks of summary components. */
|
||||
module SummaryComponentStack {
|
||||
private import Impl::Public::SummaryComponentStack as SummaryComponentStackInternal
|
||||
|
||||
predicate singleton = SummaryComponentStackInternal::singleton/1;
|
||||
|
||||
predicate push = SummaryComponentStackInternal::push/2;
|
||||
|
||||
/** Gets a singleton stack for argument `i`. */
|
||||
SummaryComponentStack argument(int i) { result = singleton(SummaryComponent::argument(i)) }
|
||||
|
||||
predicate return = SummaryComponentStackInternal::return/1;
|
||||
import Impl::Public::SummaryComponentStack
|
||||
|
||||
/** Gets a singleton stack representing a qualifier. */
|
||||
SummaryComponentStack qualifier() { result = singleton(SummaryComponent::qualifier()) }
|
||||
@@ -117,12 +84,12 @@ private class SummarizedCallableDefaultClearsContent extends Impl::Public::Summa
|
||||
}
|
||||
|
||||
// By default, we assume that all stores into arguments are definite
|
||||
override predicate clearsContent(ParameterPosition pos, DataFlow::Content content) {
|
||||
override predicate clearsContent(int i, DataFlow::Content content) {
|
||||
exists(SummaryComponentStack output |
|
||||
this.propagatesFlow(_, output, _) and
|
||||
output.drop(_) =
|
||||
SummaryComponentStack::push(SummaryComponent::content(content),
|
||||
SummaryComponentStack::argument(pos.getPosition())) and
|
||||
SummaryComponentStack::argument(i)) and
|
||||
not content instanceof DataFlow::ElementContent
|
||||
)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@ private import DataFlowImplCommon as DataFlowImplCommon
|
||||
private import DataFlowPublic
|
||||
private import DataFlowPrivate
|
||||
private import FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.csharp.dataflow.FlowSummary as FlowSummary
|
||||
private import semmle.code.csharp.dataflow.FlowSummary
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dispatch.Dispatch
|
||||
private import semmle.code.csharp.dispatch.RuntimeCallable
|
||||
@@ -13,7 +13,7 @@ private import semmle.code.csharp.frameworks.system.Collections
|
||||
private import semmle.code.csharp.frameworks.system.collections.Generic
|
||||
|
||||
private predicate summarizedCallable(DataFlowCallable c) {
|
||||
c instanceof FlowSummary::SummarizedCallable
|
||||
c instanceof SummarizedCallable
|
||||
or
|
||||
FlowSummaryImpl::Private::summaryReturnNode(_, TJumpReturnKind(c, _))
|
||||
or
|
||||
@@ -108,27 +108,13 @@ private module Cached {
|
||||
// No need to include calls that are compiled from source
|
||||
not call.getImplementation().getMethod().compiledFromSource()
|
||||
} or
|
||||
TSummaryCall(FlowSummary::SummarizedCallable c, Node receiver) {
|
||||
TSummaryCall(SummarizedCallable c, Node receiver) {
|
||||
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
|
||||
}
|
||||
|
||||
/** Gets a viable run-time target for the call `call`. */
|
||||
cached
|
||||
DataFlowCallable viableCallable(DataFlowCall call) { result = call.getARuntimeTarget() }
|
||||
|
||||
private int parameterPosition() {
|
||||
result =
|
||||
[
|
||||
-1, any(Parameter p).getPosition(),
|
||||
ImplicitCapturedParameterNodeImpl::getParameterPosition(_)
|
||||
]
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TParameterPosition = MkParameterPosition(int i) { i = parameterPosition() }
|
||||
|
||||
cached
|
||||
newtype TArgumentPosition = MkArgumentPosition(int i) { i = parameterPosition() }
|
||||
}
|
||||
|
||||
import Cached
|
||||
@@ -402,7 +388,7 @@ class CilDataFlowCall extends DataFlowCall, TCilCall {
|
||||
* the method `Select`.
|
||||
*/
|
||||
class SummaryCall extends DelegateDataFlowCall, TSummaryCall {
|
||||
private FlowSummary::SummarizedCallable c;
|
||||
private SummarizedCallable c;
|
||||
private Node receiver;
|
||||
|
||||
SummaryCall() { this = TSummaryCall(c, receiver) }
|
||||
@@ -424,37 +410,3 @@ class SummaryCall extends DelegateDataFlowCall, TSummaryCall {
|
||||
|
||||
override Location getLocation() { result = c.getLocation() }
|
||||
}
|
||||
|
||||
/** A parameter position represented by an integer. */
|
||||
class ParameterPosition extends MkParameterPosition {
|
||||
private int i;
|
||||
|
||||
ParameterPosition() { this = MkParameterPosition(i) }
|
||||
|
||||
/** Gets the underlying integer. */
|
||||
int getPosition() { result = i }
|
||||
|
||||
/** Gets a textual representation of this position. */
|
||||
string toString() { result = i.toString() }
|
||||
}
|
||||
|
||||
/** An argument position represented by an integer. */
|
||||
class ArgumentPosition extends MkArgumentPosition {
|
||||
private int i;
|
||||
|
||||
ArgumentPosition() { this = MkArgumentPosition(i) }
|
||||
|
||||
/** Gets the underlying integer. */
|
||||
int getPosition() { result = i }
|
||||
|
||||
/** Gets a textual representation of this position. */
|
||||
string toString() { result = i.toString() }
|
||||
}
|
||||
|
||||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
|
||||
exists(int i |
|
||||
ppos = MkParameterPosition(i) and
|
||||
apos = MkArgumentPosition(i)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1447,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2142,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2908,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2992,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3639,40 +3639,39 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, pos)
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3687,9 +3686,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3713,7 +3712,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4442,25 +4441,24 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4469,9 +4467,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4635,23 +4633,22 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = ppos and
|
||||
p.getPosition() = pos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4664,7 +4661,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1447,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2142,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2908,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2992,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3639,40 +3639,39 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, pos)
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3687,9 +3686,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3713,7 +3712,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4442,25 +4441,24 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4469,9 +4467,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4635,23 +4633,22 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = ppos and
|
||||
p.getPosition() = pos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4664,7 +4661,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1447,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2142,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2908,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2992,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3639,40 +3639,39 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, pos)
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3687,9 +3686,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3713,7 +3712,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4442,25 +4441,24 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4469,9 +4467,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4635,23 +4633,22 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = ppos and
|
||||
p.getPosition() = pos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4664,7 +4661,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1447,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2142,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2908,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2992,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3639,40 +3639,39 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, pos)
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3687,9 +3686,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3713,7 +3712,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4442,25 +4441,24 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4469,9 +4467,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4635,23 +4633,22 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = ppos and
|
||||
p.getPosition() = pos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4664,7 +4661,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1447,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2142,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2908,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2992,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3639,40 +3639,39 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, pos)
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3687,9 +3686,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3713,7 +3712,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4442,25 +4441,24 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, apos) and
|
||||
arg.argumentOf(call, i) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4469,9 +4467,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4635,23 +4633,22 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = ppos and
|
||||
p.getPosition() = pos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4664,7 +4661,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -62,18 +62,6 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
||||
tupleLimit = 1000
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `arg` is an argument of `call` with an argument position that matches
|
||||
* parameter position `ppos`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate argumentPositionMatch(DataFlowCall call, ArgNode arg, ParameterPosition ppos) {
|
||||
exists(ArgumentPosition apos |
|
||||
arg.argumentOf(call, apos) and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
|
||||
* currently excludes read-steps, store-steps, and flow-through.
|
||||
@@ -83,27 +71,25 @@ predicate argumentPositionMatch(DataFlowCall call, ArgNode arg, ParameterPositio
|
||||
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
|
||||
*/
|
||||
private module LambdaFlow {
|
||||
pragma[noinline]
|
||||
private predicate viableParamNonLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||
p.isParameterOf(viableCallable(call), ppos)
|
||||
private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate viableParamLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), ppos)
|
||||
private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), i)
|
||||
}
|
||||
|
||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParamNonLambda(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos)
|
||||
exists(int i |
|
||||
viableParamNonLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParamLambda(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos)
|
||||
exists(int i |
|
||||
viableParamLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -336,7 +322,7 @@ private module Cached {
|
||||
or
|
||||
exists(ArgNode arg |
|
||||
result.(PostUpdateNode).getPreUpdateNode() = arg and
|
||||
arg.argumentOf(call, k.(ParamUpdateReturnKind).getAMatchingArgumentPosition())
|
||||
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -344,7 +330,7 @@ private module Cached {
|
||||
predicate returnNodeExt(Node n, ReturnKindExt k) {
|
||||
k = TValueReturn(n.(ReturnNode).getKind())
|
||||
or
|
||||
exists(ParamNode p, ParameterPosition pos |
|
||||
exists(ParamNode p, int pos |
|
||||
parameterValueFlowsToPreUpdate(p, n) and
|
||||
p.isParameterOf(_, pos) and
|
||||
k = TParamUpdate(pos)
|
||||
@@ -366,13 +352,11 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate parameterNode(Node p, DataFlowCallable c, ParameterPosition pos) {
|
||||
isParameterNode(p, c, pos)
|
||||
}
|
||||
predicate parameterNode(Node p, DataFlowCallable c, int pos) { isParameterNode(p, c, pos) }
|
||||
|
||||
cached
|
||||
predicate argumentNode(Node n, DataFlowCall call, ArgumentPosition pos) {
|
||||
isArgumentNode(n, call, pos)
|
||||
predicate argumentNode(Node n, DataFlowCall call, int pos) {
|
||||
n.(ArgumentNode).argumentOf(call, pos)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -390,12 +374,12 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p` is the parameter of a viable dispatch target of `call`,
|
||||
* and `p` has position `ppos`.
|
||||
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
|
||||
* The instance parameter is considered to have index `-1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate viableParam(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||
p.isParameterOf(viableCallableExt(call), ppos)
|
||||
private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallableExt(call), i)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -404,9 +388,9 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(ParameterPosition ppos |
|
||||
viableParam(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
exists(int i |
|
||||
viableParam(call, i, p) and
|
||||
arg.argumentOf(call, i) and
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
)
|
||||
}
|
||||
@@ -878,7 +862,7 @@ private module Cached {
|
||||
cached
|
||||
newtype TReturnKindExt =
|
||||
TValueReturn(ReturnKind kind) or
|
||||
TParamUpdate(ParameterPosition pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
||||
TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
||||
|
||||
cached
|
||||
newtype TBooleanOption =
|
||||
@@ -1070,9 +1054,9 @@ class ParamNode extends Node {
|
||||
|
||||
/**
|
||||
* Holds if this node is the parameter of callable `c` at the specified
|
||||
* position.
|
||||
* (zero-based) position.
|
||||
*/
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { parameterNode(this, c, pos) }
|
||||
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
|
||||
}
|
||||
|
||||
/** A data-flow node that represents a call argument. */
|
||||
@@ -1080,9 +1064,7 @@ class ArgNode extends Node {
|
||||
ArgNode() { argumentNode(this, _, _) }
|
||||
|
||||
/** Holds if this argument occurs at the given position in the given call. */
|
||||
final predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
argumentNode(this, call, pos)
|
||||
}
|
||||
final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1128,14 +1110,11 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
|
||||
}
|
||||
|
||||
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
|
||||
private ParameterPosition pos;
|
||||
private int pos;
|
||||
|
||||
ParamUpdateReturnKind() { this = TParamUpdate(pos) }
|
||||
|
||||
ParameterPosition getPosition() { result = pos }
|
||||
|
||||
pragma[nomagic]
|
||||
ArgumentPosition getAMatchingArgumentPosition() { parameterMatch(pos, result) }
|
||||
int getPosition() { result = pos }
|
||||
|
||||
override string toString() { result = "param update " + pos }
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ private import DataFlowDispatch
|
||||
private import DataFlowImplCommon
|
||||
private import ControlFlowReachability
|
||||
private import FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.csharp.dataflow.FlowSummary as FlowSummary
|
||||
private import semmle.code.csharp.dataflow.FlowSummary
|
||||
private import semmle.code.csharp.Conversion
|
||||
private import semmle.code.csharp.dataflow.internal.SsaImpl as SsaImpl
|
||||
private import semmle.code.csharp.ExprOrStmtParent
|
||||
@@ -22,14 +22,7 @@ private import semmle.code.csharp.frameworks.system.threading.Tasks
|
||||
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
|
||||
|
||||
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
|
||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
|
||||
exists(int i | pos = MkParameterPosition(i) and p.isParameterOf(c, i))
|
||||
}
|
||||
|
||||
/** Holds if `arg` is an `ArgumentNode` of `c` with position `pos`. */
|
||||
predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) {
|
||||
exists(int i | pos = MkArgumentPosition(i) and arg.argumentOf(c, i))
|
||||
}
|
||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) { p.isParameterOf(c, pos) }
|
||||
|
||||
abstract class NodeImpl extends Node {
|
||||
/** Do not call: use `getEnclosingCallable()` instead. */
|
||||
@@ -501,12 +494,9 @@ private predicate fieldOrPropertyStore(Expr e, Content c, Expr src, Expr q, bool
|
||||
f.isFieldLike() and
|
||||
f instanceof InstanceFieldOrProperty
|
||||
or
|
||||
exists(
|
||||
FlowSummary::SummarizedCallable callable,
|
||||
FlowSummaryImpl::Public::SummaryComponentStack input
|
||||
|
|
||||
exists(SummarizedCallable callable, FlowSummaryImpl::Public::SummaryComponentStack input |
|
||||
callable.propagatesFlow(input, _, _) and
|
||||
input.contains(FlowSummary::SummaryComponent::content(f.getContent()))
|
||||
input.contains(SummaryComponent::content(f.getContent()))
|
||||
)
|
||||
)
|
||||
|
|
||||
@@ -728,7 +718,7 @@ private module Cached {
|
||||
cfn.getElement() = fla.getQualifier()
|
||||
)
|
||||
} or
|
||||
TSummaryNode(FlowSummary::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) {
|
||||
TSummaryNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) {
|
||||
FlowSummaryImpl::Private::summaryNodeRange(c, state)
|
||||
} or
|
||||
TParamsArgumentNode(ControlFlow::Node callCfn) {
|
||||
@@ -759,8 +749,7 @@ private module Cached {
|
||||
newtype TContent =
|
||||
TFieldContent(Field f) { f.isUnboundDeclaration() } or
|
||||
TPropertyContent(Property p) { p.isUnboundDeclaration() } or
|
||||
TElementContent() or
|
||||
TSyntheticFieldContent(SyntheticField f)
|
||||
TElementContent()
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate commonSubTypeGeneral(DataFlowTypeOrUnifiable t1, RelevantDataFlowType t2) {
|
||||
@@ -805,13 +794,11 @@ predicate nodeIsHidden(Node n) {
|
||||
exists(Parameter p | p = n.(ParameterNode).getParameter() |
|
||||
not p.fromSource()
|
||||
or
|
||||
p.getCallable() instanceof FlowSummary::SummarizedCallable
|
||||
p.getCallable() instanceof SummarizedCallable
|
||||
)
|
||||
or
|
||||
n =
|
||||
TInstanceParameterNode(any(Callable c |
|
||||
not c.fromSource() or c instanceof FlowSummary::SummarizedCallable
|
||||
))
|
||||
TInstanceParameterNode(any(Callable c | not c.fromSource() or c instanceof SummarizedCallable))
|
||||
or
|
||||
n instanceof YieldReturnNode
|
||||
or
|
||||
@@ -1144,10 +1131,7 @@ private module ArgumentNodes {
|
||||
SummaryArgumentNode() { FlowSummaryImpl::Private::summaryArgumentNode(_, this, _) }
|
||||
|
||||
override predicate argumentOf(DataFlowCall call, int pos) {
|
||||
exists(ArgumentPosition apos |
|
||||
FlowSummaryImpl::Private::summaryArgumentNode(call, this, apos) and
|
||||
apos.getPosition() = pos
|
||||
)
|
||||
FlowSummaryImpl::Private::summaryArgumentNode(call, this, pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1437,7 +1421,7 @@ import OutNodes
|
||||
|
||||
/** A data-flow node used to model flow summaries. */
|
||||
private class SummaryNode extends NodeImpl, TSummaryNode {
|
||||
private FlowSummary::SummarizedCallable c;
|
||||
private SummarizedCallable c;
|
||||
private FlowSummaryImpl::Private::SummaryNodeState state;
|
||||
|
||||
SummaryNode() { this = TSummaryNode(c, state) }
|
||||
@@ -1780,10 +1764,6 @@ private class DataFlowNullType extends DataFlowType {
|
||||
}
|
||||
}
|
||||
|
||||
private class DataFlowUnknownType extends DataFlowType {
|
||||
DataFlowUnknownType() { this = Gvn::getGlobalValueNumber(any(UnknownType ut)) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
|
||||
* a node of type `t1` to a node of type `t2`.
|
||||
@@ -1803,10 +1783,6 @@ predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
|
||||
t1 instanceof Gvn::TypeParameterGvnType
|
||||
or
|
||||
t2 instanceof Gvn::TypeParameterGvnType
|
||||
or
|
||||
t1 instanceof DataFlowUnknownType
|
||||
or
|
||||
t2 instanceof DataFlowUnknownType
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2047,12 +2023,3 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
|
||||
predicate allowParameterReturnInSelf(ParameterNode p) {
|
||||
FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(p)
|
||||
}
|
||||
|
||||
/** A synthetic field. */
|
||||
abstract class SyntheticField extends string {
|
||||
bindingset[this]
|
||||
SyntheticField() { any() }
|
||||
|
||||
/** Gets the type of this synthetic field. */
|
||||
Type getType() { result instanceof ObjectType }
|
||||
}
|
||||
|
||||
@@ -224,18 +224,6 @@ class FieldContent extends Content, TFieldContent {
|
||||
deprecated override Gvn::GvnType getType() { result = Gvn::getGlobalValueNumber(f.getType()) }
|
||||
}
|
||||
|
||||
/** A reference to a synthetic field. */
|
||||
class SyntheticFieldContent extends Content, TSyntheticFieldContent {
|
||||
private SyntheticField f;
|
||||
|
||||
SyntheticFieldContent() { this = TSyntheticFieldContent(f) }
|
||||
|
||||
/** Gets the underlying synthetic field. */
|
||||
SyntheticField getField() { result = f }
|
||||
|
||||
override string toString() { result = "synthetic " + f.toString() }
|
||||
}
|
||||
|
||||
/** A reference to a property. */
|
||||
class PropertyContent extends Content, TPropertyContent {
|
||||
private Property p;
|
||||
|
||||
@@ -12,6 +12,7 @@ private import semmle.code.csharp.dataflow.CallContext
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPublic
|
||||
private import semmle.code.csharp.dataflow.FlowSummary
|
||||
private import semmle.code.csharp.dispatch.Dispatch
|
||||
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||
|
||||
|
||||
@@ -26,13 +26,9 @@ module Public {
|
||||
string toString() {
|
||||
exists(Content c | this = TContentSummaryComponent(c) and result = c.toString())
|
||||
or
|
||||
exists(ArgumentPosition pos |
|
||||
this = TParameterSummaryComponent(pos) and result = "parameter " + pos
|
||||
)
|
||||
exists(int i | this = TParameterSummaryComponent(i) and result = "parameter " + i)
|
||||
or
|
||||
exists(ParameterPosition pos |
|
||||
this = TArgumentSummaryComponent(pos) and result = "argument " + pos
|
||||
)
|
||||
exists(int i | this = TArgumentSummaryComponent(i) and result = "argument " + i)
|
||||
or
|
||||
exists(ReturnKind rk | this = TReturnSummaryComponent(rk) and result = "return (" + rk + ")")
|
||||
}
|
||||
@@ -43,11 +39,11 @@ module Public {
|
||||
/** Gets a summary component for content `c`. */
|
||||
SummaryComponent content(Content c) { result = TContentSummaryComponent(c) }
|
||||
|
||||
/** Gets a summary component for a parameter at position `pos`. */
|
||||
SummaryComponent parameter(ArgumentPosition pos) { result = TParameterSummaryComponent(pos) }
|
||||
/** Gets a summary component for parameter `i`. */
|
||||
SummaryComponent parameter(int i) { result = TParameterSummaryComponent(i) }
|
||||
|
||||
/** Gets a summary component for an argument at position `pos`. */
|
||||
SummaryComponent argument(ParameterPosition pos) { result = TArgumentSummaryComponent(pos) }
|
||||
/** Gets a summary component for argument `i`. */
|
||||
SummaryComponent argument(int i) { result = TArgumentSummaryComponent(i) }
|
||||
|
||||
/** Gets a summary component for a return of kind `rk`. */
|
||||
SummaryComponent return(ReturnKind rk) { result = TReturnSummaryComponent(rk) }
|
||||
@@ -124,10 +120,8 @@ module Public {
|
||||
result = TConsSummaryComponentStack(head, tail)
|
||||
}
|
||||
|
||||
/** Gets a singleton stack for an argument at position `pos`. */
|
||||
SummaryComponentStack argument(ParameterPosition pos) {
|
||||
result = singleton(SummaryComponent::argument(pos))
|
||||
}
|
||||
/** Gets a singleton stack for argument `i`. */
|
||||
SummaryComponentStack argument(int i) { result = singleton(SummaryComponent::argument(i)) }
|
||||
|
||||
/** Gets a singleton stack representing a return of kind `rk`. */
|
||||
SummaryComponentStack return(ReturnKind rk) { result = singleton(SummaryComponent::return(rk)) }
|
||||
@@ -143,15 +137,9 @@ module Public {
|
||||
or
|
||||
noComponentSpecificCsv(sc) and
|
||||
(
|
||||
exists(ArgumentPosition pos |
|
||||
sc = TParameterSummaryComponent(pos) and
|
||||
result = "Parameter[" + getArgumentPositionCsv(pos) + "]"
|
||||
)
|
||||
exists(int i | sc = TParameterSummaryComponent(i) and result = "Parameter[" + i + "]")
|
||||
or
|
||||
exists(ParameterPosition pos |
|
||||
sc = TArgumentSummaryComponent(pos) and
|
||||
result = "Argument[" + getParameterPositionCsv(pos) + "]"
|
||||
)
|
||||
exists(int i | sc = TArgumentSummaryComponent(i) and result = "Argument[" + i + "]")
|
||||
or
|
||||
sc = TReturnSummaryComponent(getReturnValueKind()) and result = "ReturnValue"
|
||||
)
|
||||
@@ -213,10 +201,10 @@ module Public {
|
||||
|
||||
/**
|
||||
* Holds if values stored inside `content` are cleared on objects passed as
|
||||
* arguments at position `pos` to this callable.
|
||||
* the `i`th argument to this callable.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate clearsContent(ParameterPosition pos, Content content) { none() }
|
||||
predicate clearsContent(int i, Content content) { none() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,11 +217,11 @@ module Private {
|
||||
|
||||
newtype TSummaryComponent =
|
||||
TContentSummaryComponent(Content c) or
|
||||
TParameterSummaryComponent(ArgumentPosition pos) or
|
||||
TArgumentSummaryComponent(ParameterPosition pos) or
|
||||
TParameterSummaryComponent(int i) { parameterPosition(i) } or
|
||||
TArgumentSummaryComponent(int i) { parameterPosition(i) } or
|
||||
TReturnSummaryComponent(ReturnKind rk)
|
||||
|
||||
private TParameterSummaryComponent thisParam() {
|
||||
private TSummaryComponent thisParam() {
|
||||
result = TParameterSummaryComponent(instanceParameterPosition())
|
||||
}
|
||||
|
||||
@@ -297,9 +285,9 @@ module Private {
|
||||
|
||||
/**
|
||||
* Holds if `c` has a flow summary from `input` to `arg`, where `arg`
|
||||
* writes to (contents of) arguments at position `pos`, and `c` has a
|
||||
* value-preserving flow summary from the arguments at position `pos`
|
||||
* to a return value (`return`).
|
||||
* writes to (contents of) the `i`th argument, and `c` has a
|
||||
* value-preserving flow summary from the `i`th argument to a return value
|
||||
* (`return`).
|
||||
*
|
||||
* In such a case, we derive flow from `input` to (contents of) the return
|
||||
* value.
|
||||
@@ -314,10 +302,10 @@ module Private {
|
||||
SummarizedCallable c, SummaryComponentStack input, SummaryComponentStack arg,
|
||||
SummaryComponentStack return, boolean preservesValue
|
||||
) {
|
||||
exists(ParameterPosition pos |
|
||||
exists(int i |
|
||||
summary(c, input, arg, preservesValue) and
|
||||
isContentOfArgument(arg, pos) and
|
||||
summary(c, SummaryComponentStack::argument(pos), return, true) and
|
||||
isContentOfArgument(arg, i) and
|
||||
summary(c, SummaryComponentStack::singleton(TArgumentSummaryComponent(i)), return, true) and
|
||||
return.bottom() = TReturnSummaryComponent(_)
|
||||
)
|
||||
}
|
||||
@@ -342,10 +330,10 @@ module Private {
|
||||
s.head() = TParameterSummaryComponent(_) and exists(s.tail())
|
||||
}
|
||||
|
||||
private predicate isContentOfArgument(SummaryComponentStack s, ParameterPosition pos) {
|
||||
s.head() = TContentSummaryComponent(_) and isContentOfArgument(s.tail(), pos)
|
||||
private predicate isContentOfArgument(SummaryComponentStack s, int i) {
|
||||
s.head() = TContentSummaryComponent(_) and isContentOfArgument(s.tail(), i)
|
||||
or
|
||||
s = SummaryComponentStack::argument(pos)
|
||||
s = TSingletonSummaryComponentStack(TArgumentSummaryComponent(i))
|
||||
}
|
||||
|
||||
private predicate outputState(SummarizedCallable c, SummaryComponentStack s) {
|
||||
@@ -376,8 +364,8 @@ module Private {
|
||||
private newtype TSummaryNodeState =
|
||||
TSummaryNodeInputState(SummaryComponentStack s) { inputState(_, s) } or
|
||||
TSummaryNodeOutputState(SummaryComponentStack s) { outputState(_, s) } or
|
||||
TSummaryNodeClearsContentState(ParameterPosition pos, boolean post) {
|
||||
any(SummarizedCallable sc).clearsContent(pos, _) and post in [false, true]
|
||||
TSummaryNodeClearsContentState(int i, boolean post) {
|
||||
any(SummarizedCallable sc).clearsContent(i, _) and post in [false, true]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -426,23 +414,21 @@ module Private {
|
||||
result = "to write: " + s
|
||||
)
|
||||
or
|
||||
exists(ParameterPosition pos, boolean post, string postStr |
|
||||
this = TSummaryNodeClearsContentState(pos, post) and
|
||||
exists(int i, boolean post, string postStr |
|
||||
this = TSummaryNodeClearsContentState(i, post) and
|
||||
(if post = true then postStr = " (post)" else postStr = "") and
|
||||
result = "clear: " + pos + postStr
|
||||
result = "clear: " + i + postStr
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `state` represents having read from a parameter at position
|
||||
* `pos` in `c`. In this case we are not synthesizing a data-flow node,
|
||||
* but instead assume that a relevant parameter node already exists.
|
||||
* Holds if `state` represents having read the `i`th argument for `c`. In this case
|
||||
* we are not synthesizing a data-flow node, but instead assume that a relevant
|
||||
* parameter node already exists.
|
||||
*/
|
||||
private predicate parameterReadState(
|
||||
SummarizedCallable c, SummaryNodeState state, ParameterPosition pos
|
||||
) {
|
||||
state.isInputState(c, SummaryComponentStack::argument(pos))
|
||||
private predicate parameterReadState(SummarizedCallable c, SummaryNodeState state, int i) {
|
||||
state.isInputState(c, SummaryComponentStack::argument(i))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -455,9 +441,9 @@ module Private {
|
||||
or
|
||||
state.isOutputState(c, _)
|
||||
or
|
||||
exists(ParameterPosition pos |
|
||||
c.clearsContent(pos, _) and
|
||||
state = TSummaryNodeClearsContentState(pos, _)
|
||||
exists(int i |
|
||||
c.clearsContent(i, _) and
|
||||
state = TSummaryNodeClearsContentState(i, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -466,9 +452,9 @@ module Private {
|
||||
exists(SummaryNodeState state | state.isInputState(c, s) |
|
||||
result = summaryNode(c, state)
|
||||
or
|
||||
exists(ParameterPosition pos |
|
||||
parameterReadState(c, state, pos) and
|
||||
result.(ParamNode).isParameterOf(c, pos)
|
||||
exists(int i |
|
||||
parameterReadState(c, state, i) and
|
||||
result.(ParamNode).isParameterOf(c, i)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -482,20 +468,20 @@ module Private {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a write targets `post`, which is a post-update node for a
|
||||
* parameter at position `pos` in `c`.
|
||||
* Holds if a write targets `post`, which is a post-update node for the `i`th
|
||||
* parameter of `c`.
|
||||
*/
|
||||
private predicate isParameterPostUpdate(Node post, SummarizedCallable c, ParameterPosition pos) {
|
||||
post = summaryNodeOutputState(c, SummaryComponentStack::argument(pos))
|
||||
private predicate isParameterPostUpdate(Node post, SummarizedCallable c, int i) {
|
||||
post = summaryNodeOutputState(c, SummaryComponentStack::argument(i))
|
||||
}
|
||||
|
||||
/** Holds if a parameter node at position `pos` is required for `c`. */
|
||||
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
|
||||
parameterReadState(c, _, pos)
|
||||
/** Holds if a parameter node is required for the `i`th parameter of `c`. */
|
||||
predicate summaryParameterNodeRange(SummarizedCallable c, int i) {
|
||||
parameterReadState(c, _, i)
|
||||
or
|
||||
isParameterPostUpdate(_, c, pos)
|
||||
isParameterPostUpdate(_, c, i)
|
||||
or
|
||||
c.clearsContent(pos, _)
|
||||
c.clearsContent(i, _)
|
||||
}
|
||||
|
||||
private predicate callbackOutput(
|
||||
@@ -507,10 +493,10 @@ module Private {
|
||||
}
|
||||
|
||||
private predicate callbackInput(
|
||||
SummarizedCallable c, SummaryComponentStack s, Node receiver, ArgumentPosition pos
|
||||
SummarizedCallable c, SummaryComponentStack s, Node receiver, int i
|
||||
) {
|
||||
any(SummaryNodeState state).isOutputState(c, s) and
|
||||
s.head() = TParameterSummaryComponent(pos) and
|
||||
s.head() = TParameterSummaryComponent(i) and
|
||||
receiver = summaryNodeInputState(c, s.drop(1))
|
||||
}
|
||||
|
||||
@@ -561,17 +547,17 @@ module Private {
|
||||
result = getReturnType(c, rk)
|
||||
)
|
||||
or
|
||||
exists(ArgumentPosition pos | head = TParameterSummaryComponent(pos) |
|
||||
exists(int i | head = TParameterSummaryComponent(i) |
|
||||
result =
|
||||
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||
s.drop(1))), pos)
|
||||
s.drop(1))), i)
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(SummarizedCallable c, ParameterPosition pos, ParamNode p |
|
||||
n = summaryNode(c, TSummaryNodeClearsContentState(pos, false)) and
|
||||
p.isParameterOf(c, pos) and
|
||||
exists(SummarizedCallable c, int i, ParamNode p |
|
||||
n = summaryNode(c, TSummaryNodeClearsContentState(i, false)) and
|
||||
p.isParameterOf(c, i) and
|
||||
result = getNodeType(p)
|
||||
)
|
||||
}
|
||||
@@ -585,10 +571,10 @@ module Private {
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if summary node `arg` is at position `pos` in the call `c`. */
|
||||
predicate summaryArgumentNode(DataFlowCall c, Node arg, ArgumentPosition pos) {
|
||||
/** Holds if summary node `arg` is the `i`th argument of call `c`. */
|
||||
predicate summaryArgumentNode(DataFlowCall c, Node arg, int i) {
|
||||
exists(SummarizedCallable callable, SummaryComponentStack s, Node receiver |
|
||||
callbackInput(callable, s, receiver, pos) and
|
||||
callbackInput(callable, s, receiver, i) and
|
||||
arg = summaryNodeOutputState(callable, s) and
|
||||
c = summaryDataFlowCall(receiver)
|
||||
)
|
||||
@@ -596,12 +582,12 @@ module Private {
|
||||
|
||||
/** Holds if summary node `post` is a post-update node with pre-update node `pre`. */
|
||||
predicate summaryPostUpdateNode(Node post, Node pre) {
|
||||
exists(SummarizedCallable c, ParameterPosition pos |
|
||||
isParameterPostUpdate(post, c, pos) and
|
||||
pre.(ParamNode).isParameterOf(c, pos)
|
||||
exists(SummarizedCallable c, int i |
|
||||
isParameterPostUpdate(post, c, i) and
|
||||
pre.(ParamNode).isParameterOf(c, i)
|
||||
or
|
||||
pre = summaryNode(c, TSummaryNodeClearsContentState(pos, false)) and
|
||||
post = summaryNode(c, TSummaryNodeClearsContentState(pos, true))
|
||||
pre = summaryNode(c, TSummaryNodeClearsContentState(i, false)) and
|
||||
post = summaryNode(c, TSummaryNodeClearsContentState(i, true))
|
||||
)
|
||||
or
|
||||
exists(SummarizedCallable callable, SummaryComponentStack s |
|
||||
@@ -624,13 +610,13 @@ module Private {
|
||||
* node, and back out to `p`.
|
||||
*/
|
||||
predicate summaryAllowParameterReturnInSelf(ParamNode p) {
|
||||
exists(SummarizedCallable c, ParameterPosition ppos | p.isParameterOf(c, ppos) |
|
||||
c.clearsContent(ppos, _)
|
||||
exists(SummarizedCallable c, int i | p.isParameterOf(c, i) |
|
||||
c.clearsContent(i, _)
|
||||
or
|
||||
exists(SummaryComponentStack inputContents, SummaryComponentStack outputContents |
|
||||
summary(c, inputContents, outputContents, _) and
|
||||
inputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(ppos)) and
|
||||
outputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(ppos))
|
||||
inputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(i)) and
|
||||
outputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(i))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -655,9 +641,9 @@ module Private {
|
||||
preservesValue = false and not summary(c, inputContents, outputContents, true)
|
||||
)
|
||||
or
|
||||
exists(SummarizedCallable c, ParameterPosition pos |
|
||||
pred.(ParamNode).isParameterOf(c, pos) and
|
||||
succ = summaryNode(c, TSummaryNodeClearsContentState(pos, _)) and
|
||||
exists(SummarizedCallable c, int i |
|
||||
pred.(ParamNode).isParameterOf(c, i) and
|
||||
succ = summaryNode(c, TSummaryNodeClearsContentState(i, _)) and
|
||||
preservesValue = true
|
||||
)
|
||||
}
|
||||
@@ -706,20 +692,12 @@ module Private {
|
||||
* node where field `b` is cleared).
|
||||
*/
|
||||
predicate summaryClearsContent(Node n, Content c) {
|
||||
exists(SummarizedCallable sc, ParameterPosition pos |
|
||||
n = summaryNode(sc, TSummaryNodeClearsContentState(pos, true)) and
|
||||
sc.clearsContent(pos, c)
|
||||
exists(SummarizedCallable sc, int i |
|
||||
n = summaryNode(sc, TSummaryNodeClearsContentState(i, true)) and
|
||||
sc.clearsContent(i, c)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate viableParam(
|
||||
DataFlowCall call, SummarizedCallable sc, ParameterPosition ppos, ParamNode p
|
||||
) {
|
||||
p.isParameterOf(sc, ppos) and
|
||||
sc = viableCallable(call)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared inside a
|
||||
* callable to which `arg` is an argument.
|
||||
@@ -728,18 +706,18 @@ module Private {
|
||||
* `arg` (see comment for `summaryClearsContent`).
|
||||
*/
|
||||
predicate summaryClearsContentArg(ArgNode arg, Content c) {
|
||||
exists(DataFlowCall call, SummarizedCallable sc, ParameterPosition ppos |
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
viableParam(call, sc, ppos, _) and
|
||||
sc.clearsContent(ppos, c)
|
||||
exists(DataFlowCall call, int i |
|
||||
viableCallable(call).(SummarizedCallable).clearsContent(i, c) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private ParamNode summaryArgParam(ArgNode arg, ReturnKindExt rk, OutNodeExt out) {
|
||||
exists(DataFlowCall call, ParameterPosition ppos, SummarizedCallable sc |
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
viableParam(call, sc, ppos, result) and
|
||||
exists(DataFlowCall call, int pos, SummarizedCallable callable |
|
||||
arg.argumentOf(call, pos) and
|
||||
viableCallable(call) = callable and
|
||||
result.isParameterOf(callable, pos) and
|
||||
out = rk.getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
@@ -817,33 +795,39 @@ module Private {
|
||||
}
|
||||
|
||||
/** Holds if specification component `c` parses as parameter `n`. */
|
||||
predicate parseParam(string c, ArgumentPosition pos) {
|
||||
predicate parseParam(string c, int n) {
|
||||
specSplit(_, c, _) and
|
||||
exists(string body |
|
||||
body = c.regexpCapture("Parameter\\[([^\\]]*)\\]", 1) and
|
||||
pos = parseParamBody(body)
|
||||
(
|
||||
c.regexpCapture("Parameter\\[([-0-9]+)\\]", 1).toInt() = n
|
||||
or
|
||||
exists(int n1, int n2 |
|
||||
c.regexpCapture("Parameter\\[([-0-9]+)\\.\\.([0-9]+)\\]", 1).toInt() = n1 and
|
||||
c.regexpCapture("Parameter\\[([-0-9]+)\\.\\.([0-9]+)\\]", 2).toInt() = n2 and
|
||||
n = [n1 .. n2]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if specification component `c` parses as argument `n`. */
|
||||
predicate parseArg(string c, ParameterPosition pos) {
|
||||
predicate parseArg(string c, int n) {
|
||||
specSplit(_, c, _) and
|
||||
exists(string body |
|
||||
body = c.regexpCapture("Argument\\[([^\\]]*)\\]", 1) and
|
||||
pos = parseArgBody(body)
|
||||
(
|
||||
c.regexpCapture("Argument\\[([-0-9]+)\\]", 1).toInt() = n
|
||||
or
|
||||
exists(int n1, int n2 |
|
||||
c.regexpCapture("Argument\\[([-0-9]+)\\.\\.([0-9]+)\\]", 1).toInt() = n1 and
|
||||
c.regexpCapture("Argument\\[([-0-9]+)\\.\\.([0-9]+)\\]", 2).toInt() = n2 and
|
||||
n = [n1 .. n2]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private SummaryComponent interpretComponent(string c) {
|
||||
specSplit(_, c, _) and
|
||||
(
|
||||
exists(ParameterPosition pos |
|
||||
parseArg(c, pos) and result = SummaryComponent::argument(pos)
|
||||
)
|
||||
exists(int pos | parseArg(c, pos) and result = SummaryComponent::argument(pos))
|
||||
or
|
||||
exists(ArgumentPosition pos |
|
||||
parseParam(c, pos) and result = SummaryComponent::parameter(pos)
|
||||
)
|
||||
exists(int pos | parseParam(c, pos) and result = SummaryComponent::parameter(pos))
|
||||
or
|
||||
c = "ReturnValue" and result = SummaryComponent::return(getReturnValueKind())
|
||||
or
|
||||
@@ -950,18 +934,14 @@ module Private {
|
||||
interpretOutput(output, idx + 1, ref, mid) and
|
||||
specSplit(output, c, idx)
|
||||
|
|
||||
exists(ArgumentPosition apos, ParameterPosition ppos |
|
||||
node.asNode().(PostUpdateNode).getPreUpdateNode().(ArgNode).argumentOf(mid.asCall(), apos) and
|
||||
parameterMatch(ppos, apos)
|
||||
exists(int pos |
|
||||
node.asNode().(PostUpdateNode).getPreUpdateNode().(ArgNode).argumentOf(mid.asCall(), pos)
|
||||
|
|
||||
c = "Argument" or parseArg(c, ppos)
|
||||
c = "Argument" or parseArg(c, pos)
|
||||
)
|
||||
or
|
||||
exists(ArgumentPosition apos, ParameterPosition ppos |
|
||||
node.asNode().(ParamNode).isParameterOf(mid.asCallable(), ppos) and
|
||||
parameterMatch(ppos, apos)
|
||||
|
|
||||
c = "Parameter" or parseParam(c, apos)
|
||||
exists(int pos | node.asNode().(ParamNode).isParameterOf(mid.asCallable(), pos) |
|
||||
c = "Parameter" or parseParam(c, pos)
|
||||
)
|
||||
or
|
||||
c = "ReturnValue" and
|
||||
@@ -980,11 +960,8 @@ module Private {
|
||||
interpretInput(input, idx + 1, ref, mid) and
|
||||
specSplit(input, c, idx)
|
||||
|
|
||||
exists(ArgumentPosition apos, ParameterPosition ppos |
|
||||
node.asNode().(ArgNode).argumentOf(mid.asCall(), apos) and
|
||||
parameterMatch(ppos, apos)
|
||||
|
|
||||
c = "Argument" or parseArg(c, ppos)
|
||||
exists(int pos | node.asNode().(ArgNode).argumentOf(mid.asCall(), pos) |
|
||||
c = "Argument" or parseArg(c, pos)
|
||||
)
|
||||
or
|
||||
exists(ReturnNodeExt ret |
|
||||
@@ -1140,9 +1117,9 @@ module Private {
|
||||
b.asCall() = summaryDataFlowCall(a.asNode()) and
|
||||
value = "receiver"
|
||||
or
|
||||
exists(ArgumentPosition pos |
|
||||
summaryArgumentNode(b.asCall(), a.asNode(), pos) and
|
||||
value = "argument (" + pos + ")"
|
||||
exists(int i |
|
||||
summaryArgumentNode(b.asCall(), a.asNode(), i) and
|
||||
value = "argument (" + i + ")"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,11 @@ private import FlowSummaryImpl::Public
|
||||
private import semmle.code.csharp.Unification
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
|
||||
/** Holds is `i` is a valid parameter position. */
|
||||
predicate parameterPosition(int i) { i in [-1 .. any(Parameter p).getPosition()] }
|
||||
|
||||
/** Gets the parameter position of the instance parameter. */
|
||||
ArgumentPosition instanceParameterPosition() { none() } // disables implicit summary flow to `this` for callbacks
|
||||
int instanceParameterPosition() { none() } // disables implicit summary flow to `this` for callbacks
|
||||
|
||||
/** Gets the synthesized summary data-flow node for the given values. */
|
||||
Node summaryNode(SummarizedCallable c, SummaryNodeState state) { result = TSummaryNode(c, state) }
|
||||
@@ -29,8 +32,6 @@ DataFlowType getContentType(Content c) {
|
||||
or
|
||||
t = c.(PropertyContent).getProperty().getType()
|
||||
or
|
||||
t = c.(SyntheticFieldContent).getField().getType()
|
||||
or
|
||||
c instanceof ElementContent and
|
||||
t instanceof ObjectType // we don't know what the actual element type is
|
||||
)
|
||||
@@ -60,14 +61,13 @@ DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the parameter matching arguments at position `pos` in a
|
||||
* synthesized call that targets a callback of type `t`.
|
||||
* Gets the type of the `i`th parameter in a synthesized call that targets a
|
||||
* callback of type `t`.
|
||||
*/
|
||||
DataFlowType getCallbackParameterType(DataFlowType t, ArgumentPosition pos) {
|
||||
DataFlowType getCallbackParameterType(DataFlowType t, int i) {
|
||||
exists(SystemLinqExpressions::DelegateExtType dt |
|
||||
t = Gvn::getGlobalValueNumber(dt) and
|
||||
result =
|
||||
Gvn::getGlobalValueNumber(dt.getDelegateType().getParameter(pos.getPosition()).getType())
|
||||
result = Gvn::getGlobalValueNumber(dt.getDelegateType().getParameter(i).getType())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -136,11 +136,6 @@ SummaryComponent interpretComponentSpecific(string c) {
|
||||
c.regexpCapture("Property\\[(.+)\\]", 1) = p.getQualifiedName() and
|
||||
result = SummaryComponent::content(any(PropertyContent pc | pc.getProperty() = p))
|
||||
)
|
||||
or
|
||||
exists(SyntheticField f |
|
||||
c.regexpCapture("SyntheticField\\[(.+)\\]", 1) = f and
|
||||
result = SummaryComponent::content(any(SyntheticFieldContent sfc | sfc.getField() = f))
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the textual representation of the content in the format used for flow summaries. */
|
||||
@@ -150,8 +145,6 @@ private string getContentSpecificCsv(Content c) {
|
||||
exists(Field f | c = TFieldContent(f) and result = "Field[" + f.getQualifiedName() + "]")
|
||||
or
|
||||
exists(Property p | c = TPropertyContent(p) and result = "Property[" + p.getQualifiedName() + "]")
|
||||
or
|
||||
exists(SyntheticField f | c = TSyntheticFieldContent(f) and result = "SyntheticField[" + f + "]")
|
||||
}
|
||||
|
||||
/** Gets the textual representation of a summary component in the format used for flow summaries. */
|
||||
@@ -165,12 +158,6 @@ string getComponentSpecificCsv(SummaryComponent sc) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the textual representation of a parameter position in the format used for flow summaries. */
|
||||
string getParameterPositionCsv(ParameterPosition pos) { result = pos.toString() }
|
||||
|
||||
/** Gets the textual representation of an argument position in the format used for flow summaries. */
|
||||
string getArgumentPositionCsv(ArgumentPosition pos) { result = pos.toString() }
|
||||
|
||||
class SourceOrSinkElement = Element;
|
||||
|
||||
/** Gets the return kind corresponding to specification `"ReturnValue"`. */
|
||||
@@ -236,22 +223,3 @@ predicate interpretInputSpecific(string c, InterpretNode mid, InterpretNode n) {
|
||||
a.getUnboundDeclaration() = mid.asElement()
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[s]
|
||||
private int parsePosition(string s) {
|
||||
result = s.regexpCapture("([-0-9]+)", 1).toInt()
|
||||
or
|
||||
exists(int n1, int n2 |
|
||||
s.regexpCapture("([-0-9]+)\\.\\.([0-9]+)", 1).toInt() = n1 and
|
||||
s.regexpCapture("([-0-9]+)\\.\\.([0-9]+)", 2).toInt() = n2 and
|
||||
result in [n1 .. n2]
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the argument position obtained by parsing `X` in `Parameter[X]`. */
|
||||
bindingset[s]
|
||||
ArgumentPosition parseParamBody(string s) { result.getPosition() = parsePosition(s) }
|
||||
|
||||
/** Gets the parameter position obtained by parsing `X` in `Argument[X]`. */
|
||||
bindingset[s]
|
||||
ParameterPosition parseArgBody(string s) { result.getPosition() = parsePosition(s) }
|
||||
|
||||
@@ -8,11 +8,24 @@ import csharp
|
||||
/**
|
||||
* A callable that can be overridden or implemented.
|
||||
*
|
||||
* Unlike the class `Overridable`, this class only includes callables that
|
||||
* can actually be overriden/implemented.
|
||||
* Unlike the class `Virtualizable`, this class only includes methods that
|
||||
* can actually be overriden/implemented. Additionally, this class includes
|
||||
* accessors whose declarations can actually be overridden/implemented.
|
||||
*/
|
||||
class OverridableCallable extends Callable, Overridable {
|
||||
OverridableCallable() { this.isOverridableOrImplementable() }
|
||||
class OverridableCallable extends Callable {
|
||||
OverridableCallable() {
|
||||
this.(Method).isOverridableOrImplementable() or
|
||||
this.(Accessor).getDeclaration().isOverridableOrImplementable()
|
||||
}
|
||||
|
||||
/** Gets a callable that immediately overrides this callable, if any. */
|
||||
Callable getAnOverrider() { none() }
|
||||
|
||||
/**
|
||||
* Gets a callable that immediately implements this interface callable,
|
||||
* if any.
|
||||
*/
|
||||
Callable getAnImplementor(ValueOrRefType t) { none() }
|
||||
|
||||
/**
|
||||
* Gets a callable that immediately implements this interface member,
|
||||
@@ -55,6 +68,40 @@ class OverridableCallable extends Callable, Overridable {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a callable that (transitively) implements this interface callable,
|
||||
* if any. That is, either this interface callable is immediately implemented
|
||||
* by the result, or the result overrides (transitively) another callable that
|
||||
* immediately implements this interface callable.
|
||||
*
|
||||
* Note that this is generally *not* equivalent with
|
||||
*
|
||||
* ```ql
|
||||
* result = getAnImplementor()
|
||||
* or
|
||||
* result = getAnImplementor().(OverridableCallable).getAnOverrider+()`
|
||||
* ```
|
||||
*
|
||||
* as the example below illustrates:
|
||||
*
|
||||
* ```csharp
|
||||
* interface I { void M(); }
|
||||
*
|
||||
* class A { public virtual void M() { } }
|
||||
*
|
||||
* class B : A, I { }
|
||||
*
|
||||
* class C : A { public override void M() }
|
||||
*
|
||||
* class D : B { public override void M() }
|
||||
* ```
|
||||
*
|
||||
* If this callable is `I.M` then `A.M = getAnUltimateImplementor() ` and
|
||||
* `D.M = getAnUltimateImplementor()`. However, it is *not* the case that
|
||||
* `C.M = getAnUltimateImplementor()`, because `C` is not a sub type of `I`.
|
||||
*/
|
||||
Callable getAnUltimateImplementor() { none() }
|
||||
|
||||
/**
|
||||
* Gets a callable that overrides (transitively) another callable that
|
||||
* implements this interface callable, if any.
|
||||
@@ -163,10 +210,73 @@ class OverridableCallable extends Callable, Overridable {
|
||||
}
|
||||
|
||||
/** An overridable method. */
|
||||
deprecated class OverridableMethod extends Method, OverridableCallable { }
|
||||
class OverridableMethod extends Method, OverridableCallable {
|
||||
override Method getAnOverrider() { result = Method.super.getAnOverrider() }
|
||||
|
||||
override Method getAnImplementor(ValueOrRefType t) { result = Method.super.getAnImplementor(t) }
|
||||
|
||||
override Method getAnUltimateImplementor() { result = Method.super.getAnUltimateImplementor() }
|
||||
|
||||
override Method getInherited(ValueOrRefType t) {
|
||||
result = OverridableCallable.super.getInherited(t)
|
||||
}
|
||||
|
||||
override Method getAnOverrider(ValueOrRefType t) {
|
||||
result = OverridableCallable.super.getAnOverrider(t)
|
||||
}
|
||||
}
|
||||
|
||||
/** An overridable accessor. */
|
||||
deprecated class OverridableAccessor extends Accessor, OverridableCallable { }
|
||||
class OverridableAccessor extends Accessor, OverridableCallable {
|
||||
override Accessor getAnOverrider() { overrides(result, this) }
|
||||
|
||||
override Accessor getAnImplementor(ValueOrRefType t) {
|
||||
exists(Virtualizable implementor, int kind |
|
||||
this.getAnImplementorAux(t, implementor, kind) and
|
||||
result.getDeclaration() = implementor and
|
||||
getAccessorKind(result) = kind
|
||||
)
|
||||
}
|
||||
|
||||
// predicate folding to get proper join order
|
||||
private predicate getAnImplementorAux(ValueOrRefType t, Virtualizable implementor, int kind) {
|
||||
exists(Virtualizable implementee |
|
||||
implementee = this.getDeclaration() and
|
||||
kind = getAccessorKind(this) and
|
||||
implementor = implementee.getAnImplementor(t)
|
||||
)
|
||||
}
|
||||
|
||||
override Accessor getAnUltimateImplementor() {
|
||||
exists(Virtualizable implementor, int kind |
|
||||
this.getAnUltimateImplementorAux(implementor, kind) and
|
||||
result.getDeclaration() = implementor and
|
||||
getAccessorKind(result) = kind
|
||||
)
|
||||
}
|
||||
|
||||
// predicate folding to get proper join order
|
||||
private predicate getAnUltimateImplementorAux(Virtualizable implementor, int kind) {
|
||||
exists(Virtualizable implementee |
|
||||
implementee = this.getDeclaration() and
|
||||
kind = getAccessorKind(this) and
|
||||
implementor = implementee.getAnUltimateImplementor()
|
||||
)
|
||||
}
|
||||
|
||||
override Accessor getInherited(ValueOrRefType t) {
|
||||
result = OverridableCallable.super.getInherited(t)
|
||||
}
|
||||
|
||||
override Accessor getAnOverrider(ValueOrRefType t) {
|
||||
result = OverridableCallable.super.getAnOverrider(t)
|
||||
}
|
||||
}
|
||||
|
||||
private int getAccessorKind(Accessor a) {
|
||||
accessors(a, result, _, _, _) or
|
||||
event_accessors(a, -result, _, _, _)
|
||||
}
|
||||
|
||||
/** An unbound type. */
|
||||
class UnboundDeclarationType extends Type {
|
||||
|
||||
@@ -996,7 +996,7 @@ class QualifiableExpr extends Expr, @qualifiable_expr {
|
||||
*/
|
||||
predicate targetIsOverridableOrImplementable() {
|
||||
not this.getQualifier() instanceof BaseAccess and
|
||||
this.getQualifiedDeclaration().(Overridable).isOverridableOrImplementable()
|
||||
this.getQualifiedDeclaration().(Virtualizable).isOverridableOrImplementable()
|
||||
}
|
||||
|
||||
/** Holds if this expression has a conditional qualifier `?.` */
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||
private import semmle.code.csharp.dataflow.LibraryTypeDataFlow
|
||||
|
||||
/** Definitions relating to the `Json.NET` package. */
|
||||
module JsonNET {
|
||||
@@ -31,9 +31,15 @@ module JsonNET {
|
||||
}
|
||||
|
||||
/** The class `Newtonsoft.Json.JsonConvert`. */
|
||||
class JsonConvertClass extends JsonClass {
|
||||
class JsonConvertClass extends JsonClass, LibraryTypeDataFlow {
|
||||
JsonConvertClass() { this.hasName("JsonConvert") }
|
||||
|
||||
/** Gets a `ToString` method. */
|
||||
private Method getAToStringMethod() {
|
||||
result = this.getAMethod("ToString") and
|
||||
result.isStatic()
|
||||
}
|
||||
|
||||
/** Gets a `Deserialize` method. */
|
||||
Method getADeserializeMethod() {
|
||||
result = this.getAMethod() and
|
||||
@@ -45,73 +51,39 @@ module JsonNET {
|
||||
result = this.getAMethod() and
|
||||
result.getName().matches("Serialize%")
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `Newtonsoft.Json.JsonConvert`. */
|
||||
private class JsonConvertClassFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeAnonymousType<>;(System.String,T);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeAnonymousType<>;(System.String,T,Newtonsoft.Json.JsonSerializerSettings);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeObject;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeObject;(System.String,Newtonsoft.Json.JsonSerializerSettings);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeObject;(System.String,System.Type);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeObject;(System.String,System.Type,Newtonsoft.Json.JsonConverter[]);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeObject;(System.String,System.Type,Newtonsoft.Json.JsonSerializerSettings);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeObject<>;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeObject<>;(System.String,Newtonsoft.Json.JsonConverter[]);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeObject<>;(System.String,Newtonsoft.Json.JsonSerializerSettings);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeXNode;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeXNode;(System.String,System.String);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeXNode;(System.String,System.String,System.Boolean);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeXNode;(System.String,System.String,System.Boolean,System.Boolean);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeXmlNode;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeXmlNode;(System.String,System.String);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeXmlNode;(System.String,System.String,System.Boolean);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;DeserializeXmlNode;(System.String,System.String,System.Boolean,System.Boolean);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;PopulateObject;(System.String,System.Object);;Argument[0];Argument[1];taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;PopulateObject;(System.String,System.Object,Newtonsoft.Json.JsonSerializerSettings);;Argument[0];Argument[1];taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;SerializeObject;(System.Object);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;SerializeObject;(System.Object,Newtonsoft.Json.Formatting);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;SerializeObject;(System.Object,Newtonsoft.Json.Formatting,Newtonsoft.Json.JsonConverter[]);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;SerializeObject;(System.Object,Newtonsoft.Json.Formatting,Newtonsoft.Json.JsonSerializerSettings);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;SerializeObject;(System.Object,Newtonsoft.Json.JsonConverter[]);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;SerializeObject;(System.Object,Newtonsoft.Json.JsonSerializerSettings);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;SerializeObject;(System.Object,System.Type,Newtonsoft.Json.Formatting,Newtonsoft.Json.JsonSerializerSettings);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;SerializeObject;(System.Object,System.Type,Newtonsoft.Json.JsonSerializerSettings);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;SerializeXNode;(System.Xml.Linq.XObject);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;SerializeXNode;(System.Xml.Linq.XObject,Newtonsoft.Json.Formatting);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;SerializeXNode;(System.Xml.Linq.XObject,Newtonsoft.Json.Formatting,System.Boolean);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;SerializeXmlNode;(System.Xml.XmlNode);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;SerializeXmlNode;(System.Xml.XmlNode,Newtonsoft.Json.Formatting);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;SerializeXmlNode;(System.Xml.XmlNode,Newtonsoft.Json.Formatting,System.Boolean);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.Boolean);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.Byte);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.Char);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.DateTime);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.DateTime,Newtonsoft.Json.DateFormatHandling,Newtonsoft.Json.DateTimeZoneHandling);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.DateTimeOffset);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.DateTimeOffset,Newtonsoft.Json.DateFormatHandling);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.Decimal);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.Double);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.Enum);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.Guid);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.Int16);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.Int32);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.Int64);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.Object);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.SByte);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.Single);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.String,System.Char);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.String,System.Char,Newtonsoft.Json.StringEscapeHandling);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.TimeSpan);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.UInt16);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.UInt32);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.UInt64);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonConvert;false;ToString;(System.Uri);;Argument[0];ReturnValue;taint",
|
||||
]
|
||||
private Method getAPopulateMethod() {
|
||||
result = this.getAMethod() and
|
||||
result.getName().matches("Populate%")
|
||||
}
|
||||
|
||||
override predicate callableFlow(
|
||||
CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c,
|
||||
boolean preservesValue
|
||||
) {
|
||||
// ToString methods
|
||||
c = this.getAToStringMethod() and
|
||||
preservesValue = false and
|
||||
source = any(CallableFlowSourceArg arg | arg.getArgumentIndex() = 0) and
|
||||
sink instanceof CallableFlowSinkReturn
|
||||
or
|
||||
// Deserialize methods
|
||||
c = this.getADeserializeMethod() and
|
||||
preservesValue = false and
|
||||
source = any(CallableFlowSourceArg arg | arg.getArgumentIndex() = 0) and
|
||||
sink instanceof CallableFlowSinkReturn
|
||||
or
|
||||
// Serialize methods
|
||||
c = this.getASerializeMethod() and
|
||||
preservesValue = false and
|
||||
source = any(CallableFlowSourceArg arg | arg.getArgumentIndex() = 0) and
|
||||
sink instanceof CallableFlowSinkReturn
|
||||
or
|
||||
// Populate methods
|
||||
c = this.getAPopulateMethod() and
|
||||
preservesValue = false and
|
||||
source = any(CallableFlowSourceArg arg | arg.getArgumentIndex() = 0) and
|
||||
sink = any(CallableFlowSinkArg arg | arg.getArgumentIndex() = 1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +137,7 @@ module JsonNET {
|
||||
}
|
||||
|
||||
/** The class `NewtonSoft.Json.JsonSerializer`. */
|
||||
class JsonSerializerClass extends JsonClass {
|
||||
class JsonSerializerClass extends JsonClass, LibraryTypeDataFlow {
|
||||
JsonSerializerClass() { this.hasName("JsonSerializer") }
|
||||
|
||||
/** Gets the method for `JsonSerializer.Serialize`. */
|
||||
@@ -173,21 +145,22 @@ module JsonNET {
|
||||
|
||||
/** Gets the method for `JsonSerializer.Deserialize`. */
|
||||
Method getDeserializeMethod() { result = this.getAMethod("Deserialize") }
|
||||
}
|
||||
|
||||
/** Data flow for `NewtonSoft.Json.JSonSerializer`. */
|
||||
private class JsonSerializerClassFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"Newtonsoft.Json;JsonSerializer;false;Deserialize;(Newtonsoft.Json.JsonReader);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonSerializer;false;Deserialize;(Newtonsoft.Json.JsonReader,System.Type);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonSerializer;false;Deserialize;(System.IO.TextReader,System.Type);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json;JsonSerializer;false;Serialize;(Newtonsoft.Json.JsonWriter,System.Object);;Argument[1];Argument[0];taint",
|
||||
"Newtonsoft.Json;JsonSerializer;false;Serialize;(Newtonsoft.Json.JsonWriter,System.Object,System.Type);;Argument[1];Argument[0];taint",
|
||||
"Newtonsoft.Json;JsonSerializer;false;Serialize;(System.IO.TextWriter,System.Object);;Argument[1];Argument[0];taint",
|
||||
"Newtonsoft.Json;JsonSerializer;false;Serialize;(System.IO.TextWriter,System.Object,System.Type);;Argument[1];Argument[0];taint"
|
||||
]
|
||||
override predicate callableFlow(
|
||||
CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c,
|
||||
boolean preservesValue
|
||||
) {
|
||||
// Serialize
|
||||
c = this.getSerializeMethod() and
|
||||
preservesValue = false and
|
||||
source = any(CallableFlowSourceArg arg | arg.getArgumentIndex() = 1) and
|
||||
sink = any(CallableFlowSinkArg arg | arg.getArgumentIndex() = 0)
|
||||
or
|
||||
// Deserialize
|
||||
c = this.getDeserializeMethod() and
|
||||
preservesValue = false and
|
||||
source = any(CallableFlowSourceArg arg | arg.getArgumentIndex() = 0) and
|
||||
sink instanceof CallableFlowSinkReturn
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,39 +196,46 @@ module JsonNET {
|
||||
LinqClass() { this.getDeclaringNamespace() instanceof LinqNamespace }
|
||||
}
|
||||
|
||||
/** Data flow for `Newtonsoft.Json.Linq.JToken`. */
|
||||
private class JTokenClassFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"Newtonsoft.Json.Linq;JToken;false;SelectToken;(System.String);;Argument[-1];ReturnValue;taint",
|
||||
"Newtonsoft.Json.Linq;JToken;false;SelectToken;(System.String,Newtonsoft.Json.Linq.JsonSelectSettings);;Argument[-1];ReturnValue;taint",
|
||||
"Newtonsoft.Json.Linq;JToken;false;SelectToken;(System.String,System.Boolean);;Argument[-1];ReturnValue;taint",
|
||||
"Newtonsoft.Json.Linq;JToken;false;ToString;();;Argument[-1];ReturnValue;taint",
|
||||
"Newtonsoft.Json.Linq;JToken;false;ToString;(Newtonsoft.Json.Formatting,Newtonsoft.Json.JsonConverter[]);;Argument[-1];ReturnValue;taint",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/** The `NewtonSoft.Json.Linq.JObject` class. */
|
||||
class JObjectClass extends LinqClass {
|
||||
class JObjectClass extends LinqClass, LibraryTypeDataFlow {
|
||||
JObjectClass() { this.hasName("JObject") }
|
||||
|
||||
override predicate callableFlow(
|
||||
CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c,
|
||||
boolean preservesValue
|
||||
) {
|
||||
// ToString method
|
||||
c = this.getAMethod("ToString") and
|
||||
source instanceof CallableFlowSourceQualifier and
|
||||
sink instanceof CallableFlowSinkReturn and
|
||||
preservesValue = false
|
||||
or
|
||||
// Parse method
|
||||
c = this.getParseMethod() and
|
||||
source = any(CallableFlowSourceArg arg | arg.getArgumentIndex() = 0) and
|
||||
sink instanceof CallableFlowSinkReturn and
|
||||
preservesValue = false
|
||||
or
|
||||
// operator string
|
||||
c =
|
||||
any(Operator op |
|
||||
op.getDeclaringType() = this.getABaseType*() and op.getReturnType() instanceof StringType
|
||||
) and
|
||||
source.(CallableFlowSourceArg).getArgumentIndex() = 0 and
|
||||
sink instanceof CallableFlowSinkReturn and
|
||||
preservesValue = false
|
||||
or
|
||||
// SelectToken method
|
||||
c = this.getSelectTokenMethod() and
|
||||
source instanceof CallableFlowSourceQualifier and
|
||||
sink instanceof CallableFlowSinkReturn and
|
||||
preservesValue = false
|
||||
}
|
||||
|
||||
/** Gets the `Parse` method. */
|
||||
Method getParseMethod() { result = this.getAMethod("Parse") }
|
||||
|
||||
/** Gets the `SelectToken` method. */
|
||||
Method getSelectTokenMethod() { result = this.getABaseType*().getAMethod("SelectToken") }
|
||||
}
|
||||
|
||||
/** Data flow for `NewtonSoft.Json.Linq.JObject`. */
|
||||
private class JObjectClassFlowModelCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"Newtonsoft.Json.Linq;JObject;false;Parse;(System.String);;Argument[0];ReturnValue;taint",
|
||||
"Newtonsoft.Json.Linq;JObject;false;Parse;(System.String,Newtonsoft.Json.Linq.JsonLoadSettings);;Argument[0];ReturnValue;taint"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user