Compare commits

..

2 Commits

Author SHA1 Message Date
Esben Sparre Andreasen
3248fc2e1b make ATM anti sink model for dojo.require 2021-12-08 14:36:51 +01:00
Esben Sparre Andreasen
55c35659b5 add file write model for express-fileupload mv 2021-12-08 13:26:34 +01:00
704 changed files with 6191 additions and 68982 deletions

View File

@@ -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"
]
}

View File

@@ -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

View File

@@ -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

View File

@@ -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 }}

View File

@@ -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

View File

@@ -17,7 +17,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="16.11.0" />
<PackageReference Include="Microsoft.Build" Version="16.9.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -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.

View File

@@ -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.

View File

@@ -1,2 +0,0 @@
---
lastReleaseVersion: 0.0.4

View File

@@ -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

View File

@@ -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) }
}

View File

@@ -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 }

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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 }
}

View File

@@ -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)
)

View File

@@ -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) {

View File

@@ -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 }

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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 }
}

View File

@@ -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

View File

@@ -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(_)) }
}

View File

@@ -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`.

View File

@@ -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

View File

@@ -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)
)
}

View File

@@ -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."

View File

@@ -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."

View File

@@ -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
}
/*

View File

@@ -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*())
)
}
}

View File

@@ -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`.

View File

@@ -1,2 +0,0 @@
---
lastReleaseVersion: 0.0.4

View File

@@ -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: "*"

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-tests
groups: [cpp, test]
version: 0.0.2
dependencies:
codeql/cpp-all: "*"
codeql/cpp-queries: "*"

View File

@@ -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
}

View File

@@ -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: "*"

View File

@@ -1 +0,0 @@
## 0.0.4

View File

@@ -1 +0,0 @@
## 0.0.4

View File

@@ -1,2 +0,0 @@
---
lastReleaseVersion: 0.0.4

View File

@@ -1,5 +1,4 @@
name: codeql/cpp-upgrades
groups: cpp
upgrades: .
version: 0.0.5-dev
version: 0.0.2
library: true

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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
1 package sink source summary sink:code sink:html sink:remote sink:sql sink:xss source:local summary:taint summary:value
2 Dapper 55 55
3 Microsoft.ApplicationBlocks.Data 28 28
4 MySql.Data.MySqlClient 48 48
5 Newtonsoft.Json ServiceStack 194 73 7 27 75 92 73 7
6 ServiceStack System 194 28 3 7 25 27 4 75 92 23 1 3 7 25
System 28 3 1221 4 23 1 3 611 610

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);
}

View File

@@ -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)
{

View File

@@ -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);
}

View File

@@ -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("\")");

View File

@@ -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);
}
}
}

View File

@@ -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.

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -1 +0,0 @@
## 0.0.4

View File

@@ -1 +0,0 @@
## 0.0.4

View File

@@ -1,2 +0,0 @@
---
lastReleaseVersion: 0.0.4

View File

@@ -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()) }

View File

@@ -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

View File

@@ -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())
}
}

View File

@@ -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
}

View File

@@ -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() }

View File

@@ -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() }
}

View File

@@ -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. */

View File

@@ -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()
)
}

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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) }

View File

@@ -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() {

View File

@@ -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) }
}
/**

View File

@@ -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

View File

@@ -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 }

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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) }

View File

@@ -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()
)
}

View File

@@ -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
)
}

View File

@@ -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)
)
}

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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 }
}

View File

@@ -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 }
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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 + ")"
)
}

View File

@@ -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) }

View File

@@ -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 {

View File

@@ -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 `?.` */

View File

@@ -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