Compare commits

..

1 Commits

Author SHA1 Message Date
Andrew Eisenberg
bcd942270e Actions: Add workflow to publish packages 2021-11-09 15:16:48 -08:00
1317 changed files with 29043 additions and 80815 deletions

View File

@@ -1,23 +1,11 @@
{
"provide": [
"*/ql/src/qlpack.yml",
"*/ql/lib/qlpack.yml",
"*/ql/test/qlpack.yml",
"*/ql/examples/qlpack.yml",
"*/upgrades/qlpack.yml",
"cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml",
"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"
],
"versionPolicies": {
"default": {
"requireChangeNotes": true,
"committedPrereleaseSuffix": "dev",
"committedVersion": "nextPatchRelease"
}
}
}
{ "provide": [ "ruby/.codeqlmanifest.json",
"*/ql/src/qlpack.yml",
"*/ql/lib/qlpack.yml",
"*/ql/test/qlpack.yml",
"cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml",
"*/ql/examples/qlpack.yml",
"*/upgrades/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml",
"misc/legacy-support/*/qlpack.yml",
"misc/suite-helpers/qlpack.yml" ] }

View File

@@ -1,14 +1,29 @@
name: Fetch CodeQL
description: Fetches the latest version of CodeQL
inputs:
use-bundle:
description: Set to `true` to download the CodeQL CLI bundle that also includes compiled queries.
default: 'false'
required: false
runs:
using: composite
steps:
- name: Fetch CodeQL
shell: bash
run: |
LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | grep -v beta | sort --version-sort | tail -1)
gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-linux64.zip "$LATEST"
unzip -q -d "${RUNNER_TEMP}" codeql-linux64.zip
LATEST=$(gh release list --repo $REPO | cut -f 3 | grep -v beta | sort --version-sort | tail -1)
gh release download --repo $REPO --pattern "$PATTERN" "$LATEST"
if [ "$USE_BUNDLE" == 'true' ]; then
tar -xzf "$PATTERN" -C "${RUNNER_TEMP}"
else
unzip -q -d "${RUNNER_TEMP}" "$PATTERN"
fi
echo "${RUNNER_TEMP}/codeql" >> "${GITHUB_PATH}"
env:
GITHUB_TOKEN: ${{ github.token }}
USE_BUNDLE: '${{ inputs.use-bundle == ''true'' }}'
REPO: '${{ inputs.use-bundle == ''true'' && ''https://github.com/dsp-testing/codeql-cli-nightlies'' || ''https://github.com/github/codeql-cli-binaries''}}'
# REPO: '${{ inputs.use-bundle == ''true'' && ''https://github.com/github/codeql-action'' || ''https://github.com/github/codeql-cli-binaries''}}'
PATTERN: '${{ inputs.use-bundle == ''true'' && ''codeql-bundle-linux64.tar.gz'' || ''codeql-linux64.zip''}}'

88
.github/workflows/pack-publisher.yml vendored Normal file
View File

@@ -0,0 +1,88 @@
# Publishes the core libraries to the CodeQL package registry.
name: Publish CodeQL core libraries
on:
pull_request:
paths:
- '.github/workflows/pack-publisher.yml' # for testing changes to this workflow
workflow_dispatch:
# the cli to use, or blank to build it again
# the pre-built packs, or blank to build again
inputs:
packages-build-number:
description: |
A CodeQL CLI workflow run number to download the packages artifacts from.
Leave blank to build packages from this repository.
default: ''
required: false
permissions:
contents: write
jobs:
codeql-package-publish:
name: CodeQL Package - Publish
runs-on: ubuntu-20.04
env:
GITHUB_TOKEN: ${{ github.token }}
steps:
- name: Dump environment
run: env
- name: Dump GitHub event context
env:
GITHUB_CONTEXT: '${{ toJson(github.event) }}'
run: echo "$GITHUB_CONTEXT"
- name: Checkout repository
uses: actions/checkout@v2
# TODO add a way to specify different versions of the CLI
- name: Download CLI
uses: ./.github/actions/fetch-codeql
with:
use-bundle: 'true'
- name: Publish packs
run: |
# do not publish go or suite-helpers
# `ls` all directories in the bundle remove suite-helpers and go
PACK_FOLDERS_TO_PUBLISH="$(ls -d $RUNNER_TEMP/codeql/qlpacks/codeql/*/* | grep -v suite | grep -v "\-go")"
ARCHIVES="$RUNNER_TEMP/archives"
mkdir -p "$ARCHIVES"
echo "Running on: $PACK_FOLDERS_TO_PUBLISH"
# tgz each folder
# then run pack publish on it
for folder in $PACK_FOLDERS_TO_PUBLISH
do
echo "Archiving $folder for publishing"
tar cfz "$ARCHIVES/archive.tgz" -C "$folder" .
echo "Publishing $ARCHIVES/archive.tgz"
echo "Would have run: 'codeql pack publish --file "$ARCHIVES/archive.tgz"'"
done
- name: Bump versions
run: |
echo "Would have run 'codeql pack release'"
- name: Update git config
run: |
git config --global user.email "github-actions@github.com"
git config --global user.name "github-actions[bot]"
- name: Create PR
run: |
set -exu
git add .
git commit -m "Post-release preparation"
NEW_BRANCH="post-release-prep-$(git show -s --format=%h)"
git checkout -b $NEW_BRANCH
git push origin "$NEW_BRANCH"
gh pr create \
--head "$NEW_BRANCH" \
--base "$GITHUB_BASE_REF" \
--fill \
--draft

View File

@@ -102,6 +102,16 @@ jobs:
PACK_FOLDER=$(readlink -f target/packs/codeql/ruby-queries/*)
codeql/codeql generate query-help --format=sarifv2.1.0 --output="${PACK_FOLDER}/rules.sarif" ql/src
(cd ql/src; find queries \( -name '*.qhelp' -o -name '*.rb' -o -name '*.erb' \) -exec bash -c 'mkdir -p "'"${PACK_FOLDER}"'/$(dirname "{}")"' \; -exec cp "{}" "${PACK_FOLDER}/{}" \;)
- name: Compile with previous CodeQL versions
run: |
for version in $(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | sort --version-sort | tail -3 | head -2); do
rm -f codeql-linux64.zip
gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-linux64.zip "$version"
rm -rf codeql; unzip -q codeql-linux64.zip
codeql/codeql query compile target/packs/*
done
env:
GITHUB_TOKEN: ${{ github.token }}
- uses: actions/upload-artifact@v2
with:
name: codeql-ruby-queries

View File

@@ -24,7 +24,7 @@ jobs:
strategy:
fail-fast: false
matrix:
repo: [rails/rails, discourse/discourse, spree/spree, ruby/ruby]
repo: [rails/rails, discourse/discourse, spree/spree]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
@@ -41,7 +41,7 @@ jobs:
- name: Create database
run: |
codeql database create \
--search-path "${{ github.workspace }}/ruby/extractor-pack" \
--search-path "${{ github.workspace }}/ruby" \
--threads 4 \
--language ruby --source-root "${{ github.workspace }}/repo" \
"${{ runner.temp }}/database"

View File

@@ -32,14 +32,14 @@ jobs:
- uses: ./ruby/actions/create-extractor-pack
- name: Run QL tests
run: |
codeql test run --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test
codeql test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}/ruby" --additional-packs "${{ github.workspace }}" --consistency-queries ql/consistency-queries ql/test
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Check QL formatting
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
- name: Check QL compilation
run: |
codeql query compile --check-only --threads=4 --warnings=error "ql/src" "ql/examples"
codeql query compile --check-only --threads=4 --warnings=error --search-path "${{ github.workspace }}/ruby" --additional-packs "${{ github.workspace }}" "ql/src" "ql/examples"
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Check DB upgrade scripts

3
.gitignore vendored
View File

@@ -27,6 +27,3 @@ csharp/extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
# Avoid committing cached package components
.codeql
# Compiled class file
*.class

View File

@@ -460,10 +460,9 @@
"javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll",
"python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll"
],
"ReDoS Util Python/JS/Ruby": [
"ReDoS Util Python/JS": [
"javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll",
"python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll",
"ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll"
"python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll"
],
"ReDoS Exponential Python/JS": [
"javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll",
@@ -472,12 +471,7 @@
"ReDoS Polynomial Python/JS": [
"javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll",
"ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll"
],
"BadTagFilterQuery Python/JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll",
"python/ql/lib/semmle/python/security/BadTagFilterQuery.qll",
"ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll"
"ruby/ql/lib/codeql/ruby/regexp/SuperlinearBackTracking.qll"
],
"CFG": [
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",

View File

@@ -1,2 +0,0 @@
lgtm,codescanning
* 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 @@
lgtm,codescanning
* A new query `cpp/certificate-not-checked` has been added for C/C++. The query flags unsafe use of OpenSSL and similar libraries.

View File

@@ -1,2 +0,0 @@
lgtm,codescanning
* A new query `cpp/certificate-result-conflation` has been added for C/C++. The query flags unsafe use of OpenSSL and similar libraries.

View File

@@ -1,9 +0,0 @@
## 0.0.5
## 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 +0,0 @@
## 0.0.5

View File

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

View File

@@ -1,8 +1,7 @@
name: codeql/cpp-all
version: 0.0.5
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

@@ -6,8 +6,6 @@ import semmle.code.cpp.Type
import semmle.code.cpp.commons.CommonType
import semmle.code.cpp.commons.StringAnalysis
import semmle.code.cpp.models.interfaces.FormattingFunction
private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
class PrintfFormatAttribute extends FormatAttribute {
PrintfFormatAttribute() { this.getArchetype() = ["printf", "__printf__"] }
@@ -270,18 +268,6 @@ class FormattingFunctionCall extends Expr {
}
}
/**
* Gets the number of digits required to represent the integer represented by `f`.
*
* `f` is assumed to be nonnegative.
*/
bindingset[f]
private int lengthInBase10(float f) {
f = 0 and result = 1
or
result = f.log10().floor() + 1
}
/**
* A class to represent format strings that occur as arguments to invocations of formatting functions.
*/
@@ -1060,63 +1046,39 @@ class FormatLiteral extends Literal {
or
this.getConversionChar(n).toLowerCase() = ["d", "i"] and
// e.g. -2^31 = "-2147483648"
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)
)
)
)
)
exists(int sizeBits |
sizeBits =
min(int bits |
bits = this.getIntegralDisplayType(n).getSize() * 8
or
exists(IntegralType t |
t = this.getUse().getConversionArgument(n).getType().getUnderlyingType()
|
t.isSigned() and bits = t.getSize() * 8
)
) and
len = 1 + ((sizeBits - 1) / 10.0.log2()).ceil()
// this calculation is as %u (below) only we take out the sign bit (- 1) and allow a whole
// character for it to be expressed as '-'.
)
or
this.getConversionChar(n).toLowerCase() = "u" and
// e.g. 2^32 - 1 = "4294967295"
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
cand0 = 2.pow(any(IntType t | t.isUnsigned()).getSize() * 8)
or
cand0 = upperBound(arg.getFullyConverted())
)
)
|
lengthInBase10(cand)
)
exists(int sizeBits |
sizeBits =
min(int bits |
bits = this.getIntegralDisplayType(n).getSize() * 8
or
exists(IntegralType t |
t = this.getUse().getConversionArgument(n).getType().getUnderlyingType()
|
t.isUnsigned() and bits = t.getSize() * 8
)
) and
len = (sizeBits / 10.0.log2()).ceil()
// convert the size from bits to decimal characters, and round up as you can't have
// fractional characters (10.0.log2() is the number of bits expressed per decimal character)
)
or
this.getConversionChar(n).toLowerCase() = "x" and
// e.g. "12345678"

View File

@@ -626,9 +626,9 @@ library class ExprEvaluator extends int {
// All assignments must have the same int value
result =
unique(Expr value |
value = v.getAnAssignedValue() and not this.ignoreVariableAssignment(e, v, value)
value = v.getAnAssignedValue() and not ignoreVariableAssignment(e, v, value)
|
this.getValueInternalNonSubExpr(value)
getValueInternalNonSubExpr(value)
)
)
}

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()) }
}
@@ -289,7 +289,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -308,23 +307,11 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -333,14 +320,16 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
node2.isImplicitReadNode(n, false)
)
}
@@ -353,14 +342,16 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n and
not fullBarrier(node2, config)
node2.asNode() = n
)
}
@@ -372,7 +363,10 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -386,14 +380,16 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
read(node1.asNode(), c, node2.asNode())
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -406,8 +402,7 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
read(_, tc.getContent(), _, config)
}
pragma[nomagic]
@@ -456,59 +451,63 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
)
}
@@ -548,8 +547,7 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
viableReturnPosOutEx(call, pos, out)
)
}
@@ -775,7 +773,6 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1012,9 +1009,6 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1023,23 +1017,14 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1052,13 +1037,6 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1129,7 +1107,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1164,8 +1142,9 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1180,8 +1159,9 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1191,8 +1171,10 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1206,7 +1188,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
}
@@ -1248,11 +1230,6 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1329,7 +1306,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1364,8 +1341,9 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1375,8 +1353,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1386,8 +1365,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1447,7 +1427,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),
@@ -1727,14 +1707,12 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1859,8 +1837,9 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1875,8 +1854,9 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1886,8 +1866,10 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1943,11 +1925,6 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2024,7 +2001,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2059,8 +2036,9 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2070,8 +2048,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2081,8 +2060,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2142,7 +2122,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),
@@ -2493,14 +2473,12 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -2625,8 +2603,9 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2641,8 +2620,9 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2652,8 +2632,10 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2709,11 +2691,6 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2790,7 +2767,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2825,8 +2802,9 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2836,8 +2814,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2847,8 +2826,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2908,7 +2888,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 +2972,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 +3619,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 +3666,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 +3692,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
@@ -3761,14 +3740,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
)
}
@@ -3802,17 +3780,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3821,12 +3790,11 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4442,25 +4410,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 +4436,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 +4602,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 +4630,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()) }
}
@@ -289,7 +289,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -308,23 +307,11 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -333,14 +320,16 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
node2.isImplicitReadNode(n, false)
)
}
@@ -353,14 +342,16 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n and
not fullBarrier(node2, config)
node2.asNode() = n
)
}
@@ -372,7 +363,10 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -386,14 +380,16 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
read(node1.asNode(), c, node2.asNode())
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -406,8 +402,7 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
read(_, tc.getContent(), _, config)
}
pragma[nomagic]
@@ -456,59 +451,63 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
)
}
@@ -548,8 +547,7 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
viableReturnPosOutEx(call, pos, out)
)
}
@@ -775,7 +773,6 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1012,9 +1009,6 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1023,23 +1017,14 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1052,13 +1037,6 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1129,7 +1107,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1164,8 +1142,9 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1180,8 +1159,9 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1191,8 +1171,10 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1206,7 +1188,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
}
@@ -1248,11 +1230,6 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1329,7 +1306,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1364,8 +1341,9 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1375,8 +1353,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1386,8 +1365,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1447,7 +1427,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),
@@ -1727,14 +1707,12 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1859,8 +1837,9 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1875,8 +1854,9 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1886,8 +1866,10 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1943,11 +1925,6 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2024,7 +2001,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2059,8 +2036,9 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2070,8 +2048,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2081,8 +2060,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2142,7 +2122,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),
@@ -2493,14 +2473,12 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -2625,8 +2603,9 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2641,8 +2620,9 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2652,8 +2632,10 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2709,11 +2691,6 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2790,7 +2767,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2825,8 +2802,9 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2836,8 +2814,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2847,8 +2826,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2908,7 +2888,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 +2972,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 +3619,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 +3666,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 +3692,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
@@ -3761,14 +3740,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
)
}
@@ -3802,17 +3780,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3821,12 +3790,11 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4442,25 +4410,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 +4436,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 +4602,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 +4630,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()) }
}
@@ -289,7 +289,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -308,23 +307,11 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -333,14 +320,16 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
node2.isImplicitReadNode(n, false)
)
}
@@ -353,14 +342,16 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n and
not fullBarrier(node2, config)
node2.asNode() = n
)
}
@@ -372,7 +363,10 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -386,14 +380,16 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
read(node1.asNode(), c, node2.asNode())
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -406,8 +402,7 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
read(_, tc.getContent(), _, config)
}
pragma[nomagic]
@@ -456,59 +451,63 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
)
}
@@ -548,8 +547,7 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
viableReturnPosOutEx(call, pos, out)
)
}
@@ -775,7 +773,6 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1012,9 +1009,6 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1023,23 +1017,14 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1052,13 +1037,6 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1129,7 +1107,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1164,8 +1142,9 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1180,8 +1159,9 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1191,8 +1171,10 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1206,7 +1188,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
}
@@ -1248,11 +1230,6 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1329,7 +1306,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1364,8 +1341,9 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1375,8 +1353,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1386,8 +1365,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1447,7 +1427,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),
@@ -1727,14 +1707,12 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1859,8 +1837,9 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1875,8 +1854,9 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1886,8 +1866,10 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1943,11 +1925,6 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2024,7 +2001,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2059,8 +2036,9 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2070,8 +2048,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2081,8 +2060,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2142,7 +2122,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),
@@ -2493,14 +2473,12 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -2625,8 +2603,9 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2641,8 +2620,9 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2652,8 +2632,10 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2709,11 +2691,6 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2790,7 +2767,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2825,8 +2802,9 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2836,8 +2814,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2847,8 +2826,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2908,7 +2888,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 +2972,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 +3619,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 +3666,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 +3692,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
@@ -3761,14 +3740,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
)
}
@@ -3802,17 +3780,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3821,12 +3790,11 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4442,25 +4410,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 +4436,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 +4602,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 +4630,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()) }
}
@@ -289,7 +289,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -308,23 +307,11 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -333,14 +320,16 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
node2.isImplicitReadNode(n, false)
)
}
@@ -353,14 +342,16 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n and
not fullBarrier(node2, config)
node2.asNode() = n
)
}
@@ -372,7 +363,10 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -386,14 +380,16 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
read(node1.asNode(), c, node2.asNode())
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -406,8 +402,7 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
read(_, tc.getContent(), _, config)
}
pragma[nomagic]
@@ -456,59 +451,63 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
)
}
@@ -548,8 +547,7 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
viableReturnPosOutEx(call, pos, out)
)
}
@@ -775,7 +773,6 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1012,9 +1009,6 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1023,23 +1017,14 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1052,13 +1037,6 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1129,7 +1107,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1164,8 +1142,9 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1180,8 +1159,9 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1191,8 +1171,10 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1206,7 +1188,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
}
@@ -1248,11 +1230,6 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1329,7 +1306,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1364,8 +1341,9 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1375,8 +1353,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1386,8 +1365,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1447,7 +1427,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),
@@ -1727,14 +1707,12 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1859,8 +1837,9 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1875,8 +1854,9 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1886,8 +1866,10 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1943,11 +1925,6 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2024,7 +2001,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2059,8 +2036,9 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2070,8 +2048,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2081,8 +2060,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2142,7 +2122,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),
@@ -2493,14 +2473,12 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -2625,8 +2603,9 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2641,8 +2620,9 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2652,8 +2632,10 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2709,11 +2691,6 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2790,7 +2767,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2825,8 +2802,9 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2836,8 +2814,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2847,8 +2826,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2908,7 +2888,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 +2972,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 +3619,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 +3666,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 +3692,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
@@ -3761,14 +3740,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
)
}
@@ -3802,17 +3780,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3821,12 +3790,11 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4442,25 +4410,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 +4436,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 +4602,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 +4630,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

@@ -9,19 +9,6 @@ private import tainttracking1.TaintTrackingParameter::Private
private import tainttracking1.TaintTrackingParameter::Public
module Consistency {
private newtype TConsistencyConfiguration = MkConsistencyConfiguration()
/** A class for configuring the consistency queries. */
class ConsistencyConfiguration extends TConsistencyConfiguration {
string toString() { none() }
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
predicate postWithInFlowExclude(Node n) { none() }
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
}
private class RelevantNode extends Node {
RelevantNode() {
this instanceof ArgumentNode or
@@ -177,7 +164,7 @@ module Consistency {
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
not hasPost(n) and
not any(ConsistencyConfiguration c).argHasPostUpdateExclude(n) and
not isImmutableOrUnobservable(n) and
msg = "ArgumentNode is missing PostUpdateNode."
}
@@ -190,7 +177,6 @@ module Consistency {
isPostUpdateNode(n) and
not clearsContent(n, _) and
simpleLocalFlowStep(_, n) and
not any(ConsistencyConfiguration c).postWithInFlowExclude(n) and
msg = "PostUpdateNode should not be the target of local flow."
}
}

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()) }
}
@@ -289,7 +289,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -308,23 +307,11 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -333,14 +320,16 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
node2.isImplicitReadNode(n, false)
)
}
@@ -353,14 +342,16 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n and
not fullBarrier(node2, config)
node2.asNode() = n
)
}
@@ -372,7 +363,10 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -386,14 +380,16 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
read(node1.asNode(), c, node2.asNode())
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -406,8 +402,7 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
read(_, tc.getContent(), _, config)
}
pragma[nomagic]
@@ -456,59 +451,63 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
)
}
@@ -548,8 +547,7 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
viableReturnPosOutEx(call, pos, out)
)
}
@@ -775,7 +773,6 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1012,9 +1009,6 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1023,23 +1017,14 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1052,13 +1037,6 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1129,7 +1107,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1164,8 +1142,9 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1180,8 +1159,9 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1191,8 +1171,10 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1206,7 +1188,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
}
@@ -1248,11 +1230,6 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1329,7 +1306,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1364,8 +1341,9 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1375,8 +1353,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1386,8 +1365,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1447,7 +1427,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),
@@ -1727,14 +1707,12 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1859,8 +1837,9 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1875,8 +1854,9 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1886,8 +1866,10 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1943,11 +1925,6 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2024,7 +2001,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2059,8 +2036,9 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2070,8 +2048,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2081,8 +2060,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2142,7 +2122,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),
@@ -2493,14 +2473,12 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -2625,8 +2603,9 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2641,8 +2620,9 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2652,8 +2632,10 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2709,11 +2691,6 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2790,7 +2767,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2825,8 +2802,9 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2836,8 +2814,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2847,8 +2826,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2908,7 +2888,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 +2972,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 +3619,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 +3666,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 +3692,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
@@ -3761,14 +3740,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
)
}
@@ -3802,17 +3780,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3821,12 +3790,11 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4442,25 +4410,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 +4436,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 +4602,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 +4630,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

@@ -2,20 +2,12 @@ private import cpp
private import DataFlowUtil
private import DataFlowDispatch
private import FlowVar
private import DataFlowImplConsistency
/** Gets the callable in which this node occurs. */
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) {
@@ -267,6 +259,27 @@ class Unit extends TUnit {
string toString() { result = "unit" }
}
/**
* Holds if `n` does not require a `PostUpdateNode` as it either cannot be
* modified or its modification cannot be observed, for example if it is a
* freshly created object that is not saved in a variable.
*
* This predicate is only used for consistency checks.
*/
predicate isImmutableOrUnobservable(Node n) {
// Is the null pointer (or something that's not really a pointer)
exists(n.asExpr().getValue())
or
// Isn't a pointer or is a pointer to const
forall(DerivedType dt | dt = n.asExpr().getActualType() |
dt.getBaseType().isConst()
or
dt.getBaseType() instanceof RoutineType
)
// The above list of cases isn't exhaustive, but it narrows down the
// consistency alerts enough that most of them are interesting.
}
/** Holds if `n` should be hidden from path explanations. */
predicate nodeIsHidden(Node n) { none() }
@@ -289,19 +302,3 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
* by default as a heuristic.
*/
predicate allowParameterReturnInSelf(ParameterNode p) { none() }
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
override predicate argHasPostUpdateExclude(ArgumentNode n) {
// Is the null pointer (or something that's not really a pointer)
exists(n.asExpr().getValue())
or
// Isn't a pointer or is a pointer to const
forall(DerivedType dt | dt = n.asExpr().getActualType() |
dt.getBaseType().isConst()
or
dt.getBaseType() instanceof RoutineType
)
// The above list of cases isn't exhaustive, but it narrows down the
// consistency alerts enough that most of them are interesting.
}
}

View File

@@ -484,9 +484,8 @@ module TaintedWithPath {
/** Gets the element that `pathNode` wraps, if any. */
Element getElementFromPathNode(PathNode pathNode) {
exists(DataFlow::Node node | node = pathNode.(WrapPathNode).inner().getNode() |
result = node.asInstruction().getAST()
or
result = node.asOperand().getDef().getAST()
result = node.asExpr() or
result = node.asParameter()
)
or
result = pathNode.(EndpointPathNode).inner()

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()) }
}
@@ -289,7 +289,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -308,23 +307,11 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -333,14 +320,16 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
node2.isImplicitReadNode(n, false)
)
}
@@ -353,14 +342,16 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n and
not fullBarrier(node2, config)
node2.asNode() = n
)
}
@@ -372,7 +363,10 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -386,14 +380,16 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
read(node1.asNode(), c, node2.asNode())
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -406,8 +402,7 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
read(_, tc.getContent(), _, config)
}
pragma[nomagic]
@@ -456,59 +451,63 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
)
}
@@ -548,8 +547,7 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
viableReturnPosOutEx(call, pos, out)
)
}
@@ -775,7 +773,6 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1012,9 +1009,6 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1023,23 +1017,14 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1052,13 +1037,6 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1129,7 +1107,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1164,8 +1142,9 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1180,8 +1159,9 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1191,8 +1171,10 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1206,7 +1188,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
}
@@ -1248,11 +1230,6 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1329,7 +1306,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1364,8 +1341,9 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1375,8 +1353,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1386,8 +1365,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1447,7 +1427,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),
@@ -1727,14 +1707,12 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1859,8 +1837,9 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1875,8 +1854,9 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1886,8 +1866,10 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1943,11 +1925,6 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2024,7 +2001,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2059,8 +2036,9 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2070,8 +2048,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2081,8 +2060,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2142,7 +2122,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),
@@ -2493,14 +2473,12 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -2625,8 +2603,9 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2641,8 +2620,9 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2652,8 +2632,10 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2709,11 +2691,6 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2790,7 +2767,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2825,8 +2802,9 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2836,8 +2814,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2847,8 +2826,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2908,7 +2888,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 +2972,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 +3619,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 +3666,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 +3692,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
@@ -3761,14 +3740,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
)
}
@@ -3802,17 +3780,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3821,12 +3790,11 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4442,25 +4410,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 +4436,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 +4602,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 +4630,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()) }
}
@@ -289,7 +289,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -308,23 +307,11 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -333,14 +320,16 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
node2.isImplicitReadNode(n, false)
)
}
@@ -353,14 +342,16 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n and
not fullBarrier(node2, config)
node2.asNode() = n
)
}
@@ -372,7 +363,10 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -386,14 +380,16 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
read(node1.asNode(), c, node2.asNode())
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -406,8 +402,7 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
read(_, tc.getContent(), _, config)
}
pragma[nomagic]
@@ -456,59 +451,63 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
)
}
@@ -548,8 +547,7 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
viableReturnPosOutEx(call, pos, out)
)
}
@@ -775,7 +773,6 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1012,9 +1009,6 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1023,23 +1017,14 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1052,13 +1037,6 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1129,7 +1107,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1164,8 +1142,9 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1180,8 +1159,9 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1191,8 +1171,10 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1206,7 +1188,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
}
@@ -1248,11 +1230,6 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1329,7 +1306,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1364,8 +1341,9 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1375,8 +1353,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1386,8 +1365,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1447,7 +1427,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),
@@ -1727,14 +1707,12 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1859,8 +1837,9 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1875,8 +1854,9 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1886,8 +1866,10 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1943,11 +1925,6 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2024,7 +2001,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2059,8 +2036,9 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2070,8 +2048,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2081,8 +2060,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2142,7 +2122,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),
@@ -2493,14 +2473,12 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -2625,8 +2603,9 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2641,8 +2620,9 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2652,8 +2632,10 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2709,11 +2691,6 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2790,7 +2767,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2825,8 +2802,9 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2836,8 +2814,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2847,8 +2826,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2908,7 +2888,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 +2972,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 +3619,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 +3666,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 +3692,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
@@ -3761,14 +3740,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
)
}
@@ -3802,17 +3780,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3821,12 +3790,11 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4442,25 +4410,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 +4436,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 +4602,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 +4630,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()) }
}
@@ -289,7 +289,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -308,23 +307,11 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -333,14 +320,16 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
node2.isImplicitReadNode(n, false)
)
}
@@ -353,14 +342,16 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n and
not fullBarrier(node2, config)
node2.asNode() = n
)
}
@@ -372,7 +363,10 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -386,14 +380,16 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
read(node1.asNode(), c, node2.asNode())
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -406,8 +402,7 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
read(_, tc.getContent(), _, config)
}
pragma[nomagic]
@@ -456,59 +451,63 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
)
}
@@ -548,8 +547,7 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
viableReturnPosOutEx(call, pos, out)
)
}
@@ -775,7 +773,6 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1012,9 +1009,6 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1023,23 +1017,14 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1052,13 +1037,6 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1129,7 +1107,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1164,8 +1142,9 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1180,8 +1159,9 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1191,8 +1171,10 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1206,7 +1188,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
}
@@ -1248,11 +1230,6 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1329,7 +1306,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1364,8 +1341,9 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1375,8 +1353,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1386,8 +1365,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1447,7 +1427,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),
@@ -1727,14 +1707,12 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1859,8 +1837,9 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1875,8 +1854,9 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1886,8 +1866,10 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1943,11 +1925,6 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2024,7 +2001,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2059,8 +2036,9 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2070,8 +2048,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2081,8 +2060,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2142,7 +2122,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),
@@ -2493,14 +2473,12 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -2625,8 +2603,9 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2641,8 +2620,9 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2652,8 +2632,10 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2709,11 +2691,6 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2790,7 +2767,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2825,8 +2802,9 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2836,8 +2814,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2847,8 +2826,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2908,7 +2888,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 +2972,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 +3619,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 +3666,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 +3692,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
@@ -3761,14 +3740,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
)
}
@@ -3802,17 +3780,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3821,12 +3790,11 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4442,25 +4410,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 +4436,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 +4602,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 +4630,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()) }
}
@@ -289,7 +289,6 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -308,23 +307,11 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -333,14 +320,16 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
node2.isImplicitReadNode(n, false)
)
}
@@ -353,14 +342,16 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config)
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n and
not fullBarrier(node2, config)
node2.asNode() = n
)
}
@@ -372,7 +363,10 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -386,14 +380,16 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
read(node1.asNode(), c, node2.asNode())
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -406,8 +402,7 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
read(_, tc.getContent(), _, config)
}
pragma[nomagic]
@@ -456,59 +451,63 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
not fullBarrier(node, config) and
(
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
)
}
@@ -548,8 +547,7 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
viableReturnPosOutEx(call, pos, out)
)
}
@@ -775,7 +773,6 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -1012,9 +1009,6 @@ private module Stage2 {
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
bindingset[node, ap]
private predicate filter(NodeEx node, Ap ap) { any() }
bindingset[ap, contentType]
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
@@ -1023,23 +1017,14 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
exists(ApApprox apa0 |
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1052,13 +1037,6 @@ private module Stage2 {
*/
pragma[nomagic]
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
fwdFlow0(node, cc, argAp, ap, config) and
flowCand(node, unbindApa(getApprox(ap)), config) and
filter(node, ap)
}
pragma[nomagic]
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
@@ -1129,7 +1107,7 @@ private module Stage2 {
) {
exists(DataFlowType contentType |
fwdFlow(node1, cc, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
typecheckStore(ap1, contentType)
)
}
@@ -1164,8 +1142,9 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1180,8 +1159,9 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1191,8 +1171,10 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1206,7 +1188,7 @@ private module Stage2 {
) {
exists(ParamNodeEx p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
}
@@ -1248,11 +1230,6 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1329,7 +1306,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1364,8 +1341,9 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1375,8 +1353,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1386,8 +1365,9 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1447,7 +1427,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),
@@ -1727,14 +1707,12 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -1859,8 +1837,9 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1875,8 +1854,9 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1886,8 +1866,10 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -1943,11 +1925,6 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2024,7 +2001,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2059,8 +2036,9 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2070,8 +2048,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2081,8 +2060,9 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2142,7 +2122,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),
@@ -2493,14 +2473,12 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
pragma[only_bind_into](config))
}
/**
@@ -2625,8 +2603,9 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2641,8 +2620,9 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2652,8 +2632,10 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2709,11 +2691,6 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2790,7 +2767,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if returnNodeMayFlowThrough(node, ap, config)
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2825,8 +2802,9 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2836,8 +2814,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2847,8 +2826,9 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
@@ -2908,7 +2888,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 +2972,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 +3619,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 +3666,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 +3692,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
@@ -3761,14 +3740,13 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
)
}
@@ -3802,17 +3780,8 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
apout = ret.getAp() and
not ret.isHidden()
)
}
@@ -3821,12 +3790,11 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout
@@ -4442,25 +4410,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 +4436,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 +4602,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 +4630,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

@@ -9,19 +9,6 @@ private import tainttracking1.TaintTrackingParameter::Private
private import tainttracking1.TaintTrackingParameter::Public
module Consistency {
private newtype TConsistencyConfiguration = MkConsistencyConfiguration()
/** A class for configuring the consistency queries. */
class ConsistencyConfiguration extends TConsistencyConfiguration {
string toString() { none() }
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
predicate postWithInFlowExclude(Node n) { none() }
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
}
private class RelevantNode extends Node {
RelevantNode() {
this instanceof ArgumentNode or
@@ -177,7 +164,7 @@ module Consistency {
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
not hasPost(n) and
not any(ConsistencyConfiguration c).argHasPostUpdateExclude(n) and
not isImmutableOrUnobservable(n) and
msg = "ArgumentNode is missing PostUpdateNode."
}
@@ -190,7 +177,6 @@ module Consistency {
isPostUpdateNode(n) and
not clearsContent(n, _) and
simpleLocalFlowStep(_, n) and
not any(ConsistencyConfiguration c).postWithInFlowExclude(n) and
msg = "PostUpdateNode should not be the target of local flow."
}
}

View File

@@ -2,20 +2,12 @@ private import cpp
private import DataFlowUtil
private import semmle.code.cpp.ir.IR
private import DataFlowDispatch
private import DataFlowImplConsistency
/** Gets the callable in which this node occurs. */
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
@@ -293,19 +285,22 @@ class Unit extends TUnit {
string toString() { result = "unit" }
}
/** Holds if `n` should be hidden from path explanations. */
predicate nodeIsHidden(Node n) {
n instanceof OperandNode and not n instanceof ArgumentNode
or
StoreNodeFlow::flowThrough(n, _) and
not StoreNodeFlow::flowOutOf(n, _) and
not StoreNodeFlow::flowInto(_, n)
or
ReadNodeFlow::flowThrough(n, _) and
not ReadNodeFlow::flowOutOf(n, _) and
not ReadNodeFlow::flowInto(_, n)
/**
* Holds if `n` does not require a `PostUpdateNode` as it either cannot be
* modified or its modification cannot be observed, for example if it is a
* freshly created object that is not saved in a variable.
*
* This predicate is only used for consistency checks.
*/
predicate isImmutableOrUnobservable(Node n) {
// The rules for whether an IR argument gets a post-update node are too
// complex to model here.
any()
}
/** Holds if `n` should be hidden from path explanations. */
predicate nodeIsHidden(Node n) { n instanceof OperandNode and not n instanceof ArgumentNode }
class LambdaCallKind = Unit;
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
@@ -325,11 +320,3 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
* by default as a heuristic.
*/
predicate allowParameterReturnInSelf(ParameterNode p) { none() }
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
override predicate argHasPostUpdateExclude(ArgumentNode n) {
// The rules for whether an IR argument gets a post-update node are too
// complex to model here.
any()
}
}

View File

@@ -452,7 +452,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
/** Holds if this phi node has input from the `rnk`'th write operation in block `block`. */
final predicate hasInputAtRankInBlock(IRBlock block, int rnk) {
this.hasInputAtRankInBlock(block, rnk, _)
hasInputAtRankInBlock(block, rnk, _)
}
/**
@@ -806,7 +806,7 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand())
or
// Flow into, through, and out of store nodes
StoreNodeFlow::flowInto(nodeFrom.asInstruction(), nodeTo)
StoreNodeFlow::flowInto(nodeFrom, nodeTo)
or
StoreNodeFlow::flowThrough(nodeFrom, nodeTo)
or
@@ -831,19 +831,23 @@ private predicate adjacentDefUseFlow(Node nodeFrom, Node nodeTo) {
//Def-use flow
Ssa::ssaFlow(nodeFrom, nodeTo)
or
// Use-use flow through stores.
exists(Instruction loadAddress, Node store |
loadAddress = Ssa::getSourceAddressFromNode(nodeFrom) and
Ssa::explicitWrite(_, store.asInstruction(), loadAddress) and
Ssa::ssaFlow(store, nodeTo)
exists(Instruction loadAddress | loadAddress = Ssa::getSourceAddressFromNode(nodeFrom) |
// Use-use flow through reads
exists(Node address |
Ssa::addressFlowTC(address.asInstruction(), loadAddress) and
Ssa::ssaFlow(address, nodeTo)
)
or
// Use-use flow through stores.
exists(Node store |
Ssa::explicitWrite(_, store.asInstruction(), loadAddress) and
Ssa::ssaFlow(store, nodeTo)
)
)
)
}
/**
* INTERNAL: Do not use.
*/
module ReadNodeFlow {
private module ReadNodeFlow {
/** Holds if the read node `nodeTo` should receive flow from `nodeFrom`. */
predicate flowInto(Node nodeFrom, ReadNode nodeTo) {
nodeTo.isInitial() and
@@ -863,12 +867,7 @@ module ReadNodeFlow {
)
}
/**
* Holds if the read node `nodeTo` should receive flow from the read node `nodeFrom`.
*
* This happens when `readFrom` is _not_ the source of a `readStep`, and `nodeTo` is
* the `ReadNode` that represents an address that directly depends on `nodeFrom`.
*/
/** Holds if the read node `nodeTo` should receive flow from the read node `nodeFrom`. */
predicate flowThrough(ReadNode nodeFrom, ReadNode nodeTo) {
not readStep(nodeFrom, _, _) and
nodeFrom.getOuter() = nodeTo
@@ -907,25 +906,17 @@ module ReadNodeFlow {
}
}
/**
* INTERNAL: Do not use.
*/
module StoreNodeFlow {
private module StoreNodeFlow {
/** Holds if the store node `nodeTo` should receive flow from `nodeFrom`. */
predicate flowInto(Instruction instrFrom, StoreNode nodeTo) {
nodeTo.flowInto(Ssa::getDestinationAddress(instrFrom))
predicate flowInto(Node nodeFrom, StoreNode nodeTo) {
nodeTo.flowInto(Ssa::getDestinationAddress(nodeFrom.asInstruction()))
}
/**
* Holds if the store node `nodeTo` should receive flow from `nodeFom`.
*
* This happens when `nodeFrom` is _not_ the source of a `storeStep`, and `nodeFrom` is
* the `Storenode` that represents an address that directly depends on `nodeTo`.
*/
predicate flowThrough(StoreNode nodeFrom, StoreNode nodeTo) {
/** Holds if the store node `nodeTo` should receive flow from `nodeFom`. */
predicate flowThrough(StoreNode nFrom, StoreNode nodeTo) {
// Flow through a post update node that doesn't need a store step.
not storeStep(nodeFrom, _, _) and
nodeTo.getOuter() = nodeFrom
not storeStep(nFrom, _, _) and
nodeTo.getOuter() = nFrom
}
/**

View File

@@ -634,29 +634,3 @@ class UncertainWriteDefinition extends WriteDefinition {
)
}
}
/** Provides a set of consistency queries. */
module Consistency {
abstract class RelevantDefinition extends Definition {
abstract predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
);
}
query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
ssaDefReachesRead(v, def, bb, i) and
not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i)))
}
query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) {
variableRead(bb, i, v, _) and
not ssaDefReachesRead(v, _, bb, i)
}
query predicate deadDef(RelevantDefinition def, SourceVariable v) {
v = def.getSourceVariable() and
not ssaDefReachesRead(_, def, _, _) and
not phiHasInputFromBlock(_, def, _) and
not uncertainWriteDefinitionInput(_, def)
}
}

View File

@@ -244,6 +244,17 @@ Instruction getDestinationAddress(Instruction instr) {
]
}
class ReferenceToInstruction extends CopyValueInstruction {
ReferenceToInstruction() {
this.getResultType() instanceof Cpp::ReferenceType and
not this.getUnary().getResultType() instanceof Cpp::ReferenceType
}
Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() }
Operand getSourceAddressOperand() { result = this.getUnaryOperand() }
}
/** Gets the source address of `instr` if it is an instruction that behaves like a `LoadInstruction`. */
Instruction getSourceAddress(Instruction instr) { result = getSourceAddressOperand(instr).getDef() }
@@ -255,7 +266,11 @@ Operand getSourceAddressOperand(Instruction instr) {
result =
[
instr.(LoadInstruction).getSourceAddressOperand(),
instr.(ReadSideEffectInstruction).getArgumentOperand()
instr.(ReadSideEffectInstruction).getArgumentOperand(),
// `ReferenceToInstruction` is really more of an address-of operation,
// but by including it in this list we break out of `flowOutOfAddressStep` at an
// instruction that, at the source level, looks like a use of a variable.
instr.(ReferenceToInstruction).getSourceAddressOperand()
]
}
@@ -280,6 +295,10 @@ Operand getSourceValueOperand(Instruction instr) {
result = instr.(LoadInstruction).getSourceValueOperand()
or
result = instr.(ReadSideEffectInstruction).getSideEffectOperand()
or
// See the comment on the `ReferenceToInstruction` disjunct in `getSourceAddressOperand` for why
// this case is included.
result = instr.(ReferenceToInstruction).getSourceValueOperand()
}
/**
@@ -494,64 +513,6 @@ private module Cached {
explicitWrite(false, storeNode.getStoreInstruction(), def)
)
or
// The destination of a store operation has undergone lvalue-to-rvalue conversion and is now a
// right-hand-side of a store operation.
// Find the next use of the variable in that store operation, and recursively find the load of that
// pointer. For example, consider this case:
//
// ```cpp
// int x = source();
// int* p = &x;
// sink(*p);
// ```
//
// if we want to find the load of the address of `x`, we see that the pointer is stored into `p`,
// and we then need to recursively look for the load of `p`.
exists(
Def def, StoreInstruction store, IRBlock block1, int rnk1, Use use, IRBlock block2, int rnk2
|
store = def.getInstruction() and
store.getSourceValueOperand() = operand and
def.hasRankInBlock(block1, rnk1) and
use.hasRankInBlock(block2, rnk2) and
adjacentDefRead(_, block1, rnk1, block2, rnk2)
|
// The shared SSA library has determined that `use` is the next use of the operand
// so we find the next load of that use (but only if there is no `PostUpdateNode`) we
// need to flow into first.
not StoreNodeFlow::flowInto(store, _) and
flowOutOfAddressStep(use.getOperand(), nodeTo)
or
// It may also be the case that `store` gives rise to another store step. So let's make sure that
// we also take those into account.
StoreNodeFlow::flowInto(store, nodeTo)
)
or
// As we find the next load of an address, we might come across another use of the same variable.
// In that case, we recursively find the next use of _that_ operand, and continue searching for
// the next load of that operand. For example, consider this case:
//
// ```cpp
// int x = source();
// use(&x);
// int* p = &x;
// sink(*p);
// ```
//
// The next use of `x` after its definition is `use(&x)`, but there is a later load of the address
// of `x` that we want to flow to. So we use the shared SSA library to find the next load.
not operand = getSourceAddressOperand(_) and
exists(Use use1, Use use2, IRBlock block1, int rnk1, IRBlock block2, int rnk2 |
use1.getOperand() = operand and
use1.hasRankInBlock(block1, rnk1) and
// Don't flow to the next use if this use is part of a store operation that totally
// overrides a variable.
not explicitWrite(true, _, use1.getOperand().getDef()) and
adjacentDefRead(_, block1, rnk1, block2, rnk2) and
use2.hasRankInBlock(block2, rnk2) and
flowOutOfAddressStep(use2.getOperand(), nodeTo)
)
or
operand = getSourceAddressOperand(nodeTo.asInstruction())
or
exists(ReturnIndirectionInstruction ret |

View File

@@ -20,14 +20,6 @@ private import internal.OperandInternal
private class TStageOperand =
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
/**
* A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as
* opposed to testing `not loc isntanceof UnknownLocation`
*/
private class KnownLocation extends Language::Location {
KnownLocation() { not this instanceof Language::UnknownLocation }
}
/**
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
* (the defining instruction) in another instruction (the use instruction)
@@ -53,10 +45,8 @@ class Operand extends TStageOperand {
/**
* Gets the location of the source code for this operand.
* By default this is where the operand is used, but some subclasses may override this
* using `getAnyDef()` if it makes more sense.
*/
Language::Location getLocation() { result = this.getUse().getLocation() }
final Language::Location getLocation() { result = this.getUse().getLocation() }
/**
* Gets the function that contains this operand.
@@ -279,10 +269,6 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
final override string toString() { result = tag.toString() }
// most `RegisterOperands` have a more meaningful location at the definition
// the only exception are specific cases of `ThisArgumentOperand`
override Language::Location getLocation() { result = this.getAnyDef().getLocation() }
final override Instruction getAnyDef() { result = defInstr }
final override Overlap getDefinitionOverlap() {
@@ -307,7 +293,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
final override string toString() { result = tag.toString() }
final override Instruction getAnyDef() {
result = unique(Instruction defInstr | this.hasDefinition(defInstr, _))
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
}
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
@@ -415,19 +401,11 @@ class ArgumentOperand extends RegisterOperand {
}
/**
* An operand representing the implicit `this` argument to a member function
* An operand representing the implicit 'this' argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand {
override ThisArgumentOperandTag tag;
// in most cases the def location makes more sense, but in some corner cases it
// has an unknown location: in those cases we fall back to the use location
override Language::Location getLocation() {
if this.getAnyDef().getLocation() instanceof KnownLocation
then result = this.getAnyDef().getLocation()
else result = this.getUse().getLocation()
}
}
/**

View File

@@ -20,14 +20,6 @@ private import internal.OperandInternal
private class TStageOperand =
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
/**
* A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as
* opposed to testing `not loc isntanceof UnknownLocation`
*/
private class KnownLocation extends Language::Location {
KnownLocation() { not this instanceof Language::UnknownLocation }
}
/**
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
* (the defining instruction) in another instruction (the use instruction)
@@ -53,10 +45,8 @@ class Operand extends TStageOperand {
/**
* Gets the location of the source code for this operand.
* By default this is where the operand is used, but some subclasses may override this
* using `getAnyDef()` if it makes more sense.
*/
Language::Location getLocation() { result = this.getUse().getLocation() }
final Language::Location getLocation() { result = this.getUse().getLocation() }
/**
* Gets the function that contains this operand.
@@ -279,10 +269,6 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
final override string toString() { result = tag.toString() }
// most `RegisterOperands` have a more meaningful location at the definition
// the only exception are specific cases of `ThisArgumentOperand`
override Language::Location getLocation() { result = this.getAnyDef().getLocation() }
final override Instruction getAnyDef() { result = defInstr }
final override Overlap getDefinitionOverlap() {
@@ -307,7 +293,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
final override string toString() { result = tag.toString() }
final override Instruction getAnyDef() {
result = unique(Instruction defInstr | this.hasDefinition(defInstr, _))
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
}
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
@@ -415,19 +401,11 @@ class ArgumentOperand extends RegisterOperand {
}
/**
* An operand representing the implicit `this` argument to a member function
* An operand representing the implicit 'this' argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand {
override ThisArgumentOperandTag tag;
// in most cases the def location makes more sense, but in some corner cases it
// has an unknown location: in those cases we fall back to the use location
override Language::Location getLocation() {
if this.getAnyDef().getLocation() instanceof KnownLocation
then result = this.getAnyDef().getLocation()
else result = this.getUse().getLocation()
}
}
/**

View File

@@ -20,14 +20,6 @@ private import internal.OperandInternal
private class TStageOperand =
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
/**
* A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as
* opposed to testing `not loc isntanceof UnknownLocation`
*/
private class KnownLocation extends Language::Location {
KnownLocation() { not this instanceof Language::UnknownLocation }
}
/**
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
* (the defining instruction) in another instruction (the use instruction)
@@ -53,10 +45,8 @@ class Operand extends TStageOperand {
/**
* Gets the location of the source code for this operand.
* By default this is where the operand is used, but some subclasses may override this
* using `getAnyDef()` if it makes more sense.
*/
Language::Location getLocation() { result = this.getUse().getLocation() }
final Language::Location getLocation() { result = this.getUse().getLocation() }
/**
* Gets the function that contains this operand.
@@ -279,10 +269,6 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
final override string toString() { result = tag.toString() }
// most `RegisterOperands` have a more meaningful location at the definition
// the only exception are specific cases of `ThisArgumentOperand`
override Language::Location getLocation() { result = this.getAnyDef().getLocation() }
final override Instruction getAnyDef() { result = defInstr }
final override Overlap getDefinitionOverlap() {
@@ -307,7 +293,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
final override string toString() { result = tag.toString() }
final override Instruction getAnyDef() {
result = unique(Instruction defInstr | this.hasDefinition(defInstr, _))
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
}
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
@@ -415,19 +401,11 @@ class ArgumentOperand extends RegisterOperand {
}
/**
* An operand representing the implicit `this` argument to a member function
* An operand representing the implicit 'this' argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand {
override ThisArgumentOperandTag tag;
// in most cases the def location makes more sense, but in some corner cases it
// has an unknown location: in those cases we fall back to the use location
override Language::Location getLocation() {
if this.getAnyDef().getLocation() instanceof KnownLocation
then result = this.getAnyDef().getLocation()
else result = this.getUse().getLocation()
}
}
/**

View File

@@ -34,16 +34,6 @@ private class IteratorByTraits extends Iterator {
IteratorByTraits() { exists(IteratorTraits it | it.getIteratorType() = this) }
}
/**
* The C++ standard includes an `std::iterator_traits` specialization for pointer types. When
* this specialization is included in the database, a pointer type `T*` will be an instance
* of the `IteratorByTraits` class. However, if the `T*` specialization is not in the database,
* we need to explicitly include them with this class.
*/
private class IteratorByPointer extends Iterator instanceof PointerType {
IteratorByPointer() { not this instanceof IteratorByTraits }
}
/**
* A type which has the typedefs expected for an iterator.
*/

View File

@@ -18,12 +18,12 @@ class SuppressionComment extends Comment {
(
this instanceof CppStyleComment and
// strip the beginning slashes
text = this.getContents().suffix(2)
text = getContents().suffix(2)
or
this instanceof CStyleComment and
// strip both the beginning /* and the end */ the comment
exists(string text0 |
text0 = this.getContents().suffix(2) and
text0 = getContents().suffix(2) and
text = text0.prefix(text0.length() - 2)
) and
// The /* */ comment must be a single-line comment

View File

@@ -153,12 +153,12 @@ class ExtClass extends Class {
}
predicate hasLocationInfo(string path, int startline, int startcol, int endline, int endcol) {
if this.hasOneVariableGroup()
if hasOneVariableGroup()
then
exists(VariableDeclarationGroup vdg | vdg.getClass() = this |
vdg.hasLocationInfo(path, startline, startcol, endline, endcol)
)
else this.getLocation().hasLocationInfo(path, startline, startcol, endline, endcol)
else getLocation().hasLocationInfo(path, startline, startcol, endline, endcol)
}
}

View File

@@ -50,16 +50,6 @@ predicate reachableThing(Thing t) {
exists(Thing mid | reachableThing(mid) and mid.callsOrAccesses() = t)
}
pragma[nomagic]
predicate callsOrAccessesPlus(Thing thing1, FunctionToRemove thing2) {
thing1.callsOrAccesses() = thing2
or
exists(Thing mid |
thing1.callsOrAccesses() = mid and
callsOrAccessesPlus(mid, thing2)
)
}
class Thing extends Locatable {
Thing() {
this instanceof Function or
@@ -91,7 +81,7 @@ class FunctionToRemove extends Function {
}
Thing getOther() {
callsOrAccessesPlus(result, this) and
result.callsOrAccesses+() = this and
this != result and
// We will already be reporting the enclosing function of a
// local variable, so don't also report the variable

View File

@@ -1,7 +0,0 @@
## 0.0.5
## 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

@@ -103,9 +103,9 @@ class CallWithBufferSize extends FunctionCall {
// `upperBound(e)` defaults to `exprMaxVal(e)` when `e` isn't analyzable. So to get a meaningful
// result in this case we pick the minimum value obtainable from dataflow and range analysis.
result =
upperBound(this.statedSizeExpr())
upperBound(statedSizeExpr())
.minimum(min(Expr statedSizeSrc |
DataFlow::localExprFlow(statedSizeSrc, this.statedSizeExpr())
DataFlow::localExprFlow(statedSizeSrc, statedSizeExpr())
|
statedSizeSrc.getValue().toInt()
))

View File

@@ -22,7 +22,7 @@ abstract class LockOperation extends FunctionCall {
ControlFlowNode getAReachedNode() {
result = this
or
exists(ControlFlowNode mid | mid = this.getAReachedNode() |
exists(ControlFlowNode mid | mid = getAReachedNode() |
not mid != this.getMatchingUnlock() and
result = mid.getASuccessor()
)

View File

@@ -156,8 +156,8 @@ abstract class LeapYearFieldAccess extends YearFieldAccess {
//
// https://aa.usno.navy.mil/faq/docs/calendars.php
this.isUsedInMod4Operation() and
this.additionalModulusCheckForLeapYear(400) and
this.additionalModulusCheckForLeapYear(100)
additionalModulusCheckForLeapYear(400) and
additionalModulusCheckForLeapYear(100)
}
}
@@ -176,17 +176,17 @@ class StructTmLeapYearFieldAccess extends LeapYearFieldAccess {
override predicate isUsedInCorrectLeapYearCheck() {
this.isUsedInMod4Operation() and
this.additionalModulusCheckForLeapYear(400) and
this.additionalModulusCheckForLeapYear(100) and
additionalModulusCheckForLeapYear(400) and
additionalModulusCheckForLeapYear(100) and
// tm_year represents years since 1900
(
this.additionalAdditionOrSubstractionCheckForLeapYear(1900)
additionalAdditionOrSubstractionCheckForLeapYear(1900)
or
// some systems may use 2000 for 2-digit year conversions
this.additionalAdditionOrSubstractionCheckForLeapYear(2000)
additionalAdditionOrSubstractionCheckForLeapYear(2000)
or
// converting from/to Unix epoch
this.additionalAdditionOrSubstractionCheckForLeapYear(1970)
additionalAdditionOrSubstractionCheckForLeapYear(1970)
)
}
}

View File

@@ -57,7 +57,7 @@ class LoopWithAlloca extends Stmt {
or
// `e == 0`
exists(EQExpr eq |
this.conditionRequires(eq, truth.booleanNot()) and
conditionRequires(eq, truth.booleanNot()) and
eq.getAnOperand().getValue().toInt() = 0 and
e = eq.getAnOperand() and
not exists(e.getValue())
@@ -65,7 +65,7 @@ class LoopWithAlloca extends Stmt {
or
// `e != 0`
exists(NEExpr eq |
this.conditionRequires(eq, truth) and
conditionRequires(eq, truth) and
eq.getAnOperand().getValue().toInt() = 0 and
e = eq.getAnOperand() and
not exists(e.getValue())
@@ -73,7 +73,7 @@ class LoopWithAlloca extends Stmt {
or
// `(bool)e == true`
exists(EQExpr eq |
this.conditionRequires(eq, truth) and
conditionRequires(eq, truth) and
eq.getAnOperand().getValue().toInt() = 1 and
e = eq.getAnOperand() and
e.getUnspecifiedType() instanceof BoolType and
@@ -82,7 +82,7 @@ class LoopWithAlloca extends Stmt {
or
// `(bool)e != true`
exists(NEExpr eq |
this.conditionRequires(eq, truth.booleanNot()) and
conditionRequires(eq, truth.booleanNot()) and
eq.getAnOperand().getValue().toInt() = 1 and
e = eq.getAnOperand() and
e.getUnspecifiedType() instanceof BoolType and
@@ -90,7 +90,7 @@ class LoopWithAlloca extends Stmt {
)
or
exists(NotExpr notExpr |
this.conditionRequires(notExpr, truth.booleanNot()) and
conditionRequires(notExpr, truth.booleanNot()) and
e = notExpr.getOperand()
)
or
@@ -98,7 +98,7 @@ class LoopWithAlloca extends Stmt {
// requires both of its operand to be true as well.
exists(LogicalAndExpr andExpr |
truth = true and
this.conditionRequires(andExpr, truth) and
conditionRequires(andExpr, truth) and
e = andExpr.getAnOperand()
)
or
@@ -106,7 +106,7 @@ class LoopWithAlloca extends Stmt {
// it requires both of its operand to be false as well.
exists(LogicalOrExpr orExpr |
truth = false and
this.conditionRequires(orExpr, truth) and
conditionRequires(orExpr, truth) and
e = orExpr.getAnOperand()
)
}
@@ -141,9 +141,9 @@ class LoopWithAlloca extends Stmt {
* `conditionRequiresInequality`.
*/
private Variable getAControllingVariable() {
this.conditionRequires(result.getAnAccess(), _)
conditionRequires(result.getAnAccess(), _)
or
this.conditionRequiresInequality(result.getAnAccess(), _, _)
conditionRequiresInequality(result.getAnAccess(), _, _)
}
/**

View File

@@ -61,72 +61,72 @@ class PointerArithmeticAccess extends BufferAccess, Expr {
* A pair of buffer accesses through a call to memcpy.
*/
class MemCpy extends BufferAccess, FunctionCall {
MemCpy() { this.getTarget().hasName("memcpy") }
MemCpy() { getTarget().hasName("memcpy") }
override Expr getPointer() {
result = this.getArgument(0) or
result = this.getArgument(1)
result = getArgument(0) or
result = getArgument(1)
}
override Expr getAccessedLength() { result = this.getArgument(2) }
override Expr getAccessedLength() { result = getArgument(2) }
}
class StrncpySizeExpr extends BufferAccess, FunctionCall {
StrncpySizeExpr() { this.getTarget().hasName("strncpy") }
StrncpySizeExpr() { getTarget().hasName("strncpy") }
override Expr getPointer() {
result = this.getArgument(0) or
result = this.getArgument(1)
result = getArgument(0) or
result = getArgument(1)
}
override Expr getAccessedLength() { result = this.getArgument(2) }
override Expr getAccessedLength() { result = getArgument(2) }
}
class RecvSizeExpr extends BufferAccess, FunctionCall {
RecvSizeExpr() { this.getTarget().hasName("recv") }
RecvSizeExpr() { getTarget().hasName("recv") }
override Expr getPointer() { result = this.getArgument(1) }
override Expr getPointer() { result = getArgument(1) }
override Expr getAccessedLength() { result = this.getArgument(2) }
override Expr getAccessedLength() { result = getArgument(2) }
}
class SendSizeExpr extends BufferAccess, FunctionCall {
SendSizeExpr() { this.getTarget().hasName("send") }
SendSizeExpr() { getTarget().hasName("send") }
override Expr getPointer() { result = this.getArgument(1) }
override Expr getPointer() { result = getArgument(1) }
override Expr getAccessedLength() { result = this.getArgument(2) }
override Expr getAccessedLength() { result = getArgument(2) }
}
class SnprintfSizeExpr extends BufferAccess, FunctionCall {
SnprintfSizeExpr() { this.getTarget().hasName("snprintf") }
SnprintfSizeExpr() { getTarget().hasName("snprintf") }
override Expr getPointer() { result = this.getArgument(0) }
override Expr getPointer() { result = getArgument(0) }
override Expr getAccessedLength() { result = this.getArgument(1) }
override Expr getAccessedLength() { result = getArgument(1) }
}
class MemcmpSizeExpr extends BufferAccess, FunctionCall {
MemcmpSizeExpr() { this.getTarget().hasName("Memcmp") }
MemcmpSizeExpr() { getTarget().hasName("Memcmp") }
override Expr getPointer() {
result = this.getArgument(0) or
result = this.getArgument(1)
result = getArgument(0) or
result = getArgument(1)
}
override Expr getAccessedLength() { result = this.getArgument(2) }
override Expr getAccessedLength() { result = getArgument(2) }
}
class MallocSizeExpr extends BufferAccess, FunctionCall {
MallocSizeExpr() { this.getTarget().hasName("malloc") }
MallocSizeExpr() { getTarget().hasName("malloc") }
override Expr getPointer() { none() }
override Expr getAccessedLength() { result = this.getArgument(0) }
override Expr getAccessedLength() { result = getArgument(0) }
}
class NetworkFunctionCall extends FunctionCall {
NetworkFunctionCall() { this.getTarget().hasName(["ntohd", "ntohf", "ntohl", "ntohll", "ntohs"]) }
NetworkFunctionCall() { getTarget().hasName(["ntohd", "ntohf", "ntohl", "ntohll", "ntohs"]) }
}
class NetworkToBufferSizeConfiguration extends DataFlow::Configuration {

View File

@@ -3,10 +3,8 @@
* @description Using the TLS or SSLv23 protocol from the boost::asio library, but not disabling deprecated protocols, or disabling minimum-recommended protocols.
* @kind problem
* @problem.severity error
* @security-severity 7.5
* @id cpp/boost/tls-settings-misconfiguration
* @tags security
* external/cwe/cwe-326
*/
import cpp

View File

@@ -3,10 +3,8 @@
* @description Using a deprecated hard-coded protocol using the boost::asio library.
* @kind problem
* @problem.severity error
* @security-severity 7.5
* @id cpp/boost/use-of-deprecated-hardcoded-security-protocol
* @tags security
* external/cwe/cwe-327
*/
import cpp

View File

@@ -13,7 +13,7 @@ import cpp
class MacroFunctionCall extends MacroInvocation {
MacroFunctionCall() {
not exists(this.getParentInvocation()) and
not exists(getParentInvocation()) and
this.getMacro().getHead().matches("%(%")
}

View File

@@ -13,7 +13,7 @@ import semmle.code.cpp.commons.Assertions
class MacroFunctionCall extends MacroInvocation {
MacroFunctionCall() {
not exists(this.getParentInvocation()) and
not exists(getParentInvocation()) and
this.getMacro().getHead().matches("%(%")
}

View File

@@ -38,7 +38,7 @@ class ExternalAPIDataNode extends DataFlow::Node {
int getIndex() { result = i }
/** Gets the description of the function being called. */
string getFunctionDescription() { result = this.getExternalFunction().toString() }
string getFunctionDescription() { result = getExternalFunction().toString() }
}
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalAPIDataNode`s. */

View File

@@ -38,7 +38,7 @@ class ExternalAPIDataNode extends DataFlow::Node {
int getIndex() { result = i }
/** Gets the description of the function being called. */
string getFunctionDescription() { result = this.getExternalFunction().toString() }
string getFunctionDescription() { result = getExternalFunction().toString() }
}
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalAPIDataNode`s. */

View File

@@ -42,7 +42,7 @@ class VarargsFunction extends Function {
}
private int trailingArgValueCount(string value) {
result = strictcount(FunctionCall fc | this.trailingArgValue(fc) = value)
result = strictcount(FunctionCall fc | trailingArgValue(fc) = value)
}
string nonTrailingVarArgValue(FunctionCall fc, int index) {
@@ -58,11 +58,11 @@ class VarargsFunction extends Function {
string normalTerminator(int cnt) {
result = ["0", "-1"] and
cnt = this.trailingArgValueCount(result) and
2 * cnt > this.totalCount() and
cnt = trailingArgValueCount(result) and
2 * cnt > totalCount() and
not exists(FunctionCall fc, int index |
// terminator value is used in a non-terminating position
this.nonTrailingVarArgValue(fc, index) = result
nonTrailingVarArgValue(fc, index) = result
)
}

View File

@@ -42,7 +42,7 @@ class TaintSource extends VariableAccess {
definitionUsePair(_, this, va)
or
exists(VariableAccess mid, Expr def |
this.sourceReaches(mid) and
sourceReaches(mid) and
exprDefinition(_, def, mid) and
definitionUsePair(_, def, va)
)
@@ -53,11 +53,11 @@ class TaintSource extends VariableAccess {
* from `va`, possibly using intermediate reassignments.
*/
private predicate reachesSink(VariableAccess va, VariableAccess sink) {
this.isSink(sink) and
isSink(sink) and
va = sink
or
exists(VariableAccess mid, Expr def |
this.reachesSink(mid, sink) and
reachesSink(mid, sink) and
exprDefinition(_, def, va) and
definitionUsePair(_, def, mid)
)
@@ -71,15 +71,15 @@ class TaintSource extends VariableAccess {
* this source to `sink` found via `tainted(source, sink)`.)
*/
predicate reaches(VariableAccess sink) {
this.isSink(sink) and
isSink(sink) and
not exists(VariableAccess va |
va != this and
va != sink and
mayAddNullTerminator(_, va)
|
this.sourceReaches(va)
sourceReaches(va)
or
this.reachesSink(va, sink)
reachesSink(va, sink)
)
}
}

View File

@@ -1,28 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>When checking the result of SSL certificate verification, accepting any error code may allow an attacker to impersonate someone who is trusted.</p>
</overview>
<recommendation>
<p>When checking an SSL certificate with <code>SSL_get_verify_result</code>, only <code>X509_V_OK</code> is a success code. If there is any other result the certificate should not be accepted.</p>
</recommendation>
<example>
<p>In this example the error code <code>X509_V_ERR_CERT_HAS_EXPIRED</code> is treated the same as an OK result. An expired certificate should not be accepted as it is more likely to be compromised than a valid certificate.</p>
<sample src="SSLResultConflationBad.cpp" />
<p>In the corrected example, only a result of <code>X509_V_OK</code> is accepted.</p>
<sample src="SSLResultConflationGood.cpp" />
</example>
<references>
</references>
</qhelp>

View File

@@ -1,50 +0,0 @@
/**
* @name Certificate result conflation
* @description Only accept SSL certificates that pass certificate verification.
* @kind problem
* @problem.severity error
* @security-severity 7.5
* @precision medium
* @id cpp/certificate-result-conflation
* @tags security
* external/cwe/cwe-295
*/
import cpp
import semmle.code.cpp.controlflow.Guards
import semmle.code.cpp.dataflow.DataFlow
/**
* A call to `SSL_get_verify_result`.
*/
class SSLGetVerifyResultCall extends FunctionCall {
SSLGetVerifyResultCall() { getTarget().getName() = "SSL_get_verify_result" }
}
/**
* Data flow from a call to `SSL_get_verify_result` to a guard condition
* that references the result.
*/
class VerifyResultConfig extends DataFlow::Configuration {
VerifyResultConfig() { this = "VerifyResultConfig" }
override predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof SSLGetVerifyResultCall
}
override predicate isSink(DataFlow::Node sink) {
exists(GuardCondition guard | guard.getAChild*() = sink.asExpr())
}
}
from
VerifyResultConfig config, DataFlow::Node source, DataFlow::Node sink1, DataFlow::Node sink2,
GuardCondition guard, Expr c1, Expr c2, boolean testIsTrue
where
config.hasFlow(source, sink1) and
config.hasFlow(source, sink2) and
guard.comparesEq(sink1.asExpr(), c1, 0, false, testIsTrue) and // (value != c1) => testIsTrue
guard.comparesEq(sink2.asExpr(), c2, 0, false, testIsTrue) and // (value != c2) => testIsTrue
c1.getValue().toInt() = 0 and
c2.getValue().toInt() != 0
select guard, "This expression conflates OK and non-OK results from $@.", source, source.toString()

View File

@@ -1,13 +0,0 @@
// ...
if (cert = SSL_get_peer_certificate(ssl))
{
result = SSL_get_verify_result(ssl);
if ((result == X509_V_OK) || (result == X509_V_ERR_CERT_HAS_EXPIRED)) // BAD (conflates OK and a non-OK codes)
{
do_ok();
} else {
do_error();
}
}

View File

@@ -1,13 +0,0 @@
// ...
if (cert = SSL_get_peer_certificate(ssl))
{
result = SSL_get_verify_result(ssl);
if (result == X509_V_OK) // GOOD
{
do_ok();
} else {
do_error();
}
}

View File

@@ -1,28 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>After fetching an SSL certificate, always check the result of certificate verification.</p>
</overview>
<recommendation>
<p>Always check the result of SSL certificate verification. A certificate that has been revoked may indicate that data is coming from an attacker, whereas a certificate that has expired or was self-signed may indicate an increased likelihood that the data is malicious.</p>
</recommendation>
<example>
<p>In this example, the <code>SSL_get_peer_certificate</code> function is used to get the certificate of a peer. However it is unsafe to use that information without checking if the certificate is valid.</p>
<sample src="SSLResultNotCheckedBad.cpp" />
<p>In the corrected example, we use <code>SSL_get_verify_result</code> to check that certificate verification was successful.</p>
<sample src="SSLResultNotCheckedGood.cpp" />
</example>
<references>
</references>
</qhelp>

View File

@@ -1,120 +0,0 @@
/**
* @name Certificate not checked
* @description Always check the result of certificate verification after fetching an SSL certificate.
* @kind problem
* @problem.severity error
* @security-severity 7.5
* @precision medium
* @id cpp/certificate-not-checked
* @tags security
* external/cwe/cwe-295
*/
import cpp
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.controlflow.IRGuards
/**
* A call to `SSL_get_peer_certificate`.
*/
class SSLGetPeerCertificateCall extends FunctionCall {
SSLGetPeerCertificateCall() {
getTarget().getName() = "SSL_get_peer_certificate" // SSL_get_peer_certificate(ssl)
}
Expr getSSLArgument() { result = getArgument(0) }
}
/**
* A call to `SSL_get_verify_result`.
*/
class SSLGetVerifyResultCall extends FunctionCall {
SSLGetVerifyResultCall() {
getTarget().getName() = "SSL_get_verify_result" // SSL_get_peer_certificate(ssl)
}
Expr getSSLArgument() { result = getArgument(0) }
}
/**
* Holds if the SSL object passed into `SSL_get_peer_certificate` is checked with
* `SSL_get_verify_result` entering `node`.
*/
predicate resultIsChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) {
exists(Expr ssl, SSLGetVerifyResultCall check |
ssl = globalValueNumber(getCertCall.getSSLArgument()).getAnExpr() and
ssl = check.getSSLArgument() and
node = check
)
}
/**
* Holds if the certificate returned by `SSL_get_peer_certificate` is found to be
* `0` on the edge `node1` to `node2`.
*/
predicate certIsZero(
SSLGetPeerCertificateCall getCertCall, ControlFlowNode node1, ControlFlowNode node2
) {
exists(Expr cert | cert = globalValueNumber(getCertCall).getAnExpr() |
exists(GuardCondition guard, Expr zero |
zero.getValue().toInt() = 0 and
node1 = guard and
(
// if (cert == zero) {
guard.comparesEq(cert, zero, 0, true, true) and
node2 = guard.getATrueSuccessor()
or
// if (cert != zero) { }
guard.comparesEq(cert, zero, 0, false, true) and
node2 = guard.getAFalseSuccessor()
)
)
or
(
// if (cert) { }
node1 = cert
or
// if (!cert) {
node1.(NotExpr).getAChild() = cert
) and
node2 = node1.getASuccessor() and
not cert.(GuardCondition).controls(node2, true) // cert may be false
)
}
/**
* Holds if the SSL object passed into `SSL_get_peer_certificate` has not been checked with
* `SSL_get_verify_result` at `node`. Note that this is only computed at the call to
* `SSL_get_peer_certificate` and at the start and end of `BasicBlock`s.
*/
predicate certNotChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) {
// cert is not checked at the call to `SSL_get_peer_certificate`
node = getCertCall
or
exists(BasicBlock bb, int pos |
// flow to end of a `BasicBlock`
certNotChecked(getCertCall, bb.getNode(pos)) and
node = bb.getEnd() and
// check for barrier node
not exists(int pos2 |
pos2 > pos and
resultIsChecked(getCertCall, bb.getNode(pos2))
)
)
or
exists(BasicBlock pred, BasicBlock bb |
// flow from the end of one `BasicBlock` to the beginning of a successor
certNotChecked(getCertCall, pred.getEnd()) and
bb = pred.getASuccessor() and
node = bb.getStart() and
// check for barrier bb
not certIsZero(getCertCall, pred.getEnd(), bb.getStart())
)
}
from SSLGetPeerCertificateCall getCertCall, ControlFlowNode node
where
certNotChecked(getCertCall, node) and
node instanceof Function // (function exit)
select getCertCall,
"This " + getCertCall.toString() + " is not followed by a call to SSL_get_verify_result."

View File

@@ -1,5 +0,0 @@
// ...
X509 *cert = SSL_get_peer_certificate(ssl); // BAD (SSL_get_verify_result is never called)
// ...

View File

@@ -1,9 +0,0 @@
// ...
X509 *cert = SSL_get_peer_certificate(ssl); // GOOD
if (cert)
{
result = SSL_get_verify_result(ssl);
if (result == X509_V_OK)
{
// ...

View File

@@ -8,7 +8,6 @@
* @precision high
* @id cpp/cleartext-storage-file
* @tags security
* external/cwe/cwe-260
* external/cwe/cwe-313
*/

View File

@@ -29,7 +29,7 @@ class SqliteFunctionCall extends FunctionCall {
}
predicate sqlite_encryption_used() {
any(StringLiteral l).getValue().toLowerCase().matches("pragma key%") or
any(StringLiteral l).getValue().toLowerCase().regexpMatch("pragma key.*") or
any(StringLiteral l).getValue().toLowerCase().matches("%attach%database%key%") or
any(FunctionCall fc).getTarget().getName().matches("sqlite%\\_key\\_%")
}

View File

@@ -1,9 +0,0 @@
void openUrl(char *url)
{
// ...
}
openUrl("http://example.com"); // BAD
openUrl("https://example.com"); // GOOD: Opening a connection to a URL using HTTPS enforces SSL.

View File

@@ -1,35 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Constructing URLs with the HTTP protocol can lead to unsecured connections.</p>
</overview>
<recommendation>
<p>When you construct a URL, ensure that you use an HTTPS URL rather than an HTTP URL. Then, any connections that are made using that URL are secure SSL connections.</p>
</recommendation>
<example>
<p>The following example shows two ways of opening a connection using a URL. When the connection is
opened using an HTTP URL rather than an HTTPS URL, the connection is unsecured. When the connection is opened using an HTTPS URL, the connection is a secure SSL connection.</p>
<sample src="UseOfHttp.cpp" />
</example>
<references>
<li>
OWASP:
<a href="https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html">Transport Layer Protection Cheat Sheet</a>.
</li>
<li>
OWASP Top 10:
<a href="https://owasp.org/Top10/A08_2021-Software_and_Data_Integrity_Failures/">A08:2021 - Software and Data Integrity Failures</a>.
</li>
</references>
</qhelp>

View File

@@ -1,90 +0,0 @@
/**
* @name Failure to use HTTPS URLs
* @description Non-HTTPS connections can be intercepted by third parties.
* @kind path-problem
* @problem.severity warning
* @precision medium
* @id cpp/non-https-url
* @tags security
* external/cwe/cwe-319
* external/cwe/cwe-345
*/
import cpp
import semmle.code.cpp.dataflow.TaintTracking
import DataFlow::PathGraph
/**
* A string matching private host names of IPv4 and IPv6, which only matches
* the host portion therefore checking for port is not necessary.
* Several examples are localhost, reserved IPv4 IP addresses including
* 127.0.0.1, 10.x.x.x, 172.16.x,x, 192.168.x,x, and reserved IPv6 addresses
* including [0:0:0:0:0:0:0:1] and [::1]
*/
class PrivateHostName extends string {
bindingset[this]
PrivateHostName() {
this.regexpMatch("(?i)localhost(?:[:/?#].*)?|127\\.0\\.0\\.1(?:[:/?#].*)?|10(?:\\.[0-9]+){3}(?:[:/?#].*)?|172\\.16(?:\\.[0-9]+){2}(?:[:/?#].*)?|192.168(?:\\.[0-9]+){2}(?:[:/?#].*)?|\\[?0:0:0:0:0:0:0:1\\]?(?:[:/?#].*)?|\\[?::1\\]?(?:[:/?#].*)?")
}
}
/**
* A string containing an HTTP URL not in a private domain.
*/
class HttpStringLiteral extends StringLiteral {
HttpStringLiteral() {
exists(string s | this.getValue() = s |
s = "http"
or
exists(string tail |
tail = s.regexpCapture("http://(.*)", 1) and not tail instanceof PrivateHostName
) and
not TaintTracking::localExprTaint(any(StringLiteral p |
p.getValue() instanceof PrivateHostName
), this.getParent*())
)
}
}
/**
* Taint tracking configuration for HTTP connections.
*/
class HttpStringToUrlOpenConfig extends TaintTracking::Configuration {
HttpStringToUrlOpenConfig() { this = "HttpStringToUrlOpenConfig" }
override predicate isSource(DataFlow::Node src) {
// Sources are strings containing an HTTP URL not in a private domain.
src.asExpr() instanceof HttpStringLiteral
}
override predicate isSink(DataFlow::Node sink) {
// Sinks can be anything that demonstrates the string is likely to be
// accessed as a URL, for example using it in a network access. Some
// URLs are only ever displayed or used for data processing.
exists(FunctionCall fc |
fc.getTarget()
.hasGlobalOrStdName([
"system", "gethostbyname", "gethostbyname2", "gethostbyname_r", "getaddrinfo",
"X509_load_http", "X509_CRL_load_http"
]) and
sink.asExpr() = fc.getArgument(0)
or
fc.getTarget().hasGlobalOrStdName(["send", "URLDownloadToFile", "URLDownloadToCacheFile"]) and
sink.asExpr() = fc.getArgument(1)
or
fc.getTarget().hasGlobalOrStdName(["curl_easy_setopt", "getnameinfo"]) and
sink.asExpr() = fc.getArgument(2)
or
fc.getTarget().hasGlobalOrStdName(["ShellExecute", "ShellExecuteA", "ShellExecuteW"]) and
sink.asExpr() = fc.getArgument(3)
)
}
}
from
HttpStringToUrlOpenConfig config, DataFlow::PathNode source, DataFlow::PathNode sink,
HttpStringLiteral str
where
config.hasFlowPath(source, sink) and
str = source.getNode().asExpr()
select str, source, sink, "A URL may be constructed with the HTTP protocol."

View File

@@ -84,8 +84,8 @@ class ParameterNullCheck extends ParameterCheck {
p.getFunction() instanceof InitializationFunction and
p.getType().getUnspecifiedType() instanceof PointerType and
exists(VariableAccess va | va = p.getAnAccess() |
nullSuccessor = this.getATrueSuccessor() and
notNullSuccessor = this.getAFalseSuccessor() and
nullSuccessor = getATrueSuccessor() and
notNullSuccessor = getAFalseSuccessor() and
(
va = this.(NotExpr).getOperand() or
va = any(EQExpr eq | eq = this and eq.getAnOperand().getValue() = "0").getAnOperand() or
@@ -95,8 +95,8 @@ class ParameterNullCheck extends ParameterCheck {
.getAnOperand()
)
or
nullSuccessor = this.getAFalseSuccessor() and
notNullSuccessor = this.getATrueSuccessor() and
nullSuccessor = getAFalseSuccessor() and
notNullSuccessor = getATrueSuccessor() and
(
va = this or
va = any(NEExpr eq | eq = this and eq.getAnOperand().getValue() = "0").getAnOperand() or
@@ -132,7 +132,7 @@ class ValidatedExternalCondInitFunction extends ExternalData {
ValidatedExternalCondInitFunction() { this.getDataPath().matches("%cond-init%.csv") }
predicate isExternallyVerified(Function f, int param) {
functionSignature(f, this.getField(1), this.getField(2)) and param = this.getFieldAsInt(3)
functionSignature(f, getField(1), getField(2)) and param = getFieldAsInt(3)
}
}
@@ -193,7 +193,7 @@ class InitializationFunction extends Function {
.getAnOverridingFunction+()
.(InitializationFunction)
.initializedParameter() or
this.getParameter(i) = any(InitializationFunctionCall c).getAnInitParameter()
getParameter(i) = any(InitializationFunctionCall c).getAnInitParameter()
)
or
// If we have no definition, we look at SAL annotations
@@ -227,7 +227,7 @@ class InitializationFunction extends Function {
result = getAnInitializedArgument(any(Call c))
or
exists(IfStmt check | result = check.getCondition().getAChild*() |
this.paramReassignmentCondition(check)
paramReassignmentCondition(check)
)
)
or
@@ -249,15 +249,15 @@ class InitializationFunction extends Function {
/** Holds if `n` can be reached without the parameter at `index` being reassigned. */
predicate paramNotReassignedAt(ControlFlowNode n, int index, Context c) {
c = this.getAContext(index) and
c = getAContext(index) and
(
not exists(this.getEntryPoint()) and index = i and n = this
or
n = this.getEntryPoint() and index = i
or
exists(ControlFlowNode mid | this.paramNotReassignedAt(mid, index, c) |
exists(ControlFlowNode mid | paramNotReassignedAt(mid, index, c) |
n = mid.getASuccessor() and
not n = this.paramReassignment(index) and
not n = paramReassignment(index) and
/*
* Ignore successor edges where the parameter is null, because it is then confirmed to be
* initialized.
@@ -265,7 +265,7 @@ class InitializationFunction extends Function {
not exists(ParameterNullCheck nullCheck |
nullCheck = mid and
nullCheck = this.getANullCheck(index) and
nullCheck = getANullCheck(index) and
n = nullCheck.getNullSuccessor()
) and
/*
@@ -281,13 +281,13 @@ class InitializationFunction extends Function {
/** Gets a null-check on the parameter at `index`. */
private ParameterNullCheck getANullCheck(int index) {
this.getParameter(index) = result.getParameter()
getParameter(index) = result.getParameter()
}
/** Gets a parameter which is not at the given index. */
private Parameter getOtherParameter(int index) {
index = i and
result = this.getAParameter() and
result = getAParameter() and
not result.getIndex() = index
}
@@ -306,10 +306,10 @@ class InitializationFunction extends Function {
if
strictcount(Parameter p |
exists(Context c | c = ParamNull(p) or c = ParamNotNull(p)) and
p = this.getOtherParameter(index)
p = getOtherParameter(index)
) = 1
then
exists(Parameter p | p = this.getOtherParameter(index) |
exists(Parameter p | p = getOtherParameter(index) |
result = ParamNull(p) or result = ParamNotNull(p)
)
else
@@ -424,8 +424,8 @@ class ConditionalInitializationCall extends FunctionCall {
/** Gets the argument passed for the given parameter to this call. */
Expr getArgumentForParameter(Parameter p) {
p = this.getTarget().getAParameter() and
result = this.getArgument(p.getIndex())
p = getTarget().getAParameter() and
result = getArgument(p.getIndex())
}
/**
@@ -442,7 +442,7 @@ class ConditionalInitializationCall extends FunctionCall {
context = ParamNotNull(otherP) or
context = ParamNull(otherP)
|
otherArg = this.getArgumentForParameter(otherP) and
otherArg = getArgumentForParameter(otherP) and
(otherArg instanceof AddressOfExpr implies context = ParamNotNull(otherP)) and
(otherArg.getType() instanceof ArrayType implies context = ParamNotNull(otherP)) and
(otherArg.getValue() = "0" implies context = ParamNull(otherP))
@@ -511,8 +511,8 @@ class ConditionalInitializationCall extends FunctionCall {
)
)
or
exists(ControlFlowNode mid | mid = this.uncheckedReaches(var) |
not mid = this.getStatusVariable().getAnAccess() and
exists(ControlFlowNode mid | mid = uncheckedReaches(var) |
not mid = getStatusVariable().getAnAccess() and
not mid = var.getAnAccess() and
not exists(VariableAccess write | result = write and write = var.getAnAccess() |
write = any(AssignExpr a).getLValue() or

View File

@@ -44,7 +44,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
// Find a call that conditionally initializes this variable
hasConditionalInitialization(f, call, this, initAccess, e) and
// Ignore cases where the variable is assigned prior to the call
not reaches(this.getAnAssignedValue(), initAccess) and
not reaches(getAnAssignedValue(), initAccess) and
// Ignore cases where the variable is assigned field-wise prior to the call.
not exists(FieldAccess fa |
exists(Assignment a |
@@ -56,7 +56,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
) and
// Ignore cases where the variable is assigned by a prior call to an initialization function
not exists(Call c |
this.getAnAccess() = getAnInitializedArgument(c).(AddressOfExpr).getOperand() and
getAnAccess() = getAnInitializedArgument(c).(AddressOfExpr).getOperand() and
reaches(c, initAccess)
) and
/*
@@ -64,7 +64,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
* the CFG, but should always be considered as initialized, so exclude them.
*/
not exists(this.getInitializer().getExpr())
not exists(getInitializer().getExpr())
}
/**
@@ -90,7 +90,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
// Variable associated with this particular call
call = initializingCall and
// Access is a meaningful read access
result = this.getAReadAccess() and
result = getAReadAccess() and
// Which occurs after the call
reaches(call, result) and
/*
@@ -124,7 +124,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
call = initializingCall and
initializingFunction = f and
e = evidence and
result = this.getAReadAccessAfterCall(initializingCall) and
result = getAReadAccessAfterCall(initializingCall) and
(
// Access is risky because status return code ignored completely
call instanceof ExprInVoidContext
@@ -148,7 +148,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
call = initializingCall and
initializingFunction = f and
e = evidence and
result = this.getAReadAccessAfterCall(initializingCall) and
result = getAReadAccessAfterCall(initializingCall) and
exists(LocalVariable status, Assignment a |
a.getRValue() = call and
call = status.getAnAssignedValue() and
@@ -184,7 +184,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
ConditionalInitializationFunction initializingFunction,
ConditionalInitializationCall initializingCall, Evidence evidence
) {
result = this.getARiskyAccessBeforeStatusCheck(initializingFunction, initializingCall, evidence) or
result = this.getARiskyAccessWithNoStatusCheck(initializingFunction, initializingCall, evidence)
result = getARiskyAccessBeforeStatusCheck(initializingFunction, initializingCall, evidence) or
result = getARiskyAccessWithNoStatusCheck(initializingFunction, initializingCall, evidence)
}
}

View File

@@ -31,15 +31,15 @@ abstract class SystemData extends Element {
*/
Expr getAnExprIndirect() {
// direct SystemData
result = this.getAnExpr() or
result = getAnExpr() or
// flow via global or member variable (conservative approximation)
result = this.getAnAffectedVar().getAnAccess() or
result = getAnAffectedVar().getAnAccess() or
// flow via stack variable
definitionUsePair(_, this.getAnExprIndirect(), result) or
useUsePair(_, this.getAnExprIndirect(), result) or
useUsePair(_, result, this.getAnExprIndirect()) or
definitionUsePair(_, getAnExprIndirect(), result) or
useUsePair(_, getAnExprIndirect(), result) or
useUsePair(_, result, getAnExprIndirect()) or
// flow from assigned value to assignment expression
result.(AssignExpr).getRValue() = this.getAnExprIndirect()
result.(AssignExpr).getRValue() = getAnExprIndirect()
}
/**

View File

@@ -67,16 +67,16 @@ class IFStream extends Type {
*/
class CinVariable extends NamespaceVariable {
CinVariable() {
this.getName() = ["cin", "wcin"] and
this.getNamespace().getName() = "std"
getName() = ["cin", "wcin"] and
getNamespace().getName() = "std"
}
}
/** A call to `std::operator>>`. */
class OperatorRShiftCall extends FunctionCall {
OperatorRShiftCall() {
this.getTarget().getNamespace().getName() = "std" and
this.getTarget().hasName("operator>>")
getTarget().getNamespace().getName() = "std" and
getTarget().hasName("operator>>")
}
/*
@@ -87,15 +87,15 @@ class OperatorRShiftCall extends FunctionCall {
*/
Expr getSource() {
if this.getTarget() instanceof MemberFunction
then result = this.getQualifier()
else result = this.getArgument(0)
if getTarget() instanceof MemberFunction
then result = getQualifier()
else result = getArgument(0)
}
Expr getDest() {
if this.getTarget() instanceof MemberFunction
then result = this.getArgument(0)
else result = this.getArgument(1)
if getTarget() instanceof MemberFunction
then result = getArgument(0)
else result = getArgument(1)
}
}
@@ -119,7 +119,7 @@ abstract class PotentiallyDangerousInput extends Expr {
* Gets the width restriction that applies to the input stream
* for this expression, if any.
*/
Expr getWidth() { result = this.getPreviousAccess().getWidthAfter() }
Expr getWidth() { result = getPreviousAccess().getWidthAfter() }
private Expr getWidthSetHere() {
exists(FunctionCall widthCall |
@@ -154,11 +154,11 @@ abstract class PotentiallyDangerousInput extends Expr {
* after this expression, if any.
*/
Expr getWidthAfter() {
result = this.getWidthSetHere()
result = getWidthSetHere()
or
not exists(this.getWidthSetHere()) and
not this.isWidthConsumedHere() and
result = this.getWidth()
not exists(getWidthSetHere()) and
not isWidthConsumedHere() and
result = getWidth()
}
}

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 +0,0 @@
## 0.0.5

View File

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

View File

@@ -21,9 +21,9 @@ predicate argumentMayBeRoot(Expr e) {
class SetuidLikeFunctionCall extends FunctionCall {
SetuidLikeFunctionCall() {
(this.getTarget().hasGlobalName("setuid") or this.getTarget().hasGlobalName("setresuid")) and
(getTarget().hasGlobalName("setuid") or getTarget().hasGlobalName("setresuid")) and
// setuid/setresuid with the root user are false positives.
not argumentMayBeRoot(this.getArgument(0))
not argumentMayBeRoot(getArgument(0))
}
}
@@ -44,7 +44,7 @@ class SetuidLikeWrapperCall extends FunctionCall {
class CallBeforeSetuidFunctionCall extends FunctionCall {
CallBeforeSetuidFunctionCall() {
this.getTarget()
getTarget()
.hasGlobalName([
"setgid", "setresgid",
// Compatibility may require skipping initgroups and setgroups return checks.
@@ -52,7 +52,7 @@ class CallBeforeSetuidFunctionCall extends FunctionCall {
"initgroups", "setgroups"
]) and
// setgid/setresgid/etc with the root group are false positives.
not argumentMayBeRoot(this.getArgument(0))
not argumentMayBeRoot(getArgument(0))
}
}

View File

@@ -1,14 +0,0 @@
...
fp = fopen("/tmp/name.tmp","w"); // BAD
...
char filename = tmpnam(NULL);
fp = fopen(filename,"w"); // BAD
...
strcat (filename, "/tmp/name.XXXXXX");
fd = mkstemp(filename);
if ( fd < 0 ) {
return error;
}
fp = fdopen(fd,"w") // GOOD
...

View File

@@ -1,23 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Working with a file, without checking its existence and its rights, as well as working with names that can be predicted, may not be safe. Requires the attention of developers.</p>
</overview>
<example>
<p>The following example demonstrates erroneous and corrected work with file.</p>
<sample src="InsecureTemporaryFile.cpp" />
</example>
<references>
<li>
CERT C Coding Standard:
<a href="https://wiki.sei.cmu.edu/confluence/display/c/CON33-C.+Avoid+race+conditions+when+using+library+functions">CON33-C. Avoid race conditions when using library functions</a>.
</li>
</references>
</qhelp>

View File

@@ -1,112 +0,0 @@
/**
* @name Insecure generation of filenames.
* @description Using a predictable filename when creating a temporary file can lead to an attacker-controlled input.
* @kind problem
* @id cpp/insecure-generation-of-filename
* @problem.severity warning
* @precision medium
* @tags correctness
* security
* external/cwe/cwe-377
*/
import cpp
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
/** Holds for a function `f` that has an argument at index `apos` used to read the file. */
predicate numberArgumentRead(Function f, int apos) {
f.hasGlobalOrStdName("fgets") and apos = 2
or
f.hasGlobalOrStdName("fread") and apos = 3
or
f.hasGlobalOrStdName("read") and apos = 0
or
f.hasGlobalOrStdName("fscanf") and apos = 0
}
/** Holds for a function `f` that has an argument at index `apos` used to write to file */
predicate numberArgumentWrite(Function f, int apos) {
f.hasGlobalOrStdName("fprintf") and apos = 0
or
f.hasGlobalOrStdName("fputs") and apos = 1
or
f.hasGlobalOrStdName("write") and apos = 0
or
f.hasGlobalOrStdName("fwrite") and apos = 3
or
f.hasGlobalOrStdName("fflush") and apos = 0
}
from FunctionCall fc, string msg
where
// search for functions for generating a name, without a guarantee of the absence of a file during the period of work with it.
(
fc.getTarget().hasGlobalOrStdName("tmpnam") or
fc.getTarget().hasGlobalOrStdName("tmpnam_s") or
fc.getTarget().hasGlobalOrStdName("tmpnam_r")
) and
not exists(FunctionCall fctmp |
(
fctmp.getTarget().hasGlobalOrStdName("mktemp") or
fctmp.getTarget().hasGlobalOrStdName("mkstemp") or
fctmp.getTarget().hasGlobalOrStdName("mkstemps") or
fctmp.getTarget().hasGlobalOrStdName("mkdtemp")
) and
(
fc.getBasicBlock().getASuccessor*() = fctmp.getBasicBlock() or
fctmp.getBasicBlock().getASuccessor*() = fc.getBasicBlock()
)
) and
msg =
"Finding the name of a file that does not exist does not mean that it will not be exist at the next operation."
or
// finding places to work with a file without setting permissions, but with predictable names.
(
fc.getTarget().hasGlobalOrStdName("fopen") or
fc.getTarget().hasGlobalOrStdName("open")
) and
fc.getNumberOfArguments() = 2 and
exists(FunctionCall fctmp, int i |
numberArgumentWrite(fctmp.getTarget(), i) and
globalValueNumber(fc) = globalValueNumber(fctmp.getArgument(i))
) and
not exists(FunctionCall fctmp, int i |
numberArgumentRead(fctmp.getTarget(), i) and
globalValueNumber(fc) = globalValueNumber(fctmp.getArgument(i))
) and
exists(FunctionCall fctmp |
(
fctmp.getTarget().hasGlobalOrStdName("strcat") or
fctmp.getTarget().hasGlobalOrStdName("strcpy")
) and
globalValueNumber(fc.getArgument(0)) = globalValueNumber(fctmp.getAnArgument())
or
fctmp.getTarget().hasGlobalOrStdName("getenv") and
globalValueNumber(fc.getArgument(0)) = globalValueNumber(fctmp)
or
(
fctmp.getTarget().hasGlobalOrStdName("asprintf") or
fctmp.getTarget().hasGlobalOrStdName("vasprintf") or
fctmp.getTarget().hasGlobalOrStdName("xasprintf") or
fctmp.getTarget().hasGlobalOrStdName("xvasprintf ")
) and
exists(Variable vrtmp |
vrtmp = fc.getArgument(0).(VariableAccess).getTarget() and
vrtmp = fctmp.getArgument(0).(AddressOfExpr).getAddressable().(Variable) and
not vrtmp instanceof Field
)
) and
not exists(FunctionCall fctmp |
(
fctmp.getTarget().hasGlobalOrStdName("umask") or
fctmp.getTarget().hasGlobalOrStdName("fchmod") or
fctmp.getTarget().hasGlobalOrStdName("chmod")
) and
(
fc.getBasicBlock().getASuccessor*() = fctmp.getBasicBlock() or
fctmp.getBasicBlock().getASuccessor*() = fc.getBasicBlock()
)
) and
msg =
"Creating a file for writing without evaluating its existence and setting permissions can be unsafe."
select fc, msg

View File

@@ -24,7 +24,7 @@ class CallMayNotReturn extends FunctionCall {
not exists(this.(ControlFlowNode).getASuccessor())
or
// call to another function that may not return
exists(CallMayNotReturn exit | this.getTarget() = exit.getEnclosingFunction())
exists(CallMayNotReturn exit | getTarget() = exit.getEnclosingFunction())
}
}

View File

@@ -38,7 +38,13 @@ where
fc.getTargetType().(Class).getABaseClass+().hasGlobalOrStdName("exception") or
fc.getTargetType().(Class).getABaseClass+().hasGlobalOrStdName("CException")
) and
fc instanceof ExprInVoidContext and
not fc.isInMacroExpansion() and
msg = "Object creation of exception type on stack. Did you forget the throw keyword?"
not exists(ThrowExpr texp | fc.getEnclosingStmt() = texp.getEnclosingStmt()) and
not exists(FunctionCall fctmp | fctmp.getAnArgument() = fc) and
not fc instanceof ConstructorDirectInit and
not fc.getEnclosingStmt() instanceof DeclStmt and
not fc instanceof ConstructorDelegationInit and
not fc.getParent() instanceof Initializer and
not fc.getParent() instanceof AllocationExpr and
msg = "This object does not generate an exception."
select fc, msg

View File

@@ -118,7 +118,7 @@ private predicate exprReleases(Expr e, Expr released, string kind) {
}
class Resource extends MemberVariable {
Resource() { not this.isStatic() }
Resource() { not isStatic() }
// Check that an expr is somewhere in this class - does not have to be a constructor
predicate inSameClass(Expr e) {
@@ -129,7 +129,7 @@ class Resource extends MemberVariable {
f instanceof Destructor and f.getDeclaringType() = this.getDeclaringType()
or
exists(Function mid, FunctionCall fc |
this.calledFromDestructor(mid) and
calledFromDestructor(mid) and
fc.getEnclosingFunction() = mid and
fc.getTarget() = f and
f.getDeclaringType() = this.getDeclaringType()
@@ -137,7 +137,7 @@ class Resource extends MemberVariable {
}
predicate inDestructor(Expr e) {
exists(Function f | f = e.getEnclosingFunction() | this.calledFromDestructor(f))
exists(Function f | f = e.getEnclosingFunction() | calledFromDestructor(f))
}
predicate acquisitionWithRequiredKind(Assignment acquireAssign, string kind) {

View File

@@ -1,6 +1,5 @@
name: codeql/cpp-queries
version: 0.0.5
groups: cpp
version: 0.0.2
dependencies:
codeql/cpp-all: "*"
codeql/suite-helpers: "*"

View File

@@ -29,8 +29,7 @@ class CustomAddFunctionCall extends SimpleRangeAnalysisExpr, FunctionCall {
class SelfSub extends SimpleRangeAnalysisExpr, SubExpr {
SelfSub() {
this.getLeftOperand().(VariableAccess).getTarget() =
this.getRightOperand().(VariableAccess).getTarget()
getLeftOperand().(VariableAccess).getTarget() = getRightOperand().(VariableAccess).getTarget()
}
override float getLowerBounds() { result = 0 }

View File

@@ -1,2 +0,0 @@
| test.cpp:16:20:16:25 | call to tmpnam | Finding the name of a file that does not exist does not mean that it will not be exist at the next operation. |
| test.cpp:42:8:42:12 | call to fopen | Creating a file for writing without evaluating its existence and setting permissions can be unsafe. |

View File

@@ -1 +0,0 @@
experimental/Security/CWE/CWE-377/InsecureTemporaryFile.ql

View File

@@ -1,68 +0,0 @@
typedef int FILE;
#define NULL (0)
FILE *fopen(char *filename, const char *mode);
FILE *fdopen(int handle, char *mode);
char * tmpnam(char * name);
int mkstemp(char * name);
char * strcat(char *str1, const char *str2);
int umask(int pmode);
int chmod(char * filename,int pmode);
int fprintf(FILE *fp,const char *fmt, ...);
int fclose(FILE *stream);
int funcTest1()
{
FILE *fp;
char *filename = tmpnam(NULL); // BAD
fp = fopen(filename,"w");
fprintf(fp,"%s\n","data to file");
fclose(fp);
return 0;
}
int funcTest2()
{
FILE *fp;
int fd;
char filename[80];
strcat (filename, "/tmp/name.XXXXXX");
fd = mkstemp(filename);
if ( fd < 0 ) {
return 1;
}
fp = fdopen(fd,"w"); // GOOD
return 0;
}
int funcTest3()
{
FILE *fp;
char filename[80];
strcat(filename, "/tmp/tmp.name");
fp = fopen(filename,"w"); // BAD
fprintf(fp,"%s\n","data to file");
fclose(fp);
return 0;
}
int funcTest4()
{
FILE *fp;
char filename[80];
umask(0022);
strcat(filename, "/tmp/tmp.name");
fp = fopen(filename,"w"); // GOOD
chmod(filename,0666);
fprintf(fp,"%s\n","data to file");
fclose(fp);
return 0;
}
int main(int argc, char *argv[])
{
funcTest1();
funcTest2();
funcTest3();
funcTest4();
return 0;
}

View File

@@ -1,3 +1,3 @@
| test.cpp:35:3:35:33 | call to runtime_error | Object creation of exception type on stack. Did you forget the throw keyword? |
| test.cpp:35:3:35:33 | call to runtime_error | This object does not generate an exception. |
| test.cpp:41:3:41:11 | call to funcTest1 | There is an exception in the function that requires your attention. |
| test.cpp:42:3:42:9 | call to DllMain | DllMain contains an exeption not wrapped in a try..catch block. |

View File

@@ -4,8 +4,8 @@ using SinkFunction = void (*)(int);
void notSink(int notSinkParam);
void callsSink(int sinkParam) { // $ ir-path=31:23 ir-path=32:26 ir-path=34:17
sink(sinkParam); // $ ast=31:28 ast=32:31 ast=34:22 ir-sink
void callsSink(int sinkParam) { // $ ir-path=31:28 ir-path=32:31 ir-path=34:22
sink(sinkParam); // $ ir-sink=31:28 ir-sink=32:31 ir-sink=34:22 ast=31:28 ast=32:31 ast=34:22 MISSING: ast,ir=28
}
struct {
@@ -25,7 +25,7 @@ void assignGlobals() {
};
void testStruct() {
globalStruct.sinkPtr(atoi(getenv("TAINTED"))); // $ MISSING: ir-path,ast
globalStruct.sinkPtr(atoi(getenv("TAINTED"))); // $ ir MISSING: ast
globalStruct.notSinkPtr(atoi(getenv("TAINTED"))); // clean
globalUnion.sinkPtr(atoi(getenv("TAINTED"))); // $ ast ir-path
@@ -48,8 +48,8 @@ class D2 : public D1 {
class D3 : public D2 {
public:
void f(const char* p) override { // $ ir-path=58:10 ir-path=60:17 ir-path=61:28 ir-path=62:29 ir-path=63:33 SPURIOUS: ir-path=73:30
sink(p); // $ ast=58:10 ast=60:17 ast=61:28 ast=62:29 ast=63:33 ir-sink SPURIOUS: ast=73:30
void f(const char* p) override { // $ ir-path=58:10 ir-path=60:17 ir-path=61:28 ir-path=62:29 ir-path=63:33 ir-path=73:30
sink(p); // $ ir-sink=58:10 ir-sink=60:17 ir-sink=61:28 ir-sink=62:29 ir-sink=63:33 ast=58:10 ast=60:17 ast=61:28 ast=62:29 ast=63:33 SPURIOUS: ast=73:30 ir-sink=73:30
}
};

View File

@@ -23,10 +23,11 @@ class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration {
override predicate isSink(Element e) { isSinkArgument(e) }
}
predicate irTaint(Element source, TaintedWithPath::PathNode predNode, string tag) {
exists(TaintedWithPath::PathNode sinkNode |
predicate irTaint(Element source, Element sink, string tag) {
exists(TaintedWithPath::PathNode sinkNode, TaintedWithPath::PathNode predNode |
TaintedWithPath::taintedWithPath(source, _, _, sinkNode) and
predNode = getAPredecessor*(sinkNode) and
sink = getElementFromPathNode(predNode) and
// Make sure the path is actually reachable from this predecessor.
// Otherwise, we could pick `predNode` to be b when `source` is
// `source1` in this dataflow graph:
@@ -34,7 +35,7 @@ predicate irTaint(Element source, TaintedWithPath::PathNode predNode, string tag
// ^
// source2 ---> b --/
source = getElementFromPathNode(getAPredecessor*(predNode)) and
if predNode = sinkNode then tag = "ir-sink" else tag = "ir-path"
if sinkNode = predNode then tag = "ir-sink" else tag = "ir-path"
)
}
@@ -44,25 +45,21 @@ class IRDefaultTaintTrackingTest extends InlineExpectationsTest {
override string getARelevantTag() { result = ["ir-path", "ir-sink"] }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Element source, Element elem, TaintedWithPath::PathNode node, int n |
irTaint(source, node, tag) and
elem = getElementFromPathNode(node) and
n = count(int startline | getAPredecessor(node).hasLocationInfo(_, startline, _, _, _)) and
location = elem.getLocation() and
element = elem.toString()
|
// Zero predecessors means it's a source, and 1 predecessor means it has a unique predecessor.
// In either of these cases we leave out the location.
n = [0, 1] and value = ""
or
// If there is more than one predecessor for this node
// we specify the source location explicitly.
n > 1 and
exists(TaintedWithPath::PathNode pred | pred = getAPredecessor(node) |
exists(Element source, Element tainted, int n |
irTaint(source, tainted, tag) and
n = strictcount(Element otherSource | irTaint(otherSource, tainted, _)) and
(
n = 1 and value = ""
or
// If there is more than one source for this sink
// we specify the source location explicitly.
n > 1 and
value =
getElementFromPathNode(pred).getLocation().getStartLine().toString() + ":" +
getElementFromPathNode(pred).getLocation().getStartColumn()
)
source.getLocation().getStartLine().toString() + ":" +
source.getLocation().getStartColumn()
) and
location = tainted.getLocation() and
element = tainted.toString()
)
}
}

View File

@@ -13,8 +13,8 @@ struct S {
}
};
void calls_sink_with_argv(const char* a) { // $ ir-path=96:26 ir-path=102:26
sink(a); // $ ast=96:26 ast=98:18 ir-sink
void calls_sink_with_argv(const char* a) { // $ ir-path=96:26 ir-path=98:18
sink(a); // $ ast=96:26 ast=98:18 ir-sink=96:26 ir-sink=98:18
}
extern int i;
@@ -27,7 +27,7 @@ public:
class DerivedCallsSink : public BaseWithPureVirtual {
public:
void f(const char* p) override { // $ ir-path
sink(p); // $ ast=108:10 ir-sink SPURIOUS: ast=111:10
sink(p); // $ ir-sink ast=108:10 SPURIOUS: ast=111:10
}
};
@@ -49,8 +49,8 @@ public:
};
class DerivesMultiple : public DerivedCallsSinkDiamond1, public DerivedDoesNotCallSinkDiamond2 {
void f(const char* p) override { // $ ir-path=53:37 ir-path=115:11
DerivedCallsSinkDiamond1::f(p); // $ ir-path
void f(const char* p) override { // $ ir-path
DerivedCallsSinkDiamond1::f(p);
}
};
@@ -58,7 +58,7 @@ template<typename T>
class CRTP {
public:
void f(const char* p) { // $ ir-path
static_cast<T*>(this)->g(p); // $ ir-path
static_cast<T*>(this)->g(p);
}
};
@@ -79,7 +79,7 @@ class Derived2 : public Derived1 {
class Derived3 : public Derived2 {
public:
void f(const char* p) override { // $ ir-path=124:19 ir-path=126:43 ir-path=128:44
sink(p); // $ ast=124:19 ast=126:43 ast=128:44 ir-sink
sink(p); // $ ast,ir-sink=124:19 ast,ir-sink=126:43 ast,ir-sink=128:44
}
};
@@ -97,11 +97,11 @@ int main(int argc, char *argv[]) {
char*** p = &argv; // $ ast,ir-path
sink(*p[0]); // $ ast ir-sink=96:26 ir-sink=98:18
sink(*p[0]); // $ ast,ir-sink
calls_sink_with_argv(*p[i]); // $ ir-path=96:26 ir-path=98:18 MISSING:ast
calls_sink_with_argv(*p[i]); // $ MISSING: ast,ir-path
sink(*(argv + 1)); // $ ast ir-path ir-sink
sink(*(argv + 1)); // $ ast,ir-path ir-sink
BaseWithPureVirtual* b = new DerivedCallsSink;

View File

@@ -190,9 +190,9 @@ void test_pointers1()
sink(ptr1); // $ ast MISSING: ir
sink(ptr2); // $ SPURIOUS: ast
sink(*ptr2); // $ ast MISSING: ir
sink(ptr3); // $ ast,ir
sink(ptr4); // $ SPURIOUS: ast,ir
sink(*ptr4); // $ ast,ir
sink(ptr3); // $ ast MISSING: ir
sink(ptr4); // $ SPURIOUS: ast
sink(*ptr4); // $ ast MISSING: ir
}
void test_pointers2()

View File

@@ -35,17 +35,17 @@ postWithInFlow
| BarrierGuard.cpp:60:3:60:4 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| BarrierGuard.cpp:60:7:60:7 | x [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:8:20:8:29 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:22:8:22:20 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:22:3:22:6 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:22:8:22:20 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:22:9:22:20 | sourceArray1 [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:26:8:26:24 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:26:8:26:24 | sourceStruct1_ptr [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:26:8:26:24 | sourceStruct1_ptr [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:26:27:26:34 | sourceStruct1_ptr [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:28:3:28:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:28:22:28:23 | m1 [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:30:8:30:24 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:30:8:30:24 | sourceStruct1_ptr [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:30:8:30:24 | sourceStruct1_ptr [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:30:27:30:34 | sourceStruct1_ptr [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:34:19:34:41 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:34:19:34:41 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:39:16:39:21 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -77,55 +77,55 @@ postWithInFlow
| dispatch.cpp:29:29:29:34 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:31:8:31:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:31:8:31:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:31:8:31:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:31:16:31:24 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:32:8:32:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:32:8:32:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:32:8:32:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:32:16:32:24 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:33:3:33:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:33:3:33:8 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:33:3:33:8 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:33:11:33:16 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:35:8:35:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:35:8:35:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:35:8:35:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:35:16:35:25 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:36:8:36:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:36:8:36:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:36:8:36:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:36:16:36:25 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:37:3:37:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:37:3:37:8 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:37:3:37:8 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:37:11:37:17 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:39:8:39:13 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:39:8:39:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:39:8:39:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:39:8:39:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:39:15:39:23 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:40:8:40:13 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:40:8:40:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:40:8:40:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:40:8:40:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:40:15:40:23 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:41:3:41:8 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:41:3:41:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:41:3:41:8 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:41:3:41:8 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:41:10:41:15 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:43:8:43:13 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:43:8:43:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:43:8:43:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:43:8:43:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:43:15:43:24 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:44:8:44:13 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:44:8:44:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:44:8:44:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:44:8:44:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:44:15:44:24 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:45:3:45:8 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:45:3:45:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:45:3:45:8 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:45:3:45:8 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:45:10:45:16 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:51:3:51:22 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:55:8:55:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:55:8:55:19 | globalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:55:8:55:19 | globalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:55:22:55:30 | globalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:56:8:56:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:56:8:56:19 | globalMiddle [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:56:8:56:19 | globalMiddle [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:58:8:58:23 | call to readGlobalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:56:22:56:30 | globalMiddle [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:58:8:58:23 | call to readGlobalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:58:28:58:36 | call to readGlobalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:60:3:60:14 | globalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:60:18:60:29 | Call [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:60:18:60:29 | new [post update] | PostUpdateNode should not be the target of local flow. |
@@ -140,34 +140,34 @@ postWithInFlow
| dispatch.cpp:65:10:65:21 | new [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:69:3:69:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:69:3:69:5 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:69:3:69:5 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:69:8:69:13 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:73:3:73:5 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:73:3:73:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:73:3:73:5 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:73:3:73:5 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:77:21:77:34 | call to allocateBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:73:7:73:12 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:77:3:77:19 | call to allocateBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:77:21:77:34 | call to allocateBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:78:3:78:21 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:78:23:78:39 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:78:23:78:39 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:78:23:78:39 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:78:24:78:37 | call to allocateBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:80:8:80:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:81:3:81:3 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:81:3:81:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:81:3:81:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:81:6:81:11 | x [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:85:3:85:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:3:89:10 | call to identity [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:3:89:10 | bottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:3:89:10 | call to identity [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:12:89:17 | (Middle *)... [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:12:89:17 | (Top *)... [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:12:89:17 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:12:89:17 | bottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:12:89:17 | bottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:3:90:10 | call to identity [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:21:89:26 | call to identity [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:3:90:10 | call to identity [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:3:90:10 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:12:90:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:12:90:14 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:12:90:14 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:18:90:23 | call to identity [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:100:3:100:18 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:105:5:105:17 | maybeCallSink [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:113:30:113:38 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -176,11 +176,11 @@ postWithInFlow
| dispatch.cpp:127:31:127:36 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:129:10:129:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:129:10:129:15 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:129:10:129:15 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:129:18:129:25 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:130:10:130:15 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:130:10:130:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:130:10:130:15 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:130:10:130:15 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:130:17:130:24 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:148:3:148:3 | u [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:148:5:148:5 | f [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:168:3:168:4 | u2 [post update] | PostUpdateNode should not be the target of local flow. |
@@ -191,10 +191,10 @@ postWithInFlow
| example.c:24:9:24:9 | x [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:24:20:24:20 | y [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:26:9:26:9 | x [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:26:18:26:24 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:26:13:26:16 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:26:18:26:24 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:26:19:26:24 | coords [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:28:14:28:25 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:28:2:28:12 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:28:14:28:25 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:28:22:28:25 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:28:23:28:25 | pos [post update] | PostUpdateNode should not be the target of local flow. |
@@ -227,23 +227,23 @@ postWithInFlow
| lambdas.cpp:43:3:43:3 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:43:3:43:3 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:43:3:43:3 | c [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:3:45:3 | t [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:3:45:3 | u [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:3:45:3 | w [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:4:45:4 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:4:45:4 | t [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:4:45:4 | t [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:7:45:7 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:7:45:7 | u [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:7:45:7 | u [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:10:45:10 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:10:45:10 | w [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:10:45:10 | w [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:11:5:11:7 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:11:5:11:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:11:5:11:7 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:5:16:10 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:12:16:14 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:12:16:14 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:12:16:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:12:16:14 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:12:16:14 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:20:5:20:7 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:20:5:20:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:20:5:20:7 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
@@ -259,11 +259,11 @@ postWithInFlow
| ref.cpp:31:7:31:9 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:31:7:31:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:31:7:31:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:7:37:19 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:21:37:23 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:21:37:23 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:21:37:23 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:21:37:23 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:21:37:23 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:39:7:39:9 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:39:7:39:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:39:7:39:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
@@ -276,26 +276,26 @@ postWithInFlow
| ref.cpp:48:7:48:9 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:48:7:48:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:48:7:48:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:55:5:55:17 | x1 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:55:19:55:20 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:55:19:55:20 | x1 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:55:19:55:20 | x1 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:58:5:58:13 | x2 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:58:15:58:16 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:58:15:58:16 | x2 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:58:15:58:16 | x2 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:61:5:61:24 | x3 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:61:26:61:27 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:61:26:61:27 | x3 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:61:26:61:27 | x3 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:64:5:64:13 | x4 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:64:15:64:16 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:64:15:64:16 | x4 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:64:15:64:16 | x4 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:75:5:75:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:75:5:75:7 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:75:9:75:11 | val [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:5:79:10 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:12:79:14 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:12:79:14 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:12:79:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:12:79:14 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:12:79:14 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:83:5:83:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:83:5:83:7 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:83:9:83:11 | val [post update] | PostUpdateNode should not be the target of local flow. |
@@ -311,11 +311,11 @@ postWithInFlow
| ref.cpp:96:7:96:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:96:7:96:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:96:11:96:13 | val [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:7:102:19 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:21:102:23 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:21:102:23 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:21:102:23 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:21:102:23 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:21:102:23 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:104:7:104:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:104:7:104:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:104:11:104:13 | val [post update] | PostUpdateNode should not be the target of local flow. |
@@ -328,18 +328,18 @@ postWithInFlow
| ref.cpp:115:7:115:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:115:7:115:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:115:11:115:13 | val [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:122:5:122:17 | x1 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:122:19:122:20 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:122:19:122:20 | x1 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:122:19:122:20 | x1 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:125:5:125:13 | x2 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:125:15:125:16 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:125:15:125:16 | x2 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:125:15:125:16 | x2 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:128:5:128:24 | x3 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:128:26:128:27 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:128:26:128:27 | x3 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:128:26:128:27 | x3 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:131:5:131:13 | x4 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:131:15:131:16 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:131:15:131:16 | x4 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:131:15:131:16 | x4 [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:6:7:6:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:8:3:8:4 | t2 [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:12:5:12:6 | t2 [post update] | PostUpdateNode should not be the target of local flow. |
@@ -520,40 +520,40 @@ postWithInFlow
| test.cpp:374:5:374:20 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:374:5:374:20 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:383:7:383:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:384:10:384:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:384:3:384:8 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:384:10:384:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:384:10:384:13 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:384:11:384:13 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:389:7:389:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:390:8:390:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:391:10:391:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:391:3:391:8 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:391:10:391:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:391:10:391:13 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:391:11:391:13 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:400:10:400:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:400:3:400:8 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:400:10:400:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:400:10:400:13 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:400:11:400:13 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:406:8:406:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:407:10:407:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:407:3:407:8 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:407:10:407:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:407:10:407:13 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:407:11:407:13 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:417:3:417:14 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:417:16:417:20 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:417:16:417:20 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:417:16:417:20 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:423:20:423:25 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:423:3:423:18 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:423:20:423:25 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:423:21:423:25 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:429:3:429:18 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:429:20:429:24 | array to pointer conversion [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:429:20:429:24 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:429:20:429:24 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:436:18:436:23 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:436:3:436:16 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:436:18:436:23 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:436:19:436:23 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:442:3:442:16 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:442:18:442:22 | array to pointer conversion [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:442:18:442:22 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:442:18:442:22 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:453:7:453:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:456:7:456:9 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:458:7:458:9 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
@@ -561,12 +561,12 @@ postWithInFlow
| test.cpp:465:4:465:4 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:465:4:465:4 | p [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:469:7:469:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:470:21:470:22 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:470:3:470:19 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:470:21:470:22 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:470:22:470:22 | x [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:3:481:19 | content [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:21:481:21 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:21:481:30 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:21:481:30 | content [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:24:481:30 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:24:481:30 | content [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:482:8:482:16 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |

View File

@@ -1,4 +1,3 @@
| example.c:15:37:15:37 | b | example.c:15:37:15:37 | b |
| example.c:15:37:15:37 | b | example.c:19:6:19:6 | b |
| example.c:15:44:15:46 | pos | example.c:24:24:24:26 | pos |
| example.c:15:44:15:46 | pos | example.c:28:23:28:25 | pos |
@@ -71,10 +70,8 @@
| test.cpp:391:11:391:13 | tmp | test.cpp:391:10:391:13 | & ... |
| test.cpp:391:17:391:23 | source1 | test.cpp:391:10:391:13 | ref arg & ... |
| test.cpp:391:17:391:23 | source1 | test.cpp:391:16:391:23 | & ... |
| test.cpp:480:67:480:67 | s | test.cpp:480:67:480:67 | s |
| test.cpp:480:67:480:67 | s | test.cpp:481:21:481:21 | s |
| test.cpp:480:67:480:67 | s | test.cpp:482:20:482:20 | s |
| test.cpp:481:21:481:21 | s [post update] | test.cpp:480:67:480:67 | s |
| test.cpp:481:21:481:21 | s [post update] | test.cpp:482:20:482:20 | s |
| test.cpp:481:24:481:30 | ref arg content | test.cpp:482:23:482:29 | content |
| test.cpp:482:23:482:29 | content | test.cpp:483:9:483:17 | p_content |

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