mirror of
https://github.com/github/codeql.git
synced 2025-12-22 19:56:32 +01:00
Merge remote-tracking branch 'upstream/main' into incomplete-url-string-sanitization
Conflicts: config/identical-files.json javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.ql javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qll ruby/ql/src/queries/security/cwe-020/IncompleteUrlSubstringSanitization.qll
This commit is contained in:
50
.github/workflows/check-qldoc.yml
vendored
Normal file
50
.github/workflows/check-qldoc.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
name: "Check QLdoc coverage"
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "*/ql/lib/**"
|
||||||
|
- .github/workflows/check-qldoc.yml
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- "rc/*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
qldoc:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Install CodeQL
|
||||||
|
run: |
|
||||||
|
gh extension install github/gh-codeql
|
||||||
|
gh codeql set-channel nightly
|
||||||
|
gh codeql version
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- name: Check QLdoc coverage
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
EXIT_CODE=0
|
||||||
|
changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -o '^[a-z]*/ql/lib' || true; } | sort -u)"
|
||||||
|
for pack_dir in ${changed_lib_packs}; do
|
||||||
|
lang="${pack_dir%/ql/lib}"
|
||||||
|
gh codeql generate library-doc-coverage --output="${RUNNER_TEMP}/${lang}-current.txt" --dir="${pack_dir}"
|
||||||
|
done
|
||||||
|
git checkout HEAD^
|
||||||
|
for pack_dir in ${changed_lib_packs}; do
|
||||||
|
lang="${pack_dir%/ql/lib}"
|
||||||
|
gh codeql generate library-doc-coverage --output="${RUNNER_TEMP}/${lang}-baseline.txt" --dir="${pack_dir}"
|
||||||
|
awk -F, '{gsub(/"/,""); if ($4==0 && $6=="public") print "\""$3"\"" }' "${RUNNER_TEMP}/${lang}-current.txt" | sort -u > "${RUNNER_TEMP}/current-undocumented.txt"
|
||||||
|
awk -F, '{gsub(/"/,""); if ($4==0 && $6=="public") print "\""$3"\"" }' "${RUNNER_TEMP}/${lang}-baseline.txt" | sort -u > "${RUNNER_TEMP}/baseline-undocumented.txt"
|
||||||
|
UNDOCUMENTED="$(grep -f <(comm -13 "${RUNNER_TEMP}/baseline-undocumented.txt" "${RUNNER_TEMP}/current-undocumented.txt") "${RUNNER_TEMP}/${lang}-current.txt" || true)"
|
||||||
|
if [ -n "$UNDOCUMENTED" ]; then
|
||||||
|
echo "$UNDOCUMENTED" | awk -F, '{gsub(/"/,""); print "::warning file='"${pack_dir}"'/"$1",line="$2"::Missing QLdoc for "$5, $3 }'
|
||||||
|
EXIT_CODE=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
exit "${EXIT_CODE}"
|
||||||
58
config/blame-deprecations.mjs
Normal file
58
config/blame-deprecations.mjs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import fs from "fs";
|
||||||
|
import path from "path";
|
||||||
|
import cp from "child_process";
|
||||||
|
function* walk(dir) {
|
||||||
|
for (const file of fs.readdirSync(dir)) {
|
||||||
|
const filePath = path.join(dir, file);
|
||||||
|
if (fs.statSync(filePath).isDirectory()) {
|
||||||
|
yield* walk(filePath);
|
||||||
|
} else {
|
||||||
|
yield filePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function* deprecatedFiles(dir) {
|
||||||
|
for (const file of walk(dir)) {
|
||||||
|
if (file.endsWith(".ql") || file.endsWith(".qll")) {
|
||||||
|
const contents = fs.readFileSync(file, "utf8");
|
||||||
|
if (/\sdeprecated\s/.test(contents)) {
|
||||||
|
yield file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const blameRegExp =
|
||||||
|
/^(\^?\w+)\s.+\s+(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} (?:\+|-)\d{4})\s+(\d+)\).*$/;
|
||||||
|
|
||||||
|
function* deprecationMessages(dir) {
|
||||||
|
for (const file of deprecatedFiles(dir)) {
|
||||||
|
const blame = cp.execFileSync("git", ["blame", "--", file]);
|
||||||
|
const lines = blame.toString().split("\n");
|
||||||
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
const line = lines[i];
|
||||||
|
if (line.includes(" deprecated ")) {
|
||||||
|
try {
|
||||||
|
const [_, sha, time, lineNumber] = line.match(blameRegExp);
|
||||||
|
const date = new Date(time);
|
||||||
|
// check if it's within the last 14 months (a year, plus 2 months for safety, in case a PR was delayed)
|
||||||
|
if (date.getTime() >= Date.now() - 14 * 31 * 24 * 60 * 60 * 1000) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const message = `${file}:${lineNumber} was last updated on ${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
|
||||||
|
yield [message, date];
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
console.log("----");
|
||||||
|
console.log(line);
|
||||||
|
console.log("----");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[...deprecationMessages(".")]
|
||||||
|
.sort((a, b) => a[1].getTime() - b[1].getTime())
|
||||||
|
.forEach((msg) => console.log(msg[0]));
|
||||||
@@ -73,6 +73,14 @@
|
|||||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
|
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
|
||||||
],
|
],
|
||||||
|
"Model as Data Generation Java/C# - Utils": [
|
||||||
|
"java/ql/src/utils/model-generator/ModelGeneratorUtils.qll",
|
||||||
|
"csharp/ql/src/utils/model-generator/ModelGeneratorUtils.qll"
|
||||||
|
],
|
||||||
|
"Model as Data Generation Java/C# - SummaryModels": [
|
||||||
|
"java/ql/src/utils/model-generator/CaptureSummaryModels.qll",
|
||||||
|
"csharp/ql/src/utils/model-generator/CaptureSummaryModels.qll"
|
||||||
|
],
|
||||||
"Sign Java/C#": [
|
"Sign Java/C#": [
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll",
|
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll",
|
||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll"
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll"
|
||||||
@@ -426,7 +434,6 @@
|
|||||||
"python/ql/src/Lexical/CommentedOutCodeMetricOverview.inc.qhelp"
|
"python/ql/src/Lexical/CommentedOutCodeMetricOverview.inc.qhelp"
|
||||||
],
|
],
|
||||||
"FLinesOfDuplicatedCodeCommon.inc.qhelp": [
|
"FLinesOfDuplicatedCodeCommon.inc.qhelp": [
|
||||||
"cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.inc.qhelp",
|
|
||||||
"java/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.inc.qhelp",
|
"java/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.inc.qhelp",
|
||||||
"javascript/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.inc.qhelp",
|
"javascript/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.inc.qhelp",
|
||||||
"python/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.inc.qhelp"
|
"python/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.inc.qhelp"
|
||||||
@@ -512,5 +519,13 @@
|
|||||||
"IncompleteUrlSubstringSanitization": [
|
"IncompleteUrlSubstringSanitization": [
|
||||||
"javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qll",
|
"javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qll",
|
||||||
"ruby/ql/src/queries/security/cwe-020/IncompleteUrlSubstringSanitization.qll"
|
"ruby/ql/src/queries/security/cwe-020/IncompleteUrlSubstringSanitization.qll"
|
||||||
|
],
|
||||||
|
"Hostname Regexp queries": [
|
||||||
|
"javascript/ql/src/Security/CWE-020/HostnameRegexpShared.qll",
|
||||||
|
"ruby/ql/src/queries/security/cwe-020/HostnameRegexpShared.qll"
|
||||||
|
],
|
||||||
|
"ApiGraphModels": [
|
||||||
|
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll",
|
||||||
|
"ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
2096
cpp/downgrades/e9a518baf14f4322ac243578a8e1391386ff030f/old.dbscheme
Normal file
2096
cpp/downgrades/e9a518baf14f4322ac243578a8e1391386ff030f/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
|||||||
|
description: Remove uniqueness constraint from the uuid property
|
||||||
|
compatibility: full
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
## 0.0.11
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* Many queries now support structured bindings, as structured bindings are now handled in the IR translation.
|
||||||
|
|
||||||
## 0.0.10
|
## 0.0.10
|
||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
@@ -6,6 +12,7 @@
|
|||||||
|
|
||||||
## 0.0.9
|
## 0.0.9
|
||||||
|
|
||||||
|
|
||||||
## 0.0.8
|
## 0.0.8
|
||||||
|
|
||||||
### Deprecated APIs
|
### Deprecated APIs
|
||||||
|
|||||||
@@ -54,11 +54,13 @@ class Options extends string {
|
|||||||
*
|
*
|
||||||
* By default, this holds for `exit`, `_exit`, `abort`, `__assert_fail`,
|
* By default, this holds for `exit`, `_exit`, `abort`, `__assert_fail`,
|
||||||
* `longjmp`, `__builtin_unreachable` and any function with a
|
* `longjmp`, `__builtin_unreachable` and any function with a
|
||||||
* `noreturn` attribute.
|
* `noreturn` attribute or specifier.
|
||||||
*/
|
*/
|
||||||
predicate exits(Function f) {
|
predicate exits(Function f) {
|
||||||
f.getAnAttribute().hasName("noreturn")
|
f.getAnAttribute().hasName("noreturn")
|
||||||
or
|
or
|
||||||
|
f.getASpecifier().hasName("noreturn")
|
||||||
|
or
|
||||||
f.hasGlobalOrStdName([
|
f.hasGlobalOrStdName([
|
||||||
"exit", "_exit", "abort", "__assert_fail", "longjmp", "__builtin_unreachable"
|
"exit", "_exit", "abort", "__assert_fail", "longjmp", "__builtin_unreachable"
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class CustomOptions extends Options {
|
|||||||
*
|
*
|
||||||
* By default, this holds for `exit`, `_exit`, `abort`, `__assert_fail`,
|
* By default, this holds for `exit`, `_exit`, `abort`, `__assert_fail`,
|
||||||
* `longjmp`, `error`, `__builtin_unreachable` and any function with a
|
* `longjmp`, `error`, `__builtin_unreachable` and any function with a
|
||||||
* `noreturn` attribute.
|
* `noreturn` attribute or specifier.
|
||||||
*/
|
*/
|
||||||
override predicate exits(Function f) { Options.super.exits(f) }
|
override predicate exits(Function f) { Options.super.exits(f) }
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* All deprecated predicates/classes/modules that have been deprecated for over a year have been deleted.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
category: deprecated
|
||||||
|
---
|
||||||
|
* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide.
|
||||||
|
The old name still exists as a deprecated alias.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* `hasImplicitCopyConstructor` and `hasImplicitCopyAssignmentOperator` now correctly handle implicitly-deleted operators in templates.
|
||||||
4
cpp/ql/lib/change-notes/2022-03-14-c11-noreturn.md
Normal file
4
cpp/ql/lib/change-notes/2022-03-14-c11-noreturn.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* `DefaultOptions::exits` now holds for C11 functions with the `_Noreturn` or `noreturn` specifier.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: feature
|
||||||
|
---
|
||||||
|
* The data flow and taint tracking libraries have been extended with versions of `isBarrierIn`, `isBarrierOut`, and `isBarrierGuard`, respectively `isSanitizerIn`, `isSanitizerOut`, and `isSanitizerGuard`, that support flow states.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: breaking
|
||||||
|
---
|
||||||
|
* The flow state variants of `isBarrier` and `isAdditionalFlowStep` are no longer exposed in the taint tracking library. The `isSanitizer` and `isAdditionalTaintStep` predicates should be used instead.
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
## 0.0.11
|
||||||
category: minorAnalysis
|
|
||||||
---
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
* Many queries now support structured bindings, as structured bindings are now handled in the IR translation.
|
* Many queries now support structured bindings, as structured bindings are now handled in the IR translation.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.0.10
|
lastReleaseVersion: 0.0.11
|
||||||
|
|||||||
@@ -69,6 +69,4 @@ import semmle.code.cpp.Comments
|
|||||||
import semmle.code.cpp.Preprocessor
|
import semmle.code.cpp.Preprocessor
|
||||||
import semmle.code.cpp.Iteration
|
import semmle.code.cpp.Iteration
|
||||||
import semmle.code.cpp.NameQualifiers
|
import semmle.code.cpp.NameQualifiers
|
||||||
import semmle.code.cpp.ObjectiveC
|
|
||||||
import semmle.code.cpp.exprs.ObjectiveC
|
|
||||||
import DefaultOptions
|
import DefaultOptions
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-all
|
name: codeql/cpp-all
|
||||||
version: 0.0.11-dev
|
version: 0.0.12-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dbscheme: semmlecode.cpp.dbscheme
|
dbscheme: semmlecode.cpp.dbscheme
|
||||||
extractor: cpp
|
extractor: cpp
|
||||||
|
|||||||
@@ -111,24 +111,6 @@ class Class extends UserType {
|
|||||||
result = this.getCanonicalMember(index).(TemplateVariable).getAnInstantiation()
|
result = this.getCanonicalMember(index).(TemplateVariable).getAnInstantiation()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `getCanonicalMember(int)` or `getAMember(int)` instead.
|
|
||||||
* Gets the `index`th member of this class.
|
|
||||||
*/
|
|
||||||
deprecated Declaration getMember(int index) {
|
|
||||||
member(underlyingElement(this), index, unresolveElement(result))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: As this includes a somewhat arbitrary number of
|
|
||||||
* template instantiations, it is unlikely to do what
|
|
||||||
* you need.
|
|
||||||
* Gets the number of members that this class has. This includes both
|
|
||||||
* templates that are in this class, and instantiations of those
|
|
||||||
* templates.
|
|
||||||
*/
|
|
||||||
deprecated int getNumMember() { result = count(this.getAMember()) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a private member declared in this class, struct or union.
|
* Gets a private member declared in this class, struct or union.
|
||||||
* For template members, this may be either the template or an
|
* For template members, this may be either the template or an
|
||||||
@@ -208,23 +190,6 @@ class Class extends UserType {
|
|||||||
*/
|
*/
|
||||||
deprecated predicate hasCopyConstructor() { this.getAMemberFunction() instanceof CopyConstructor }
|
deprecated predicate hasCopyConstructor() { this.getAMemberFunction() instanceof CopyConstructor }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this class has a copy assignment operator that is either
|
|
||||||
* explicitly declared (though possibly `= delete`) or is auto-generated,
|
|
||||||
* non-trivial and called from somewhere.
|
|
||||||
*
|
|
||||||
* DEPRECATED: There is more than one reasonable definition of what it means
|
|
||||||
* to have a copy assignment operator, and we do not want to promote one
|
|
||||||
* particular definition by naming it with this predicate. Having a copy
|
|
||||||
* assignment operator could mean that such a member is declared or defined
|
|
||||||
* in the source or that it is callable by a particular caller. For C++11,
|
|
||||||
* there's also a question of whether to include members that are defaulted
|
|
||||||
* or deleted.
|
|
||||||
*/
|
|
||||||
deprecated predicate hasCopyAssignmentOperator() {
|
|
||||||
this.getAMemberFunction() instanceof CopyAssignmentOperator
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like accessOfBaseMember but returns multiple results if there are multiple
|
* Like accessOfBaseMember but returns multiple results if there are multiple
|
||||||
* paths to `base` through the inheritance graph.
|
* paths to `base` through the inheritance graph.
|
||||||
@@ -286,6 +251,16 @@ class Class extends UserType {
|
|||||||
not this.implicitCopyConstructorDeleted() and
|
not this.implicitCopyConstructorDeleted() and
|
||||||
forall(CopyConstructor cc | cc = this.getAMemberFunction() |
|
forall(CopyConstructor cc | cc = this.getAMemberFunction() |
|
||||||
cc.isCompilerGenerated() and not cc.isDeleted()
|
cc.isCompilerGenerated() and not cc.isDeleted()
|
||||||
|
) and
|
||||||
|
(
|
||||||
|
not this instanceof ClassTemplateInstantiation
|
||||||
|
or
|
||||||
|
this.(ClassTemplateInstantiation).getTemplate().hasImplicitCopyConstructor()
|
||||||
|
) and
|
||||||
|
(
|
||||||
|
not this instanceof PartialClassTemplateSpecialization
|
||||||
|
or
|
||||||
|
this.(PartialClassTemplateSpecialization).getPrimaryTemplate().hasImplicitCopyConstructor()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,6 +276,18 @@ class Class extends UserType {
|
|||||||
not this.implicitCopyAssignmentOperatorDeleted() and
|
not this.implicitCopyAssignmentOperatorDeleted() and
|
||||||
forall(CopyAssignmentOperator ca | ca = this.getAMemberFunction() |
|
forall(CopyAssignmentOperator ca | ca = this.getAMemberFunction() |
|
||||||
ca.isCompilerGenerated() and not ca.isDeleted()
|
ca.isCompilerGenerated() and not ca.isDeleted()
|
||||||
|
) and
|
||||||
|
(
|
||||||
|
not this instanceof ClassTemplateInstantiation
|
||||||
|
or
|
||||||
|
this.(ClassTemplateInstantiation).getTemplate().hasImplicitCopyAssignmentOperator()
|
||||||
|
) and
|
||||||
|
(
|
||||||
|
not this instanceof PartialClassTemplateSpecialization
|
||||||
|
or
|
||||||
|
this.(PartialClassTemplateSpecialization)
|
||||||
|
.getPrimaryTemplate()
|
||||||
|
.hasImplicitCopyAssignmentOperator()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1070,31 +1057,6 @@ class PartialClassTemplateSpecialization extends ClassTemplateSpecialization {
|
|||||||
override string getAPrimaryQlClass() { result = "PartialClassTemplateSpecialization" }
|
override string getAPrimaryQlClass() { result = "PartialClassTemplateSpecialization" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* An "interface" is a class that only contains pure virtual functions (and contains
|
|
||||||
* at least one such function). For example:
|
|
||||||
* ```
|
|
||||||
* class MyInterfaceClass {
|
|
||||||
* public:
|
|
||||||
* virtual void myMethod1() = 0;
|
|
||||||
* virtual void myMethod2() = 0;
|
|
||||||
* };
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* DEPRECATED: This class is considered to be too specific for general usage.
|
|
||||||
*/
|
|
||||||
deprecated class Interface extends Class {
|
|
||||||
Interface() {
|
|
||||||
forex(Declaration m |
|
|
||||||
m.getDeclaringType() = this.getABaseClass*() and not compgenerated(unresolveElement(m))
|
|
||||||
|
|
|
||||||
m instanceof PureVirtualFunction
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "Interface" }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class/struct derivation that is virtual. For example the derivation in
|
* A class/struct derivation that is virtual. For example the derivation in
|
||||||
* the following code is a `VirtualClassDerivation`:
|
* the following code is a `VirtualClassDerivation`:
|
||||||
|
|||||||
@@ -55,9 +55,6 @@ class ElementBase extends @element {
|
|||||||
cached
|
cached
|
||||||
string toString() { none() }
|
string toString() { none() }
|
||||||
|
|
||||||
/** DEPRECATED: use `getAPrimaryQlClass` instead. */
|
|
||||||
deprecated string getCanonicalQLClass() { result = this.getAPrimaryQlClass() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs.
|
* Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs.
|
||||||
*/
|
*/
|
||||||
@@ -91,13 +88,6 @@ class Element extends ElementBase {
|
|||||||
*/
|
*/
|
||||||
predicate fromSource() { this.getFile().fromSource() }
|
predicate fromSource() { this.getFile().fromSource() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this element may be from a library.
|
|
||||||
*
|
|
||||||
* DEPRECATED: always true.
|
|
||||||
*/
|
|
||||||
deprecated predicate fromLibrary() { this.getFile().fromLibrary() }
|
|
||||||
|
|
||||||
/** Gets the primary location of this element. */
|
/** Gets the primary location of this element. */
|
||||||
Location getLocation() { none() }
|
Location getLocation() { none() }
|
||||||
|
|
||||||
|
|||||||
@@ -196,31 +196,11 @@ class Folder extends Container, @folder {
|
|||||||
*/
|
*/
|
||||||
deprecated string getName() { folders(underlyingElement(this), result) }
|
deprecated string getName() { folders(underlyingElement(this), result) }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: use `getAbsolutePath` instead.
|
|
||||||
* Holds if this element is named `name`.
|
|
||||||
*/
|
|
||||||
deprecated predicate hasName(string name) { name = this.getName() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: use `getAbsolutePath` instead.
|
|
||||||
* Gets the full name of this folder.
|
|
||||||
*/
|
|
||||||
deprecated string getFullName() { result = this.getName() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DEPRECATED: use `getBaseName` instead.
|
* DEPRECATED: use `getBaseName` instead.
|
||||||
* Gets the last part of the folder name.
|
* Gets the last part of the folder name.
|
||||||
*/
|
*/
|
||||||
deprecated string getShortName() { result = this.getBaseName() }
|
deprecated string getShortName() { result = this.getBaseName() }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: use `getParentContainer` instead.
|
|
||||||
* Gets the parent folder.
|
|
||||||
*/
|
|
||||||
deprecated Folder getParent() {
|
|
||||||
containerparent(unresolveElement(result), underlyingElement(this))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -308,13 +288,6 @@ class File extends Container, @file {
|
|||||||
*/
|
*/
|
||||||
override predicate fromSource() { numlines(underlyingElement(this), _, _, _) }
|
override predicate fromSource() { numlines(underlyingElement(this), _, _, _) }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this file may be from a library.
|
|
||||||
*
|
|
||||||
* DEPRECATED: For historical reasons this is true for any file.
|
|
||||||
*/
|
|
||||||
deprecated override predicate fromLibrary() { any() }
|
|
||||||
|
|
||||||
/** Gets the metric file. */
|
/** Gets the metric file. */
|
||||||
MetricFile getMetrics() { result = this }
|
MetricFile getMetrics() { result = this }
|
||||||
|
|
||||||
@@ -428,25 +401,3 @@ class CppFile extends File {
|
|||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "CppFile" }
|
override string getAPrimaryQlClass() { result = "CppFile" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C source file, as determined by file extension.
|
|
||||||
*
|
|
||||||
* For the related notion of whether a file is compiled as Objective C
|
|
||||||
* code, use `File.compiledAsObjC`.
|
|
||||||
*/
|
|
||||||
deprecated class ObjCFile extends File {
|
|
||||||
ObjCFile() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C++ source file, as determined by file extension.
|
|
||||||
*
|
|
||||||
* For the related notion of whether a file is compiled as Objective C++
|
|
||||||
* code, use `File.compiledAsObjCpp`.
|
|
||||||
*/
|
|
||||||
deprecated class ObjCppFile extends File {
|
|
||||||
ObjCppFile() { none() }
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -105,25 +105,6 @@ class Location extends @location {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Location` instead.
|
|
||||||
* A location of an element. Not used for expressions or statements, which
|
|
||||||
* instead use LocationExpr and LocationStmt respectively.
|
|
||||||
*/
|
|
||||||
deprecated library class LocationDefault extends Location, @location_default { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Location` instead.
|
|
||||||
* A location of a statement.
|
|
||||||
*/
|
|
||||||
deprecated library class LocationStmt extends Location, @location_stmt { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `Location` instead.
|
|
||||||
* A location of an expression.
|
|
||||||
*/
|
|
||||||
deprecated library class LocationExpr extends Location, @location_expr { }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the length of the longest line in file `f`.
|
* Gets the length of the longest line in file `f`.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -30,16 +30,6 @@ class Macro extends PreprocessorDirective, @ppd_define {
|
|||||||
else result = "#define " + this.getHead() + " " + this.getBody()
|
else result = "#define " + this.getHead() + " " + this.getBody()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the body of the macro starts with an unmatched closing
|
|
||||||
* parenthesis. For example:
|
|
||||||
*
|
|
||||||
* #define RPAREN() )
|
|
||||||
*
|
|
||||||
* DEPRECATED: This predicate has a misleading name.
|
|
||||||
*/
|
|
||||||
deprecated predicate isFunctionLike() { this.getBody().regexpMatch("[^(]*\\).*") }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the name of the macro. For example, `MAX` in
|
* Gets the name of the macro. For example, `MAX` in
|
||||||
* `#define MAX(x,y) (((x)>(y))?(x):(y))`.
|
* `#define MAX(x,y) (((x)>(y))?(x):(y))`.
|
||||||
@@ -261,46 +251,6 @@ class MacroInvocation extends MacroAccess {
|
|||||||
string getExpandedArgument(int i) { macro_argument_expanded(underlyingElement(this), i, result) }
|
string getExpandedArgument(int i) { macro_argument_expanded(underlyingElement(this), i, result) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A top-level expression generated by a macro invocation.
|
|
||||||
*
|
|
||||||
* DEPRECATED: Use `MacroInvocation.getExpr()` directly to get an
|
|
||||||
* expression generated at the top-level of a macro invocation. Use
|
|
||||||
* `MacroInvocation.getAnAffectedElement()` to get any element generated
|
|
||||||
* by a macro invocation.
|
|
||||||
*/
|
|
||||||
deprecated class MacroInvocationExpr extends Expr {
|
|
||||||
MacroInvocationExpr() { exists(MacroInvocation i | this = i.getExpr()) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the macro invocation of which this is the top-level expression.
|
|
||||||
*/
|
|
||||||
MacroInvocation getInvocation() { result.getExpr() = this }
|
|
||||||
|
|
||||||
/** Gets the name of the invoked macro. */
|
|
||||||
string getMacroName() { result = this.getInvocation().getMacroName() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A top-level statement generated by a macro invocation.
|
|
||||||
*
|
|
||||||
* DEPRECATED: Use `MacroInvocation.getStmt()` directly to get a
|
|
||||||
* statement generated at the top-level of a macro invocation. Use
|
|
||||||
* `MacroInvocation.getAnAffectedElement()` to get any element generated
|
|
||||||
* by a macro invocation.
|
|
||||||
*/
|
|
||||||
deprecated class MacroInvocationStmt extends Stmt {
|
|
||||||
MacroInvocationStmt() { exists(MacroInvocation i | this = i.getStmt()) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the macro invocation of which this is the top-level statement.
|
|
||||||
*/
|
|
||||||
MacroInvocation getInvocation() { result.getStmt() = this }
|
|
||||||
|
|
||||||
/** Gets the name of the invoked macro. */
|
|
||||||
string getMacroName() { result = this.getInvocation().getMacroName() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if `l` is the location of a macro. */
|
/** Holds if `l` is the location of a macro. */
|
||||||
predicate macroLocation(Location l) { macrolocationbind(_, l) }
|
predicate macroLocation(Location l) { macrolocationbind(_, l) }
|
||||||
|
|
||||||
|
|||||||
@@ -233,40 +233,6 @@ class ImplicitConversionFunction extends MemberFunction {
|
|||||||
Type getDestType() { none() } // overridden in subclasses
|
Type getDestType() { none() } // overridden in subclasses
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: as of C++11 this class does not correspond perfectly with the
|
|
||||||
* language definition of a converting constructor.
|
|
||||||
*
|
|
||||||
* A C++ constructor that also defines an implicit conversion. For example the
|
|
||||||
* function `MyClass` in the following code is a `ConversionConstructor`:
|
|
||||||
* ```
|
|
||||||
* class MyClass {
|
|
||||||
* public:
|
|
||||||
* MyClass(const MyOtherClass &from) {
|
|
||||||
* ...
|
|
||||||
* }
|
|
||||||
* };
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
deprecated class ConversionConstructor extends Constructor, ImplicitConversionFunction {
|
|
||||||
ConversionConstructor() {
|
|
||||||
strictcount(Parameter p | p = this.getAParameter() and not p.hasInitializer()) = 1 and
|
|
||||||
not this.hasSpecifier("explicit")
|
|
||||||
}
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() {
|
|
||||||
not this instanceof CopyConstructor and
|
|
||||||
not this instanceof MoveConstructor and
|
|
||||||
result = "ConversionConstructor"
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the type this `ConversionConstructor` takes as input. */
|
|
||||||
override Type getSourceType() { result = this.getParameter(0).getType() }
|
|
||||||
|
|
||||||
/** Gets the type this `ConversionConstructor` is a constructor of. */
|
|
||||||
override Type getDestType() { result = this.getDeclaringType() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate hasCopySignature(MemberFunction f) {
|
private predicate hasCopySignature(MemberFunction f) {
|
||||||
f.getParameter(0).getUnspecifiedType().(LValueReferenceType).getBaseType() = f.getDeclaringType()
|
f.getParameter(0).getUnspecifiedType().(LValueReferenceType).getBaseType() = f.getDeclaringType()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,13 +86,6 @@ class Namespace extends NameQualifyingElement, @namespace {
|
|||||||
/** Holds if this namespace may be from source. */
|
/** Holds if this namespace may be from source. */
|
||||||
override predicate fromSource() { this.getADeclaration().fromSource() }
|
override predicate fromSource() { this.getADeclaration().fromSource() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this namespace is in a library.
|
|
||||||
*
|
|
||||||
* DEPRECATED: never holds.
|
|
||||||
*/
|
|
||||||
deprecated override predicate fromLibrary() { not this.fromSource() }
|
|
||||||
|
|
||||||
/** Gets the metric namespace. */
|
/** Gets the metric namespace. */
|
||||||
MetricNamespace getMetrics() { result = this }
|
MetricNamespace getMetrics() { result = this }
|
||||||
|
|
||||||
@@ -233,11 +226,6 @@ class GlobalNamespace extends Namespace {
|
|||||||
|
|
||||||
override Namespace getParentNamespace() { none() }
|
override Namespace getParentNamespace() { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: use `getName()`.
|
|
||||||
*/
|
|
||||||
deprecated string getFullName() { result = this.getName() }
|
|
||||||
|
|
||||||
override string getFriendlyName() { result = "(global namespace)" }
|
override string getFriendlyName() { result = "(global namespace)" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,196 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import semmle.code.cpp.Class
|
|
||||||
private import semmle.code.cpp.internal.ResolveClass
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C class.
|
|
||||||
*/
|
|
||||||
deprecated class ObjectiveClass extends Class {
|
|
||||||
ObjectiveClass() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C protocol.
|
|
||||||
*/
|
|
||||||
deprecated class Protocol extends Class {
|
|
||||||
Protocol() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the type implements the protocol, either because the type
|
|
||||||
* itself does, or because it is a type conforming to the protocol.
|
|
||||||
*/
|
|
||||||
predicate isImplementedBy(Type t) { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* A type which conforms to a protocol. Use `getAProtocol` to get a
|
|
||||||
* protocol that this type conforms to.
|
|
||||||
*/
|
|
||||||
deprecated class TypeConformingToProtocol extends DerivedType {
|
|
||||||
TypeConformingToProtocol() { none() }
|
|
||||||
|
|
||||||
/** Gets a protocol that this type conforms to. */
|
|
||||||
Protocol getAProtocol() { none() }
|
|
||||||
|
|
||||||
/** Gets the size of this type. */
|
|
||||||
override int getSize() { none() }
|
|
||||||
|
|
||||||
override int getAlignment() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C `@autoreleasepool` statement, for example
|
|
||||||
* `@autoreleasepool { int x; int y; }`.
|
|
||||||
*/
|
|
||||||
deprecated class AutoReleasePoolStmt extends Stmt {
|
|
||||||
AutoReleasePoolStmt() { none() }
|
|
||||||
|
|
||||||
override string toString() { none() }
|
|
||||||
|
|
||||||
/** Gets the body statement of this `@autoreleasepool` statement. */
|
|
||||||
Stmt getStmt() { none() }
|
|
||||||
|
|
||||||
override predicate mayBeImpure() { none() }
|
|
||||||
|
|
||||||
override predicate mayBeGloballyImpure() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C `@synchronized statement`, for example
|
|
||||||
* `@synchronized (x) { [x complicationOperation]; }`.
|
|
||||||
*/
|
|
||||||
deprecated class SynchronizedStmt extends Stmt {
|
|
||||||
SynchronizedStmt() { none() }
|
|
||||||
|
|
||||||
override string toString() { none() }
|
|
||||||
|
|
||||||
/** Gets the expression which gives the object to be locked. */
|
|
||||||
Expr getLockedObject() { none() }
|
|
||||||
|
|
||||||
/** Gets the body statement of this `@synchronized` statement. */
|
|
||||||
Stmt getStmt() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C for-in statement.
|
|
||||||
*/
|
|
||||||
deprecated class ForInStmt extends Loop {
|
|
||||||
ForInStmt() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the condition expression of the `while` statement that the
|
|
||||||
* `for...in` statement desugars into.
|
|
||||||
*/
|
|
||||||
override Expr getCondition() { none() }
|
|
||||||
|
|
||||||
override Expr getControllingExpr() { none() }
|
|
||||||
|
|
||||||
/** Gets the collection that the loop iterates over. */
|
|
||||||
Expr getCollection() { none() }
|
|
||||||
|
|
||||||
/** Gets the body of the loop. */
|
|
||||||
override Stmt getStmt() { none() }
|
|
||||||
|
|
||||||
override string toString() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C category or class extension.
|
|
||||||
*/
|
|
||||||
deprecated class Category extends Class {
|
|
||||||
Category() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C class extension.
|
|
||||||
*/
|
|
||||||
deprecated class ClassExtension extends Category {
|
|
||||||
ClassExtension() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C try statement.
|
|
||||||
*/
|
|
||||||
deprecated class ObjcTryStmt extends TryStmt {
|
|
||||||
ObjcTryStmt() { none() }
|
|
||||||
|
|
||||||
override string toString() { none() }
|
|
||||||
|
|
||||||
/** Gets the finally clause of this try statement, if any. */
|
|
||||||
FinallyBlock getFinallyClause() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C `@finally` block.
|
|
||||||
*/
|
|
||||||
deprecated class FinallyBlock extends BlockStmt {
|
|
||||||
FinallyBlock() { none() }
|
|
||||||
|
|
||||||
/** Gets the try statement corresponding to this finally block. */
|
|
||||||
ObjcTryStmt getTryStmt() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C `@property`.
|
|
||||||
*/
|
|
||||||
deprecated class Property extends Declaration {
|
|
||||||
Property() { none() }
|
|
||||||
|
|
||||||
/** Gets the name of this property. */
|
|
||||||
override string getName() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets nothing (provided for compatibility with Declaration).
|
|
||||||
*
|
|
||||||
* For the attribute list following the `@property` keyword, use
|
|
||||||
* `getAnAttribute()`.
|
|
||||||
*/
|
|
||||||
override Specifier getASpecifier() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an attribute of this property (such as `readonly`, `nonatomic`,
|
|
||||||
* or `getter=isEnabled`).
|
|
||||||
*/
|
|
||||||
Attribute getAnAttribute() { none() }
|
|
||||||
|
|
||||||
override Location getADeclarationLocation() { result = getLocation() }
|
|
||||||
|
|
||||||
override Location getDefinitionLocation() { result = getLocation() }
|
|
||||||
|
|
||||||
override Location getLocation() { none() }
|
|
||||||
|
|
||||||
/** Gets the type of this property. */
|
|
||||||
Type getType() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the instance method which is called to get the value of this
|
|
||||||
* property.
|
|
||||||
*/
|
|
||||||
MemberFunction getGetter() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the instance method which is called to set the value of this
|
|
||||||
* property (if it is a writable property).
|
|
||||||
*/
|
|
||||||
MemberFunction getSetter() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the instance variable which stores the property value (if this
|
|
||||||
* property was explicitly or automatically `@synthesize`d).
|
|
||||||
*/
|
|
||||||
MemberVariable getInstanceVariable() { none() }
|
|
||||||
}
|
|
||||||
@@ -95,22 +95,6 @@ class Parameter extends LocalScopeVariable, @parameter {
|
|||||||
else result = this.getADeclarationEntry()
|
else result = this.getADeclarationEntry()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the name of this parameter in the given block (which should be
|
|
||||||
* the body of a function with which the parameter is associated).
|
|
||||||
*
|
|
||||||
* DEPRECATED: this method was used in a previous implementation of
|
|
||||||
* getName, but is no longer in use.
|
|
||||||
*/
|
|
||||||
deprecated string getNameInBlock(BlockStmt b) {
|
|
||||||
exists(ParameterDeclarationEntry pde |
|
|
||||||
pde.getFunctionDeclarationEntry().getBlock() = b and
|
|
||||||
this.getFunction().getBlock() = b and
|
|
||||||
pde.getVariable() = this and
|
|
||||||
result = pde.getName()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this parameter has a name.
|
* Holds if this parameter has a name.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ private import PrintAST
|
|||||||
private predicate shouldPrintDeclaration(Declaration decl) {
|
private predicate shouldPrintDeclaration(Declaration decl) {
|
||||||
not decl instanceof Function
|
not decl instanceof Function
|
||||||
or
|
or
|
||||||
not exists(PrintASTConfiguration c)
|
not exists(PrintAstConfiguration c)
|
||||||
or
|
or
|
||||||
exists(PrintASTConfiguration config | config.shouldPrintFunction(decl))
|
exists(PrintAstConfiguration config | config.shouldPrintFunction(decl))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import PrintAST
|
|||||||
* Temporarily tweak this class or make a copy to control which functions are
|
* Temporarily tweak this class or make a copy to control which functions are
|
||||||
* printed.
|
* printed.
|
||||||
*/
|
*/
|
||||||
class Cfg extends PrintASTConfiguration {
|
class Cfg extends PrintAstConfiguration {
|
||||||
/**
|
/**
|
||||||
* TWEAK THIS PREDICATE AS NEEDED.
|
* TWEAK THIS PREDICATE AS NEEDED.
|
||||||
* Holds if the AST for `func` should be printed.
|
* Holds if the AST for `func` should be printed.
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
import cpp
|
import cpp
|
||||||
private import semmle.code.cpp.Print
|
private import semmle.code.cpp.Print
|
||||||
|
|
||||||
private newtype TPrintASTConfiguration = MkPrintASTConfiguration()
|
private newtype TPrintAstConfiguration = MkPrintAstConfiguration()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The query can extend this class to control which functions are printed.
|
* The query can extend this class to control which functions are printed.
|
||||||
*/
|
*/
|
||||||
class PrintASTConfiguration extends TPrintASTConfiguration {
|
class PrintAstConfiguration extends TPrintAstConfiguration {
|
||||||
/**
|
/**
|
||||||
* Gets a textual representation of this `PrintASTConfiguration`.
|
* Gets a textual representation of this `PrintASTConfiguration`.
|
||||||
*/
|
*/
|
||||||
@@ -27,8 +27,11 @@ class PrintASTConfiguration extends TPrintASTConfiguration {
|
|||||||
predicate shouldPrintFunction(Function func) { any() }
|
predicate shouldPrintFunction(Function func) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for PrintAstConfiguration */
|
||||||
|
deprecated class PrintASTConfiguration = PrintAstConfiguration;
|
||||||
|
|
||||||
private predicate shouldPrintFunction(Function func) {
|
private predicate shouldPrintFunction(Function func) {
|
||||||
exists(PrintASTConfiguration config | config.shouldPrintFunction(func))
|
exists(PrintAstConfiguration config | config.shouldPrintFunction(func))
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[s]
|
bindingset[s]
|
||||||
@@ -85,8 +88,8 @@ private Function getEnclosingFunction(Locatable ast) {
|
|||||||
* Most nodes are just a wrapper around `Locatable`, but we do synthesize new
|
* Most nodes are just a wrapper around `Locatable`, but we do synthesize new
|
||||||
* nodes for things like parameter lists and constructor init lists.
|
* nodes for things like parameter lists and constructor init lists.
|
||||||
*/
|
*/
|
||||||
private newtype TPrintASTNode =
|
private newtype TPrintAstNode =
|
||||||
TASTNode(Locatable ast) { shouldPrintFunction(getEnclosingFunction(ast)) } or
|
TAstNode(Locatable ast) { shouldPrintFunction(getEnclosingFunction(ast)) } or
|
||||||
TDeclarationEntryNode(DeclStmt stmt, DeclarationEntry entry) {
|
TDeclarationEntryNode(DeclStmt stmt, DeclarationEntry entry) {
|
||||||
// We create a unique node for each pair of (stmt, entry), to avoid having one node with
|
// We create a unique node for each pair of (stmt, entry), to avoid having one node with
|
||||||
// multiple parents due to extractor bug CPP-413.
|
// multiple parents due to extractor bug CPP-413.
|
||||||
@@ -106,7 +109,7 @@ private newtype TPrintASTNode =
|
|||||||
/**
|
/**
|
||||||
* A node in the output tree.
|
* A node in the output tree.
|
||||||
*/
|
*/
|
||||||
class PrintASTNode extends TPrintASTNode {
|
class PrintAstNode extends TPrintAstNode {
|
||||||
/**
|
/**
|
||||||
* Gets a textual representation of this node in the PrintAST output tree.
|
* Gets a textual representation of this node in the PrintAST output tree.
|
||||||
*/
|
*/
|
||||||
@@ -116,17 +119,17 @@ class PrintASTNode extends TPrintASTNode {
|
|||||||
* Gets the child node at index `childIndex`. Child indices must be unique,
|
* Gets the child node at index `childIndex`. Child indices must be unique,
|
||||||
* but need not be contiguous.
|
* but need not be contiguous.
|
||||||
*/
|
*/
|
||||||
abstract PrintASTNode getChildInternal(int childIndex);
|
abstract PrintAstNode getChildInternal(int childIndex);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the child node at index `childIndex`.
|
* Gets the child node at index `childIndex`.
|
||||||
* Adds edges to fully converted expressions, that are not part of the
|
* Adds edges to fully converted expressions, that are not part of the
|
||||||
* regular parent/child relation traversal.
|
* regular parent/child relation traversal.
|
||||||
*/
|
*/
|
||||||
final PrintASTNode getChild(int childIndex) {
|
final PrintAstNode getChild(int childIndex) {
|
||||||
// The exact value of `childIndex` doesn't matter, as long as we preserve the correct order.
|
// The exact value of `childIndex` doesn't matter, as long as we preserve the correct order.
|
||||||
result =
|
result =
|
||||||
rank[childIndex](PrintASTNode child, int nonConvertedIndex, boolean isConverted |
|
rank[childIndex](PrintAstNode child, int nonConvertedIndex, boolean isConverted |
|
||||||
childAndAccessorPredicate(child, _, nonConvertedIndex, isConverted)
|
childAndAccessorPredicate(child, _, nonConvertedIndex, isConverted)
|
||||||
|
|
|
|
||||||
// Unconverted children come first, then sort by original child index within each group.
|
// Unconverted children come first, then sort by original child index within each group.
|
||||||
@@ -138,11 +141,11 @@ class PrintASTNode extends TPrintASTNode {
|
|||||||
* Gets the node for the `.getFullyConverted()` version of the child originally at index
|
* Gets the node for the `.getFullyConverted()` version of the child originally at index
|
||||||
* `childIndex`, if that node has any conversions.
|
* `childIndex`, if that node has any conversions.
|
||||||
*/
|
*/
|
||||||
private PrintASTNode getConvertedChild(int childIndex) {
|
private PrintAstNode getConvertedChild(int childIndex) {
|
||||||
exists(Expr expr |
|
exists(Expr expr |
|
||||||
expr = getChildInternal(childIndex).(ASTNode).getAST() and
|
expr = getChildInternal(childIndex).(AstNode).getAst() and
|
||||||
expr.getFullyConverted() instanceof Conversion and
|
expr.getFullyConverted() instanceof Conversion and
|
||||||
result.(ASTNode).getAST() = expr.getFullyConverted() and
|
result.(AstNode).getAst() = expr.getFullyConverted() and
|
||||||
not expr instanceof Conversion
|
not expr instanceof Conversion
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -166,12 +169,12 @@ class PrintASTNode extends TPrintASTNode {
|
|||||||
/**
|
/**
|
||||||
* Gets the children of this node.
|
* Gets the children of this node.
|
||||||
*/
|
*/
|
||||||
final PrintASTNode getAChild() { result = getChild(_) }
|
final PrintAstNode getAChild() { result = getChild(_) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the parent of this node, if any.
|
* Gets the parent of this node, if any.
|
||||||
*/
|
*/
|
||||||
final PrintASTNode getParent() { result.getAChild() = this }
|
final PrintAstNode getParent() { result.getAChild() = this }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the location of this node in the source code.
|
* Gets the location of this node in the source code.
|
||||||
@@ -196,7 +199,7 @@ class PrintASTNode extends TPrintASTNode {
|
|||||||
* one result tuple, with `isConverted = false`.
|
* one result tuple, with `isConverted = false`.
|
||||||
*/
|
*/
|
||||||
private predicate childAndAccessorPredicate(
|
private predicate childAndAccessorPredicate(
|
||||||
PrintASTNode child, string childPredicate, int nonConvertedIndex, boolean isConverted
|
PrintAstNode child, string childPredicate, int nonConvertedIndex, boolean isConverted
|
||||||
) {
|
) {
|
||||||
child = getChildInternal(nonConvertedIndex) and
|
child = getChildInternal(nonConvertedIndex) and
|
||||||
childPredicate = getChildAccessorPredicateInternal(nonConvertedIndex) and
|
childPredicate = getChildAccessorPredicateInternal(nonConvertedIndex) and
|
||||||
@@ -234,12 +237,15 @@ class PrintASTNode extends TPrintASTNode {
|
|||||||
private Function getEnclosingFunction() { result = getParent*().(FunctionNode).getFunction() }
|
private Function getEnclosingFunction() { result = getParent*().(FunctionNode).getFunction() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for PrintAstNode */
|
||||||
|
deprecated class PrintASTNode = PrintAstNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that restricts the elements that we compute `qlClass` for.
|
* Class that restricts the elements that we compute `qlClass` for.
|
||||||
*/
|
*/
|
||||||
private class PrintableElement extends Element {
|
private class PrintableElement extends Element {
|
||||||
PrintableElement() {
|
PrintableElement() {
|
||||||
exists(TASTNode(this))
|
exists(TAstNode(this))
|
||||||
or
|
or
|
||||||
exists(TDeclarationEntryNode(_, this))
|
exists(TDeclarationEntryNode(_, this))
|
||||||
or
|
or
|
||||||
@@ -262,7 +268,7 @@ private string qlClass(PrintableElement el) {
|
|||||||
/**
|
/**
|
||||||
* A node representing an AST node.
|
* A node representing an AST node.
|
||||||
*/
|
*/
|
||||||
abstract class BaseASTNode extends PrintASTNode {
|
abstract class BaseAstNode extends PrintAstNode {
|
||||||
Locatable ast;
|
Locatable ast;
|
||||||
|
|
||||||
override string toString() { result = qlClass(ast) + ast.toString() }
|
override string toString() { result = qlClass(ast) + ast.toString() }
|
||||||
@@ -272,25 +278,34 @@ abstract class BaseASTNode extends PrintASTNode {
|
|||||||
/**
|
/**
|
||||||
* Gets the AST represented by this node.
|
* Gets the AST represented by this node.
|
||||||
*/
|
*/
|
||||||
final Locatable getAST() { result = ast }
|
final Locatable getAst() { result = ast }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated Locatable getAST() { result = getAst() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for BaseAstNode */
|
||||||
|
deprecated class BaseASTNode = BaseAstNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node representing an AST node other than a `DeclarationEntry`.
|
* A node representing an AST node other than a `DeclarationEntry`.
|
||||||
*/
|
*/
|
||||||
abstract class ASTNode extends BaseASTNode, TASTNode {
|
abstract class AstNode extends BaseAstNode, TAstNode {
|
||||||
ASTNode() { this = TASTNode(ast) }
|
AstNode() { this = TAstNode(ast) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for AstNode */
|
||||||
|
deprecated class ASTNode = AstNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node representing an `Expr`.
|
* A node representing an `Expr`.
|
||||||
*/
|
*/
|
||||||
class ExprNode extends ASTNode {
|
class ExprNode extends AstNode {
|
||||||
Expr expr;
|
Expr expr;
|
||||||
|
|
||||||
ExprNode() { expr = ast }
|
ExprNode() { expr = ast }
|
||||||
|
|
||||||
override ASTNode getChildInternal(int childIndex) { result.getAST() = expr.getChild(childIndex) }
|
override AstNode getChildInternal(int childIndex) { result.getAst() = expr.getChild(childIndex) }
|
||||||
|
|
||||||
override string getProperty(string key) {
|
override string getProperty(string key) {
|
||||||
result = super.getProperty(key)
|
result = super.getProperty(key)
|
||||||
@@ -306,7 +321,7 @@ class ExprNode extends ASTNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||||
result = getChildAccessorWithoutConversions(ast, getChildInternal(childIndex).getAST())
|
result = getChildAccessorWithoutConversions(ast, getChildInternal(childIndex).getAst())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -334,9 +349,9 @@ class ConversionNode extends ExprNode {
|
|||||||
|
|
||||||
ConversionNode() { conv = expr }
|
ConversionNode() { conv = expr }
|
||||||
|
|
||||||
override ASTNode getChildInternal(int childIndex) {
|
override AstNode getChildInternal(int childIndex) {
|
||||||
childIndex = 0 and
|
childIndex = 0 and
|
||||||
result.getAST() = conv.getExpr() and
|
result.getAst() = conv.getExpr() and
|
||||||
conv.getExpr() instanceof Conversion
|
conv.getExpr() instanceof Conversion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -363,27 +378,27 @@ class CastNode extends ConversionNode {
|
|||||||
class StmtExprNode extends ExprNode {
|
class StmtExprNode extends ExprNode {
|
||||||
override StmtExpr expr;
|
override StmtExpr expr;
|
||||||
|
|
||||||
override ASTNode getChildInternal(int childIndex) {
|
override AstNode getChildInternal(int childIndex) {
|
||||||
childIndex = 0 and
|
childIndex = 0 and
|
||||||
result.getAST() = expr.getStmt()
|
result.getAst() = expr.getStmt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node representing a `DeclarationEntry`.
|
* A node representing a `DeclarationEntry`.
|
||||||
*/
|
*/
|
||||||
class DeclarationEntryNode extends BaseASTNode, TDeclarationEntryNode {
|
class DeclarationEntryNode extends BaseAstNode, TDeclarationEntryNode {
|
||||||
override DeclarationEntry ast;
|
override DeclarationEntry ast;
|
||||||
DeclStmt declStmt;
|
DeclStmt declStmt;
|
||||||
|
|
||||||
DeclarationEntryNode() { this = TDeclarationEntryNode(declStmt, ast) }
|
DeclarationEntryNode() { this = TDeclarationEntryNode(declStmt, ast) }
|
||||||
|
|
||||||
override PrintASTNode getChildInternal(int childIndex) { none() }
|
override PrintAstNode getChildInternal(int childIndex) { none() }
|
||||||
|
|
||||||
override string getChildAccessorPredicateInternal(int childIndex) { none() }
|
override string getChildAccessorPredicateInternal(int childIndex) { none() }
|
||||||
|
|
||||||
override string getProperty(string key) {
|
override string getProperty(string key) {
|
||||||
result = BaseASTNode.super.getProperty(key)
|
result = BaseAstNode.super.getProperty(key)
|
||||||
or
|
or
|
||||||
key = "Type" and
|
key = "Type" and
|
||||||
result = qlClass(ast.getType()) + ast.getType().toString()
|
result = qlClass(ast.getType()) + ast.getType().toString()
|
||||||
@@ -396,9 +411,9 @@ class DeclarationEntryNode extends BaseASTNode, TDeclarationEntryNode {
|
|||||||
class VariableDeclarationEntryNode extends DeclarationEntryNode {
|
class VariableDeclarationEntryNode extends DeclarationEntryNode {
|
||||||
override VariableDeclarationEntry ast;
|
override VariableDeclarationEntry ast;
|
||||||
|
|
||||||
override ASTNode getChildInternal(int childIndex) {
|
override AstNode getChildInternal(int childIndex) {
|
||||||
childIndex = 0 and
|
childIndex = 0 and
|
||||||
result.getAST() = ast.getVariable().getInitializer()
|
result.getAst() = ast.getVariable().getInitializer()
|
||||||
}
|
}
|
||||||
|
|
||||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||||
@@ -410,23 +425,23 @@ class VariableDeclarationEntryNode extends DeclarationEntryNode {
|
|||||||
/**
|
/**
|
||||||
* A node representing a `Stmt`.
|
* A node representing a `Stmt`.
|
||||||
*/
|
*/
|
||||||
class StmtNode extends ASTNode {
|
class StmtNode extends AstNode {
|
||||||
Stmt stmt;
|
Stmt stmt;
|
||||||
|
|
||||||
StmtNode() { stmt = ast }
|
StmtNode() { stmt = ast }
|
||||||
|
|
||||||
override BaseASTNode getChildInternal(int childIndex) {
|
override BaseAstNode getChildInternal(int childIndex) {
|
||||||
exists(Locatable child |
|
exists(Locatable child |
|
||||||
child = stmt.getChild(childIndex) and
|
child = stmt.getChild(childIndex) and
|
||||||
(
|
(
|
||||||
result.getAST() = child.(Expr) or
|
result.getAst() = child.(Expr) or
|
||||||
result.getAST() = child.(Stmt)
|
result.getAst() = child.(Stmt)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||||
result = getChildAccessorWithoutConversions(ast, getChildInternal(childIndex).getAST())
|
result = getChildAccessorWithoutConversions(ast, getChildInternal(childIndex).getAst())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,12 +464,12 @@ class DeclStmtNode extends StmtNode {
|
|||||||
/**
|
/**
|
||||||
* A node representing a `Parameter`.
|
* A node representing a `Parameter`.
|
||||||
*/
|
*/
|
||||||
class ParameterNode extends ASTNode {
|
class ParameterNode extends AstNode {
|
||||||
Parameter param;
|
Parameter param;
|
||||||
|
|
||||||
ParameterNode() { param = ast }
|
ParameterNode() { param = ast }
|
||||||
|
|
||||||
final override PrintASTNode getChildInternal(int childIndex) { none() }
|
final override PrintAstNode getChildInternal(int childIndex) { none() }
|
||||||
|
|
||||||
final override string getChildAccessorPredicateInternal(int childIndex) { none() }
|
final override string getChildAccessorPredicateInternal(int childIndex) { none() }
|
||||||
|
|
||||||
@@ -469,14 +484,14 @@ class ParameterNode extends ASTNode {
|
|||||||
/**
|
/**
|
||||||
* A node representing an `Initializer`.
|
* A node representing an `Initializer`.
|
||||||
*/
|
*/
|
||||||
class InitializerNode extends ASTNode {
|
class InitializerNode extends AstNode {
|
||||||
Initializer init;
|
Initializer init;
|
||||||
|
|
||||||
InitializerNode() { init = ast }
|
InitializerNode() { init = ast }
|
||||||
|
|
||||||
override ASTNode getChildInternal(int childIndex) {
|
override AstNode getChildInternal(int childIndex) {
|
||||||
childIndex = 0 and
|
childIndex = 0 and
|
||||||
result.getAST() = init.getExpr()
|
result.getAst() = init.getExpr()
|
||||||
}
|
}
|
||||||
|
|
||||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||||
@@ -488,7 +503,7 @@ class InitializerNode extends ASTNode {
|
|||||||
/**
|
/**
|
||||||
* A node representing the parameters of a `Function`.
|
* A node representing the parameters of a `Function`.
|
||||||
*/
|
*/
|
||||||
class ParametersNode extends PrintASTNode, TParametersNode {
|
class ParametersNode extends PrintAstNode, TParametersNode {
|
||||||
Function func;
|
Function func;
|
||||||
|
|
||||||
ParametersNode() { this = TParametersNode(func) }
|
ParametersNode() { this = TParametersNode(func) }
|
||||||
@@ -497,8 +512,8 @@ class ParametersNode extends PrintASTNode, TParametersNode {
|
|||||||
|
|
||||||
final override Location getLocation() { result = getRepresentativeLocation(func) }
|
final override Location getLocation() { result = getRepresentativeLocation(func) }
|
||||||
|
|
||||||
override ASTNode getChildInternal(int childIndex) {
|
override AstNode getChildInternal(int childIndex) {
|
||||||
result.getAST() = func.getParameter(childIndex)
|
result.getAst() = func.getParameter(childIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||||
@@ -515,7 +530,7 @@ class ParametersNode extends PrintASTNode, TParametersNode {
|
|||||||
/**
|
/**
|
||||||
* A node representing the initializer list of a `Constructor`.
|
* A node representing the initializer list of a `Constructor`.
|
||||||
*/
|
*/
|
||||||
class ConstructorInitializersNode extends PrintASTNode, TConstructorInitializersNode {
|
class ConstructorInitializersNode extends PrintAstNode, TConstructorInitializersNode {
|
||||||
Constructor ctor;
|
Constructor ctor;
|
||||||
|
|
||||||
ConstructorInitializersNode() { this = TConstructorInitializersNode(ctor) }
|
ConstructorInitializersNode() { this = TConstructorInitializersNode(ctor) }
|
||||||
@@ -524,8 +539,8 @@ class ConstructorInitializersNode extends PrintASTNode, TConstructorInitializers
|
|||||||
|
|
||||||
final override Location getLocation() { result = getRepresentativeLocation(ctor) }
|
final override Location getLocation() { result = getRepresentativeLocation(ctor) }
|
||||||
|
|
||||||
final override ASTNode getChildInternal(int childIndex) {
|
final override AstNode getChildInternal(int childIndex) {
|
||||||
result.getAST() = ctor.getInitializer(childIndex)
|
result.getAst() = ctor.getInitializer(childIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
final override string getChildAccessorPredicateInternal(int childIndex) {
|
final override string getChildAccessorPredicateInternal(int childIndex) {
|
||||||
@@ -542,7 +557,7 @@ class ConstructorInitializersNode extends PrintASTNode, TConstructorInitializers
|
|||||||
/**
|
/**
|
||||||
* A node representing the destruction list of a `Destructor`.
|
* A node representing the destruction list of a `Destructor`.
|
||||||
*/
|
*/
|
||||||
class DestructorDestructionsNode extends PrintASTNode, TDestructorDestructionsNode {
|
class DestructorDestructionsNode extends PrintAstNode, TDestructorDestructionsNode {
|
||||||
Destructor dtor;
|
Destructor dtor;
|
||||||
|
|
||||||
DestructorDestructionsNode() { this = TDestructorDestructionsNode(dtor) }
|
DestructorDestructionsNode() { this = TDestructorDestructionsNode(dtor) }
|
||||||
@@ -551,8 +566,8 @@ class DestructorDestructionsNode extends PrintASTNode, TDestructorDestructionsNo
|
|||||||
|
|
||||||
final override Location getLocation() { result = getRepresentativeLocation(dtor) }
|
final override Location getLocation() { result = getRepresentativeLocation(dtor) }
|
||||||
|
|
||||||
final override ASTNode getChildInternal(int childIndex) {
|
final override AstNode getChildInternal(int childIndex) {
|
||||||
result.getAST() = dtor.getDestruction(childIndex)
|
result.getAst() = dtor.getDestruction(childIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
final override string getChildAccessorPredicateInternal(int childIndex) {
|
final override string getChildAccessorPredicateInternal(int childIndex) {
|
||||||
@@ -569,14 +584,14 @@ class DestructorDestructionsNode extends PrintASTNode, TDestructorDestructionsNo
|
|||||||
/**
|
/**
|
||||||
* A node representing a `Function`.
|
* A node representing a `Function`.
|
||||||
*/
|
*/
|
||||||
class FunctionNode extends ASTNode {
|
class FunctionNode extends AstNode {
|
||||||
Function func;
|
Function func;
|
||||||
|
|
||||||
FunctionNode() { func = ast }
|
FunctionNode() { func = ast }
|
||||||
|
|
||||||
override string toString() { result = qlClass(func) + getIdentityString(func) }
|
override string toString() { result = qlClass(func) + getIdentityString(func) }
|
||||||
|
|
||||||
override PrintASTNode getChildInternal(int childIndex) {
|
override PrintAstNode getChildInternal(int childIndex) {
|
||||||
childIndex = 0 and
|
childIndex = 0 and
|
||||||
result.(ParametersNode).getFunction() = func
|
result.(ParametersNode).getFunction() = func
|
||||||
or
|
or
|
||||||
@@ -584,7 +599,7 @@ class FunctionNode extends ASTNode {
|
|||||||
result.(ConstructorInitializersNode).getConstructor() = func
|
result.(ConstructorInitializersNode).getConstructor() = func
|
||||||
or
|
or
|
||||||
childIndex = 2 and
|
childIndex = 2 and
|
||||||
result.(ASTNode).getAST() = func.getEntryPoint()
|
result.(AstNode).getAst() = func.getEntryPoint()
|
||||||
or
|
or
|
||||||
childIndex = 3 and
|
childIndex = 3 and
|
||||||
result.(DestructorDestructionsNode).getDestructor() = func
|
result.(DestructorDestructionsNode).getDestructor() = func
|
||||||
@@ -603,7 +618,7 @@ class FunctionNode extends ASTNode {
|
|||||||
private int getOrder() {
|
private int getOrder() {
|
||||||
this =
|
this =
|
||||||
rank[result](FunctionNode node, Function function, string file, int line, int column |
|
rank[result](FunctionNode node, Function function, string file, int line, int column |
|
||||||
node.getAST() = function and
|
node.getAst() = function and
|
||||||
locationSortKeys(function, file, line, column)
|
locationSortKeys(function, file, line, column)
|
||||||
|
|
|
|
||||||
node order by file, line, column, getIdentityString(function)
|
node order by file, line, column, getIdentityString(function)
|
||||||
@@ -856,7 +871,7 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */
|
/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */
|
||||||
query predicate nodes(PrintASTNode node, string key, string value) {
|
query predicate nodes(PrintAstNode node, string key, string value) {
|
||||||
node.shouldPrint() and
|
node.shouldPrint() and
|
||||||
value = node.getProperty(key)
|
value = node.getProperty(key)
|
||||||
}
|
}
|
||||||
@@ -865,7 +880,7 @@ query predicate nodes(PrintASTNode node, string key, string value) {
|
|||||||
* Holds if `target` is a child of `source` in the AST, and property `key` of the edge has the
|
* Holds if `target` is a child of `source` in the AST, and property `key` of the edge has the
|
||||||
* given `value`.
|
* given `value`.
|
||||||
*/
|
*/
|
||||||
query predicate edges(PrintASTNode source, PrintASTNode target, string key, string value) {
|
query predicate edges(PrintAstNode source, PrintAstNode target, string key, string value) {
|
||||||
exists(int childIndex |
|
exists(int childIndex |
|
||||||
source.shouldPrint() and
|
source.shouldPrint() and
|
||||||
target.shouldPrint() and
|
target.shouldPrint() and
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class FunctionSpecifier extends Specifier {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A C/C++ storage class specifier: `auto`, `register`, `static`, `extern`,
|
* A C/C++ storage class specifier: `auto`, `register`, `static`, `extern`,
|
||||||
* or `mutable".
|
* or `mutable`.
|
||||||
*/
|
*/
|
||||||
class StorageClassSpecifier extends Specifier {
|
class StorageClassSpecifier extends Specifier {
|
||||||
StorageClassSpecifier() { this.hasName(["auto", "register", "static", "extern", "mutable"]) }
|
StorageClassSpecifier() { this.hasName(["auto", "register", "static", "extern", "mutable"]) }
|
||||||
|
|||||||
@@ -1085,50 +1085,6 @@ class DerivedType extends Type, @derivedtype {
|
|||||||
override predicate involvesTemplateParameter() { this.getBaseType().involvesTemplateParameter() }
|
override predicate involvesTemplateParameter() { this.getBaseType().involvesTemplateParameter() }
|
||||||
|
|
||||||
override Type stripType() { result = this.getBaseType().stripType() }
|
override Type stripType() { result = this.getBaseType().stripType() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this type has the `__autoreleasing` specifier or if it points to
|
|
||||||
* a type with the `__autoreleasing` specifier.
|
|
||||||
*
|
|
||||||
* DEPRECATED: use `hasSpecifier` directly instead.
|
|
||||||
*/
|
|
||||||
deprecated predicate isAutoReleasing() {
|
|
||||||
this.hasSpecifier("__autoreleasing") or
|
|
||||||
this.(PointerType).getBaseType().hasSpecifier("__autoreleasing")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this type has the `__strong` specifier or if it points to
|
|
||||||
* a type with the `__strong` specifier.
|
|
||||||
*
|
|
||||||
* DEPRECATED: use `hasSpecifier` directly instead.
|
|
||||||
*/
|
|
||||||
deprecated predicate isStrong() {
|
|
||||||
this.hasSpecifier("__strong") or
|
|
||||||
this.(PointerType).getBaseType().hasSpecifier("__strong")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this type has the `__unsafe_unretained` specifier or if it points
|
|
||||||
* to a type with the `__unsafe_unretained` specifier.
|
|
||||||
*
|
|
||||||
* DEPRECATED: use `hasSpecifier` directly instead.
|
|
||||||
*/
|
|
||||||
deprecated predicate isUnsafeRetained() {
|
|
||||||
this.hasSpecifier("__unsafe_unretained") or
|
|
||||||
this.(PointerType).getBaseType().hasSpecifier("__unsafe_unretained")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this type has the `__weak` specifier or if it points to
|
|
||||||
* a type with the `__weak` specifier.
|
|
||||||
*
|
|
||||||
* DEPRECATED: use `hasSpecifier` directly instead.
|
|
||||||
*/
|
|
||||||
deprecated predicate isWeak() {
|
|
||||||
this.hasSpecifier("__weak") or
|
|
||||||
this.(PointerType).getBaseType().hasSpecifier("__weak")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -106,25 +106,4 @@ class NestedTypedefType extends TypedefType {
|
|||||||
NestedTypedefType() { this.isMember() }
|
NestedTypedefType() { this.isMember() }
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "NestedTypedefType" }
|
override string getAPrimaryQlClass() { result = "NestedTypedefType" }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: use `.hasSpecifier("private")` instead.
|
|
||||||
*
|
|
||||||
* Holds if this member is private.
|
|
||||||
*/
|
|
||||||
deprecated predicate isPrivate() { this.hasSpecifier("private") }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: `.hasSpecifier("protected")` instead.
|
|
||||||
*
|
|
||||||
* Holds if this member is protected.
|
|
||||||
*/
|
|
||||||
deprecated predicate isProtected() { this.hasSpecifier("protected") }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: use `.hasSpecifier("public")` instead.
|
|
||||||
*
|
|
||||||
* Holds if this member is public.
|
|
||||||
*/
|
|
||||||
deprecated predicate isPublic() { this.hasSpecifier("public") }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -556,24 +556,6 @@ class MemberVariable extends Variable, @membervariable {
|
|||||||
private Type getAType() { membervariables(underlyingElement(this), unresolveElement(result), _) }
|
private Type getAType() { membervariables(underlyingElement(this), unresolveElement(result), _) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A C/C++ function pointer variable.
|
|
||||||
*
|
|
||||||
* DEPRECATED: use `Variable.getType() instanceof FunctionPointerType` instead.
|
|
||||||
*/
|
|
||||||
deprecated class FunctionPointerVariable extends Variable {
|
|
||||||
FunctionPointerVariable() { this.getType() instanceof FunctionPointerType }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A C/C++ function pointer member variable.
|
|
||||||
*
|
|
||||||
* DEPRECATED: use `MemberVariable.getType() instanceof FunctionPointerType` instead.
|
|
||||||
*/
|
|
||||||
deprecated class FunctionPointerMemberVariable extends MemberVariable {
|
|
||||||
FunctionPointerMemberVariable() { this instanceof FunctionPointerVariable }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A C++14 variable template. For example, in the following code the variable
|
* A C++14 variable template. For example, in the following code the variable
|
||||||
* template `v` defines a family of variables:
|
* template `v` defines a family of variables:
|
||||||
|
|||||||
@@ -4,21 +4,14 @@
|
|||||||
|
|
||||||
import semmle.files.FileSystem
|
import semmle.files.FileSystem
|
||||||
|
|
||||||
private class TXMLLocatable =
|
private class TXmlLocatable =
|
||||||
@xmldtd or @xmlelement or @xmlattribute or @xmlnamespace or @xmlcomment or @xmlcharacters;
|
@xmldtd or @xmlelement or @xmlattribute or @xmlnamespace or @xmlcomment or @xmlcharacters;
|
||||||
|
|
||||||
/** An XML element that has a location. */
|
/** An XML element that has a location. */
|
||||||
class XMLLocatable extends @xmllocatable, TXMLLocatable {
|
class XMLLocatable extends @xmllocatable, TXmlLocatable {
|
||||||
/** Gets the source location for this element. */
|
/** Gets the source location for this element. */
|
||||||
Location getLocation() { xmllocations(this, result) }
|
Location getLocation() { xmllocations(this, result) }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `getLocation()` instead.
|
|
||||||
*
|
|
||||||
* Gets the source location for this element.
|
|
||||||
*/
|
|
||||||
deprecated Location getALocation() { result = this.getLocation() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this element is at the specified location.
|
* Holds if this element is at the specified location.
|
||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
@@ -83,21 +76,6 @@ class XMLParent extends @xmlparent {
|
|||||||
/** Gets the number of places in the body of this XML parent where text occurs. */
|
/** Gets the number of places in the body of this XML parent where text occurs. */
|
||||||
int getNumberOfCharacterSets() { result = count(int pos | xmlChars(_, _, this, pos, _, _)) }
|
int getNumberOfCharacterSets() { result = count(int pos | xmlChars(_, _, this, pos, _, _)) }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Internal.
|
|
||||||
*
|
|
||||||
* Append the character sequences of this XML parent from left to right, separated by a space,
|
|
||||||
* up to a specified (zero-based) index.
|
|
||||||
*/
|
|
||||||
deprecated string charsSetUpTo(int n) {
|
|
||||||
n = 0 and xmlChars(_, result, this, 0, _, _)
|
|
||||||
or
|
|
||||||
n > 0 and
|
|
||||||
exists(string chars | xmlChars(_, chars, this, n, _, _) |
|
|
||||||
result = this.charsSetUpTo(n - 1) + " " + chars
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the result of appending all the character sequences of this XML parent from
|
* Gets the result of appending all the character sequences of this XML parent from
|
||||||
* left to right, separated by a space.
|
* left to right, separated by a space.
|
||||||
|
|||||||
@@ -2,20 +2,6 @@ import cpp
|
|||||||
import semmle.code.cpp.models.interfaces.Allocation
|
import semmle.code.cpp.models.interfaces.Allocation
|
||||||
import semmle.code.cpp.models.interfaces.Deallocation
|
import semmle.code.cpp.models.interfaces.Deallocation
|
||||||
|
|
||||||
/**
|
|
||||||
* A library routine that allocates memory.
|
|
||||||
*
|
|
||||||
* DEPRECATED: Use the `AllocationFunction` class instead of this predicate.
|
|
||||||
*/
|
|
||||||
deprecated predicate allocationFunction(Function f) { f instanceof AllocationFunction }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A call to a library routine that allocates memory.
|
|
||||||
*
|
|
||||||
* DEPRECATED: Use `AllocationExpr` instead (this also includes `new` expressions).
|
|
||||||
*/
|
|
||||||
deprecated predicate allocationCall(FunctionCall fc) { fc instanceof AllocationExpr }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A library routine that frees memory.
|
* A library routine that frees memory.
|
||||||
*/
|
*/
|
||||||
@@ -33,13 +19,6 @@ predicate freeCall(FunctionCall fc, Expr arg) { arg = fc.(DeallocationExpr).getF
|
|||||||
*/
|
*/
|
||||||
predicate isMemoryManagementExpr(Expr e) { isAllocationExpr(e) or e instanceof DeallocationExpr }
|
predicate isMemoryManagementExpr(Expr e) { isAllocationExpr(e) or e instanceof DeallocationExpr }
|
||||||
|
|
||||||
/**
|
|
||||||
* Is e an allocation from stdlib.h (`malloc`, `realloc` etc)?
|
|
||||||
*
|
|
||||||
* DEPRECATED: Use `AllocationExpr` instead (this also includes `new` expressions).
|
|
||||||
*/
|
|
||||||
deprecated predicate isStdLibAllocationExpr(Expr e) { allocationCall(e) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is e some kind of allocation (`new`, `alloc`, `realloc` etc)?
|
* Is e some kind of allocation (`new`, `alloc`, `realloc` etc)?
|
||||||
*/
|
*/
|
||||||
@@ -48,19 +27,3 @@ predicate isAllocationExpr(Expr e) {
|
|||||||
or
|
or
|
||||||
e = any(NewOrNewArrayExpr new | not exists(new.getPlacementPointer()))
|
e = any(NewOrNewArrayExpr new | not exists(new.getPlacementPointer()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Is e some kind of allocation (`new`, `alloc`, `realloc` etc) with a fixed size?
|
|
||||||
*
|
|
||||||
* DEPRECATED: Use `AllocationExpr.getSizeBytes()` instead.
|
|
||||||
*/
|
|
||||||
deprecated predicate isFixedSizeAllocationExpr(Expr allocExpr, int size) {
|
|
||||||
size = allocExpr.(AllocationExpr).getSizeBytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is e some kind of deallocation (`delete`, `free`, `realloc` etc)?
|
|
||||||
*
|
|
||||||
* DEPRECATED: Use `DeallocationExpr` instead.
|
|
||||||
*/
|
|
||||||
deprecated predicate isDeallocationExpr(Expr e) { e instanceof DeallocationExpr }
|
|
||||||
|
|||||||
@@ -207,26 +207,6 @@ predicate variadicFormatter(Function f, string type, int formatParamIndex, int o
|
|||||||
callsVariadicFormatter(f, type, formatParamIndex, outputParamIndex)
|
callsVariadicFormatter(f, type, formatParamIndex, outputParamIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A standard function such as `vprintf` that has a format parameter
|
|
||||||
* and a variable argument list of type `va_arg`.
|
|
||||||
*
|
|
||||||
* DEPRECATED: Use the four argument version instead.
|
|
||||||
*/
|
|
||||||
deprecated predicate primitiveVariadicFormatter(TopLevelFunction f, int formatParamIndex) {
|
|
||||||
primitiveVariadicFormatter(f, _, formatParamIndex, _)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `f` is a function such as `vprintf` that has a format parameter
|
|
||||||
* (at `formatParamIndex`) and a variable argument list of type `va_arg`.
|
|
||||||
*
|
|
||||||
* DEPRECATED: Use the four argument version instead.
|
|
||||||
*/
|
|
||||||
deprecated predicate variadicFormatter(Function f, int formatParamIndex) {
|
|
||||||
variadicFormatter(f, _, formatParamIndex, _)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function not in the standard library which takes a `printf`-like formatting
|
* A function not in the standard library which takes a `printf`-like formatting
|
||||||
* string and a variable number of arguments.
|
* string and a variable number of arguments.
|
||||||
@@ -428,13 +408,6 @@ class FormatLiteral extends Literal {
|
|||||||
*/
|
*/
|
||||||
FormattingFunctionCall getUse() { result.getFormat() = this }
|
FormattingFunctionCall getUse() { result.getFormat() = this }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the default meaning of `%s` is a `wchar_t *`, rather than
|
|
||||||
* a `char *` (either way, `%S` will have the opposite meaning).
|
|
||||||
* DEPRECATED: Use getDefaultCharType() instead.
|
|
||||||
*/
|
|
||||||
deprecated predicate isWideCharDefault() { this.getUse().getTarget().isWideCharDefault() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the default character type expected for `%s` by this format literal. Typically
|
* Gets the default character type expected for `%s` by this format literal. Typically
|
||||||
* `char` or `wchar_t`.
|
* `char` or `wchar_t`.
|
||||||
|
|||||||
@@ -223,20 +223,6 @@ class BasicBlock extends ControlFlowNodeBase {
|
|||||||
*/
|
*/
|
||||||
predicate inLoop() { this.getASuccessor+() = this }
|
predicate inLoop() { this.getASuccessor+() = this }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED since version 1.11: this predicate does not match the standard
|
|
||||||
* definition of _loop header_.
|
|
||||||
*
|
|
||||||
* Holds if this basic block is in a loop of the control-flow graph and
|
|
||||||
* additionally has an incoming edge that is not part of any loop containing
|
|
||||||
* this basic block. A typical example would be the basic block that computes
|
|
||||||
* `x > 0` in an outermost loop `while (x > 0) { ... }`.
|
|
||||||
*/
|
|
||||||
deprecated predicate isLoopHeader() {
|
|
||||||
this.inLoop() and
|
|
||||||
exists(BasicBlock pred | pred = this.getAPredecessor() and not pred = this.getASuccessor+())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if control flow may reach this basic block from a function entry
|
* Holds if control flow may reach this basic block from a function entry
|
||||||
* point or any handler of a reachable `try` statement.
|
* point or any handler of a reachable `try` statement.
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase {
|
|||||||
* taken when this expression is true.
|
* taken when this expression is true.
|
||||||
*/
|
*/
|
||||||
ControlFlowNode getATrueSuccessor() {
|
ControlFlowNode getATrueSuccessor() {
|
||||||
qlCFGTrueSuccessor(this, result) and
|
qlCfgTrueSuccessor(this, result) and
|
||||||
result = this.getASuccessor()
|
result = this.getASuccessor()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase {
|
|||||||
* taken when this expression is false.
|
* taken when this expression is false.
|
||||||
*/
|
*/
|
||||||
ControlFlowNode getAFalseSuccessor() {
|
ControlFlowNode getAFalseSuccessor() {
|
||||||
qlCFGFalseSuccessor(this, result) and
|
qlCfgFalseSuccessor(this, result) and
|
||||||
result = this.getASuccessor()
|
result = this.getASuccessor()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,24 +94,6 @@ import ControlFlowGraphPublic
|
|||||||
*/
|
*/
|
||||||
class ControlFlowNodeBase extends ElementBase, @cfgnode { }
|
class ControlFlowNodeBase extends ElementBase, @cfgnode { }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `ControlFlowNode.getATrueSuccessor()` instead.
|
|
||||||
* Holds when `n2` is a control-flow node such that the control-flow
|
|
||||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is true.
|
|
||||||
*/
|
|
||||||
deprecated predicate truecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) {
|
|
||||||
qlCFGTrueSuccessor(n1, n2)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `ControlFlowNode.getAFalseSuccessor()` instead.
|
|
||||||
* Holds when `n2` is a control-flow node such that the control-flow
|
|
||||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is false.
|
|
||||||
*/
|
|
||||||
deprecated predicate falsecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) {
|
|
||||||
qlCFGFalseSuccessor(n1, n2)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract class that can be extended to add additional edges to the
|
* An abstract class that can be extended to add additional edges to the
|
||||||
* control-flow graph. Instances of this class correspond to the source nodes
|
* control-flow graph. Instances of this class correspond to the source nodes
|
||||||
@@ -139,7 +121,7 @@ abstract class AdditionalControlFlowEdge extends ControlFlowNodeBase {
|
|||||||
* `AdditionalControlFlowEdge`. Use this relation instead of `qlCFGSuccessor`.
|
* `AdditionalControlFlowEdge`. Use this relation instead of `qlCFGSuccessor`.
|
||||||
*/
|
*/
|
||||||
predicate successors_extended(ControlFlowNodeBase source, ControlFlowNodeBase target) {
|
predicate successors_extended(ControlFlowNodeBase source, ControlFlowNodeBase target) {
|
||||||
qlCFGSuccessor(source, target)
|
qlCfgSuccessor(source, target)
|
||||||
or
|
or
|
||||||
source.(AdditionalControlFlowEdge).getAnEdgeTarget() = target
|
source.(AdditionalControlFlowEdge).getAnEdgeTarget() = target
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ class GuardCondition extends Expr {
|
|||||||
or
|
or
|
||||||
// the IR short-circuits if(!x)
|
// the IR short-circuits if(!x)
|
||||||
// don't produce a guard condition for `y = !x` and other non-short-circuited cases
|
// don't produce a guard condition for `y = !x` and other non-short-circuited cases
|
||||||
not exists(Instruction inst | this.getFullyConverted() = inst.getAST()) and
|
not exists(Instruction inst | this.getFullyConverted() = inst.getAst()) and
|
||||||
exists(IRGuardCondition ir | this.(NotExpr).getOperand() = ir.getAST())
|
exists(IRGuardCondition ir | this.(NotExpr).getOperand() = ir.getAst())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -146,8 +146,8 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardCondition {
|
|||||||
*/
|
*/
|
||||||
private class GuardConditionFromShortCircuitNot extends GuardCondition, NotExpr {
|
private class GuardConditionFromShortCircuitNot extends GuardCondition, NotExpr {
|
||||||
GuardConditionFromShortCircuitNot() {
|
GuardConditionFromShortCircuitNot() {
|
||||||
not exists(Instruction inst | this.getFullyConverted() = inst.getAST()) and
|
not exists(Instruction inst | this.getFullyConverted() = inst.getAst()) and
|
||||||
exists(IRGuardCondition ir | this.getOperand() = ir.getAST())
|
exists(IRGuardCondition ir | this.getOperand() = ir.getAst())
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
override predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
||||||
@@ -241,7 +241,7 @@ private class GuardConditionFromIR extends GuardCondition {
|
|||||||
private predicate controlsBlock(BasicBlock controlled, boolean testIsTrue) {
|
private predicate controlsBlock(BasicBlock controlled, boolean testIsTrue) {
|
||||||
exists(IRBlock irb |
|
exists(IRBlock irb |
|
||||||
forex(IRGuardCondition inst | inst = ir | inst.controls(irb, testIsTrue)) and
|
forex(IRGuardCondition inst | inst = ir | inst.controls(irb, testIsTrue)) and
|
||||||
irb.getAnInstruction().getAST().(ControlFlowNode).getBasicBlock() = controlled and
|
irb.getAnInstruction().getAst().(ControlFlowNode).getBasicBlock() = controlled and
|
||||||
not isUnreachedBlock(irb)
|
not isUnreachedBlock(irb)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,393 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Use `StackVariableReachability` instead.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import cpp
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `StackVariableReachability` instead.
|
|
||||||
*
|
|
||||||
* A reachability analysis for control-flow nodes involving stack variables.
|
|
||||||
* This defines sources, sinks, and any other configurable aspect of the
|
|
||||||
* analysis. Multiple analyses can coexist. To create an analysis, extend this
|
|
||||||
* class with a subclass whose characteristic predicate is a unique singleton
|
|
||||||
* string. For example, write
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* class MyAnalysisConfiguration extends LocalScopeVariableReachability {
|
|
||||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
|
||||||
* // Override `isSource` and `isSink`.
|
|
||||||
* // Override `isBarrier`.
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Then, to query whether there is flow between some source and sink, call the
|
|
||||||
* `reaches` predicate on an instance of `MyAnalysisConfiguration`.
|
|
||||||
*/
|
|
||||||
abstract deprecated class LocalScopeVariableReachability extends string {
|
|
||||||
bindingset[this]
|
|
||||||
LocalScopeVariableReachability() { length() >= 0 }
|
|
||||||
|
|
||||||
/** Holds if `node` is a source for the reachability analysis using variable `v`. */
|
|
||||||
abstract predicate isSource(ControlFlowNode node, LocalScopeVariable v);
|
|
||||||
|
|
||||||
/** Holds if `sink` is a (potential) sink for the reachability analysis using variable `v`. */
|
|
||||||
abstract predicate isSink(ControlFlowNode node, LocalScopeVariable v);
|
|
||||||
|
|
||||||
/** Holds if `node` is a barrier for the reachability analysis using variable `v`. */
|
|
||||||
abstract predicate isBarrier(ControlFlowNode node, LocalScopeVariable v);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the source node `source` can reach the sink `sink` without crossing
|
|
||||||
* a barrier. This is (almost) equivalent to the following QL predicate but
|
|
||||||
* uses basic blocks internally for better performance:
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
|
||||||
* reachesImpl(source, v, sink)
|
|
||||||
* and
|
|
||||||
* isSink(sink, v)
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* predicate reachesImpl(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
|
||||||
* sink = source.getASuccessor() and isSource(source, v)
|
|
||||||
* or
|
|
||||||
* exists(ControlFlowNode mid | reachesImpl(source, v, mid) |
|
|
||||||
* not isBarrier(mid, v)
|
|
||||||
* and
|
|
||||||
* sink = mid.getASuccessor()
|
|
||||||
* )
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* In addition to using a better performing implementation, this analysis
|
|
||||||
* accounts for loops where the condition is provably true upon entry.
|
|
||||||
*/
|
|
||||||
predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
|
||||||
/*
|
|
||||||
* Implementation detail: the predicates in this class are a generalization of
|
|
||||||
* those in DefinitionsAndUses.qll, and should be kept in sync.
|
|
||||||
*
|
|
||||||
* Unfortunately, caching of abstract predicates does not work well, so the
|
|
||||||
* predicates in DefinitionsAndUses.qll cannot use this library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exists(BasicBlock bb, int i |
|
|
||||||
this.isSource(source, v) and
|
|
||||||
bb.getNode(i) = source and
|
|
||||||
not bb.isUnreachable()
|
|
||||||
|
|
|
||||||
exists(int j |
|
|
||||||
j > i and
|
|
||||||
sink = bb.getNode(j) and
|
|
||||||
this.isSink(sink, v) and
|
|
||||||
not exists(int k | this.isBarrier(bb.getNode(k), v) | k in [i + 1 .. j - 1])
|
|
||||||
)
|
|
||||||
or
|
|
||||||
not exists(int k | this.isBarrier(bb.getNode(k), v) | k > i) and
|
|
||||||
this.bbSuccessorEntryReaches(bb, v, sink, _)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate bbSuccessorEntryReaches(
|
|
||||||
BasicBlock bb, SemanticStackVariable v, ControlFlowNode node,
|
|
||||||
boolean skipsFirstLoopAlwaysTrueUponEntry
|
|
||||||
) {
|
|
||||||
exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
|
|
||||||
bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
|
|
||||||
succSkipsFirstLoopAlwaysTrueUponEntry)
|
|
||||||
|
|
|
||||||
this.bbEntryReachesLocally(succ, v, node) and
|
|
||||||
succSkipsFirstLoopAlwaysTrueUponEntry = false
|
|
||||||
or
|
|
||||||
not this.isBarrier(succ.getNode(_), v) and
|
|
||||||
this.bbSuccessorEntryReaches(succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate bbEntryReachesLocally(
|
|
||||||
BasicBlock bb, SemanticStackVariable v, ControlFlowNode node
|
|
||||||
) {
|
|
||||||
exists(int n |
|
|
||||||
node = bb.getNode(n) and
|
|
||||||
this.isSink(node, v)
|
|
||||||
|
|
|
||||||
not exists(this.firstBarrierIndexIn(bb, v))
|
|
||||||
or
|
|
||||||
n <= this.firstBarrierIndexIn(bb, v)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private int firstBarrierIndexIn(BasicBlock bb, SemanticStackVariable v) {
|
|
||||||
result = min(int m | this.isBarrier(bb.getNode(m), v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `bb` contains the entry point `loop` for a loop at position `i`.
|
|
||||||
* The condition of that loop is provably true upon entry but not provably
|
|
||||||
* true in general (if it were, the false-successor had already been removed
|
|
||||||
* from the CFG).
|
|
||||||
*
|
|
||||||
* Examples:
|
|
||||||
* ```
|
|
||||||
* for (int i = 0; i < 2; i++) { } // always true upon entry
|
|
||||||
* for (int i = 0; true; i++) { } // always true
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
private predicate bbLoopEntryConditionAlwaysTrueAt(BasicBlock bb, int i, ControlFlowNode loop) {
|
|
||||||
exists(Expr condition |
|
|
||||||
loopConditionAlwaysTrueUponEntry(loop, condition) and
|
|
||||||
not conditionAlwaysTrue(condition) and
|
|
||||||
bb.getNode(i) = loop
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic block `pred` contains all or part of the condition belonging to a loop,
|
|
||||||
* and there is an edge from `pred` to `succ` that concludes the condition.
|
|
||||||
* If the edge corrseponds with the loop condition being found to be `true`, then
|
|
||||||
* `skipsLoop` is `false`. Otherwise the edge corresponds with the loop condition
|
|
||||||
* being found to be `false` and `skipsLoop` is `true`. Non-concluding edges
|
|
||||||
* within a complex loop condition are not matched by this predicate.
|
|
||||||
*/
|
|
||||||
private predicate bbLoopConditionAlwaysTrueUponEntrySuccessor(
|
|
||||||
BasicBlock pred, BasicBlock succ, boolean skipsLoop
|
|
||||||
) {
|
|
||||||
exists(Expr cond |
|
|
||||||
loopConditionAlwaysTrueUponEntry(_, cond) and
|
|
||||||
cond.getAChild*() = pred.getEnd() and
|
|
||||||
succ = pred.getASuccessor() and
|
|
||||||
not cond.getAChild*() = succ.getStart() and
|
|
||||||
(
|
|
||||||
succ = pred.getAFalseSuccessor() and
|
|
||||||
skipsLoop = true
|
|
||||||
or
|
|
||||||
succ = pred.getATrueSuccessor() and
|
|
||||||
skipsLoop = false
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loop invariant for `bbSuccessorEntryReaches`:
|
|
||||||
*
|
|
||||||
* - `succ` is a successor of `pred`.
|
|
||||||
* - `predSkipsFirstLoopAlwaysTrueUponEntry`: whether the path from
|
|
||||||
* `pred` (via `succ`) skips the first loop where the condition is
|
|
||||||
* provably true upon entry.
|
|
||||||
* - `succSkipsFirstLoopAlwaysTrueUponEntry`: whether the path from
|
|
||||||
* `succ` skips the first loop where the condition is provably true
|
|
||||||
* upon entry.
|
|
||||||
* - If `pred` contains the entry point of a loop where the condition
|
|
||||||
* is provably true upon entry, then `succ` is not allowed to skip
|
|
||||||
* that loop (`succSkipsFirstLoopAlwaysTrueUponEntry = false`).
|
|
||||||
*/
|
|
||||||
predicate bbSuccessorEntryReachesLoopInvariant(
|
|
||||||
BasicBlock pred, BasicBlock succ, boolean predSkipsFirstLoopAlwaysTrueUponEntry,
|
|
||||||
boolean succSkipsFirstLoopAlwaysTrueUponEntry
|
|
||||||
) {
|
|
||||||
succ = pred.getASuccessor() and
|
|
||||||
(succSkipsFirstLoopAlwaysTrueUponEntry = true or succSkipsFirstLoopAlwaysTrueUponEntry = false) and
|
|
||||||
(
|
|
||||||
// The edge from `pred` to `succ` is from a loop condition provably
|
|
||||||
// true upon entry, so the value of `predSkipsFirstLoopAlwaysTrueUponEntry`
|
|
||||||
// is determined by whether the true edge or the false edge is chosen,
|
|
||||||
// regardless of the value of `succSkipsFirstLoopAlwaysTrueUponEntry`.
|
|
||||||
bbLoopConditionAlwaysTrueUponEntrySuccessor(pred, succ, predSkipsFirstLoopAlwaysTrueUponEntry)
|
|
||||||
or
|
|
||||||
// The edge from `pred` to `succ` is _not_ from a loop condition provably
|
|
||||||
// true upon entry, so the values of `predSkipsFirstLoopAlwaysTrueUponEntry`
|
|
||||||
// and `succSkipsFirstLoopAlwaysTrueUponEntry` must be the same.
|
|
||||||
not bbLoopConditionAlwaysTrueUponEntrySuccessor(pred, succ, _) and
|
|
||||||
succSkipsFirstLoopAlwaysTrueUponEntry = predSkipsFirstLoopAlwaysTrueUponEntry and
|
|
||||||
// Moreover, if `pred` contains the entry point of a loop where the
|
|
||||||
// condition is provably true upon entry, then `succ` is not allowed
|
|
||||||
// to skip that loop, and hence `succSkipsFirstLoopAlwaysTrueUponEntry = false`.
|
|
||||||
(
|
|
||||||
bbLoopEntryConditionAlwaysTrueAt(pred, _, _)
|
|
||||||
implies
|
|
||||||
succSkipsFirstLoopAlwaysTrueUponEntry = false
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `StackVariableReachabilityWithReassignment` instead.
|
|
||||||
*
|
|
||||||
* Reachability analysis for control-flow nodes involving stack variables.
|
|
||||||
* Unlike `LocalScopeVariableReachability`, this analysis takes variable
|
|
||||||
* reassignments into account.
|
|
||||||
*
|
|
||||||
* This class is used like `LocalScopeVariableReachability`, except that
|
|
||||||
* subclasses should override `isSourceActual` and `isSinkActual` instead of
|
|
||||||
* `isSource` and `isSink`, and that there is a `reachesTo` predicate in
|
|
||||||
* addition to `reaches`.
|
|
||||||
*/
|
|
||||||
abstract deprecated class LocalScopeVariableReachabilityWithReassignment extends LocalScopeVariableReachability {
|
|
||||||
bindingset[this]
|
|
||||||
LocalScopeVariableReachabilityWithReassignment() { length() >= 0 }
|
|
||||||
|
|
||||||
/** Override this predicate rather than `isSource` (`isSource` is used internally). */
|
|
||||||
abstract predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v);
|
|
||||||
|
|
||||||
/** Override this predicate rather than `isSink` (`isSink` is used internally). */
|
|
||||||
abstract predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the source node `source` can reach the sink `sink` without crossing
|
|
||||||
* a barrier, taking reassignments into account. This is (almost) equivalent
|
|
||||||
* to the following QL predicate, but uses basic blocks internally for better
|
|
||||||
* performance:
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
|
||||||
* reachesImpl(source, v, sink)
|
|
||||||
* and
|
|
||||||
* isSinkActual(sink, v)
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* predicate reachesImpl(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
|
||||||
* isSourceActual(source, v)
|
|
||||||
* and
|
|
||||||
* (
|
|
||||||
* sink = source.getASuccessor()
|
|
||||||
* or
|
|
||||||
* exists(ControlFlowNode mid, SemanticStackVariable v0 | reachesImpl(source, v0, mid) |
|
|
||||||
* // ordinary successor
|
|
||||||
* not isBarrier(mid, v) and
|
|
||||||
* sink = mid.getASuccessor() and
|
|
||||||
* v = v0
|
|
||||||
* or
|
|
||||||
* // reassigned from v0 to v
|
|
||||||
* exprDefinition(v, mid, v0.getAnAccess()) and
|
|
||||||
* sink = mid.getASuccessor()
|
|
||||||
* )
|
|
||||||
* )
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* In addition to using a better performing implementation, this analysis
|
|
||||||
* accounts for loops where the condition is provably true upon entry.
|
|
||||||
*/
|
|
||||||
override predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
|
||||||
this.reachesTo(source, v, sink, _)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* As `reaches`, but also specifies the last variable it was reassigned to (`v0`).
|
|
||||||
*/
|
|
||||||
predicate reachesTo(
|
|
||||||
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink, SemanticStackVariable v0
|
|
||||||
) {
|
|
||||||
exists(ControlFlowNode def |
|
|
||||||
this.actualSourceReaches(source, v, def, v0) and
|
|
||||||
LocalScopeVariableReachability.super.reaches(def, v0, sink) and
|
|
||||||
this.isSinkActual(sink, v0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate actualSourceReaches(
|
|
||||||
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0
|
|
||||||
) {
|
|
||||||
this.isSourceActual(source, v) and def = source and v0 = v
|
|
||||||
or
|
|
||||||
exists(ControlFlowNode source1, SemanticStackVariable v1 |
|
|
||||||
this.actualSourceReaches(source, v, source1, v1)
|
|
||||||
|
|
|
||||||
this.reassignment(source1, v1, def, v0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate reassignment(
|
|
||||||
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0
|
|
||||||
) {
|
|
||||||
LocalScopeVariableReachability.super.reaches(source, v, def) and
|
|
||||||
exprDefinition(v0, def, v.getAnAccess())
|
|
||||||
}
|
|
||||||
|
|
||||||
final override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
|
|
||||||
this.isSourceActual(node, v)
|
|
||||||
or
|
|
||||||
// Reassignment generates a new (non-actual) source
|
|
||||||
this.reassignment(_, _, node, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
final override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
|
|
||||||
this.isSinkActual(node, v)
|
|
||||||
or
|
|
||||||
// Reassignment generates a new (non-actual) sink
|
|
||||||
exprDefinition(_, node, v.getAnAccess())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `StackVariableReachabilityExt` instead.
|
|
||||||
*
|
|
||||||
* Same as `LocalScopeVariableReachability`, but `isBarrier` works on control-flow
|
|
||||||
* edges rather than nodes and is therefore parameterized by the original
|
|
||||||
* source node as well. Otherwise, this class is used like
|
|
||||||
* `LocalScopeVariableReachability`.
|
|
||||||
*/
|
|
||||||
abstract deprecated class LocalScopeVariableReachabilityExt extends string {
|
|
||||||
bindingset[this]
|
|
||||||
LocalScopeVariableReachabilityExt() { length() >= 0 }
|
|
||||||
|
|
||||||
/** `node` is a source for the reachability analysis using variable `v`. */
|
|
||||||
abstract predicate isSource(ControlFlowNode node, LocalScopeVariable v);
|
|
||||||
|
|
||||||
/** `sink` is a (potential) sink for the reachability analysis using variable `v`. */
|
|
||||||
abstract predicate isSink(ControlFlowNode node, LocalScopeVariable v);
|
|
||||||
|
|
||||||
/** `node` is a barrier for the reachability analysis using variable `v` and starting from `source`. */
|
|
||||||
abstract predicate isBarrier(
|
|
||||||
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v
|
|
||||||
);
|
|
||||||
|
|
||||||
/** See `LocalScopeVariableReachability.reaches`. */
|
|
||||||
predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
|
||||||
exists(BasicBlock bb, int i |
|
|
||||||
this.isSource(source, v) and
|
|
||||||
bb.getNode(i) = source and
|
|
||||||
not bb.isUnreachable()
|
|
||||||
|
|
|
||||||
exists(int j |
|
|
||||||
j > i and
|
|
||||||
sink = bb.getNode(j) and
|
|
||||||
this.isSink(sink, v) and
|
|
||||||
not exists(int k | this.isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) |
|
|
||||||
k in [i .. j - 1]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
not exists(int k | this.isBarrier(source, bb.getNode(k), bb.getNode(k + 1), v) | k >= i) and
|
|
||||||
this.bbSuccessorEntryReaches(source, bb, v, sink, _)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate bbSuccessorEntryReaches(
|
|
||||||
ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node,
|
|
||||||
boolean skipsFirstLoopAlwaysTrueUponEntry
|
|
||||||
) {
|
|
||||||
exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
|
|
||||||
bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
|
|
||||||
succSkipsFirstLoopAlwaysTrueUponEntry) and
|
|
||||||
not this.isBarrier(source, bb.getEnd(), succ.getStart(), v)
|
|
||||||
|
|
|
||||||
this.bbEntryReachesLocally(source, succ, v, node) and
|
|
||||||
succSkipsFirstLoopAlwaysTrueUponEntry = false
|
|
||||||
or
|
|
||||||
not exists(int k | this.isBarrier(source, succ.getNode(k), succ.getNode(k + 1), v)) and
|
|
||||||
this.bbSuccessorEntryReaches(source, succ, v, node, succSkipsFirstLoopAlwaysTrueUponEntry)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate bbEntryReachesLocally(
|
|
||||||
ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node
|
|
||||||
) {
|
|
||||||
this.isSource(source, v) and
|
|
||||||
exists(int n | node = bb.getNode(n) and this.isSink(node, v) |
|
|
||||||
not exists(int m | m < n | this.isBarrier(source, bb.getNode(m), bb.getNode(m + 1), v))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -156,15 +156,6 @@ class AnalysedExpr extends Expr {
|
|||||||
this.isValidCheck(v) and result = this.getATrueSuccessor()
|
this.isValidCheck(v) and result = this.getATrueSuccessor()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `getNonNullSuccessor` instead, which does the same.
|
|
||||||
*/
|
|
||||||
deprecated ControlFlowNode getValidSuccessor(LocalScopeVariable v) {
|
|
||||||
this.isValidCheck(v) and result = this.getATrueSuccessor()
|
|
||||||
or
|
|
||||||
this.isNullCheck(v) and result = this.getAFalseSuccessor()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this is a `VariableAccess` of `v` nested inside a condition.
|
* Holds if this is a `VariableAccess` of `v` nested inside a condition.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -10,10 +10,13 @@ import SSAUtils
|
|||||||
* The SSA logic comes in two versions: the standard SSA and range-analysis RangeSSA.
|
* The SSA logic comes in two versions: the standard SSA and range-analysis RangeSSA.
|
||||||
* This class provides the standard SSA logic.
|
* This class provides the standard SSA logic.
|
||||||
*/
|
*/
|
||||||
library class StandardSSA extends SSAHelper {
|
library class StandardSsa extends SsaHelper {
|
||||||
StandardSSA() { this = 0 }
|
StandardSsa() { this = 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for StandardSsa */
|
||||||
|
deprecated class StandardSSA = StandardSsa;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A definition of one or more SSA variables, including phi node definitions.
|
* A definition of one or more SSA variables, including phi node definitions.
|
||||||
* An _SSA variable_, as defined in the literature, is effectively the pair of
|
* An _SSA variable_, as defined in the literature, is effectively the pair of
|
||||||
@@ -27,22 +30,22 @@ library class StandardSSA extends SSAHelper {
|
|||||||
* statically seen to be unreachable.
|
* statically seen to be unreachable.
|
||||||
*/
|
*/
|
||||||
class SsaDefinition extends ControlFlowNodeBase {
|
class SsaDefinition extends ControlFlowNodeBase {
|
||||||
SsaDefinition() { exists(StandardSSA x | x.ssa_defn(_, this, _, _)) }
|
SsaDefinition() { exists(StandardSsa x | x.ssa_defn(_, this, _, _)) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a variable corresponding to an SSA StackVariable defined by
|
* Gets a variable corresponding to an SSA StackVariable defined by
|
||||||
* this definition.
|
* this definition.
|
||||||
*/
|
*/
|
||||||
StackVariable getAVariable() { exists(StandardSSA x | x.ssa_defn(result, this, _, _)) }
|
StackVariable getAVariable() { exists(StandardSsa x | x.ssa_defn(result, this, _, _)) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a string representation of the SSA variable represented by the pair
|
* Gets a string representation of the SSA variable represented by the pair
|
||||||
* `(this, v)`.
|
* `(this, v)`.
|
||||||
*/
|
*/
|
||||||
string toString(StackVariable v) { exists(StandardSSA x | result = x.toString(this, v)) }
|
string toString(StackVariable v) { exists(StandardSsa x | result = x.toString(this, v)) }
|
||||||
|
|
||||||
/** Gets a use of the SSA variable represented by the pair `(this, v)`. */
|
/** Gets a use of the SSA variable represented by the pair `(this, v)`. */
|
||||||
VariableAccess getAUse(StackVariable v) { exists(StandardSSA x | result = x.getAUse(this, v)) }
|
VariableAccess getAUse(StackVariable v) { exists(StandardSsa x | result = x.getAUse(this, v)) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the control-flow node for this definition. This will usually be the
|
* Gets the control-flow node for this definition. This will usually be the
|
||||||
@@ -62,7 +65,7 @@ class SsaDefinition extends ControlFlowNodeBase {
|
|||||||
BasicBlock getBasicBlock() { result.contains(this.getDefinition()) }
|
BasicBlock getBasicBlock() { result.contains(this.getDefinition()) }
|
||||||
|
|
||||||
/** Holds if this definition is a phi node for variable `v`. */
|
/** Holds if this definition is a phi node for variable `v`. */
|
||||||
predicate isPhiNode(StackVariable v) { exists(StandardSSA x | x.phi_node(v, this)) }
|
predicate isPhiNode(StackVariable v) { exists(StandardSsa x | x.phi_node(v, this)) }
|
||||||
|
|
||||||
/** Gets the location of this definition. */
|
/** Gets the location of this definition. */
|
||||||
Location getLocation() { result = this.(ControlFlowNode).getLocation() }
|
Location getLocation() { result = this.(ControlFlowNode).getLocation() }
|
||||||
@@ -124,7 +127,7 @@ class SsaDefinition extends ControlFlowNodeBase {
|
|||||||
|
|
||||||
/** Holds if `(this, v)` reaches the end of basic block `b`. */
|
/** Holds if `(this, v)` reaches the end of basic block `b`. */
|
||||||
predicate reachesEndOfBB(StackVariable v, BasicBlock b) {
|
predicate reachesEndOfBB(StackVariable v, BasicBlock b) {
|
||||||
exists(StandardSSA x | x.ssaDefinitionReachesEndOfBB(v, this, b))
|
exists(StandardSsa x | x.ssaDefinitionReachesEndOfBB(v, this, b))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -147,15 +150,4 @@ class SsaDefinition extends ControlFlowNodeBase {
|
|||||||
Expr getAnUltimateDefiningValue(StackVariable v) {
|
Expr getAnUltimateDefiningValue(StackVariable v) {
|
||||||
result = this.getAnUltimateSsaDefinition(v).getDefiningValue(v)
|
result = this.getAnUltimateSsaDefinition(v).getDefiningValue(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: this is the old name for `getAnUltimateDefiningValue`. The
|
|
||||||
* name was confusing as it seemed analogous to `getDefinition` rather than
|
|
||||||
* `getDefiningValue`. The SSA libraries for other languages use the name
|
|
||||||
* `getAnUltimateSsaDefinition` to refer to a predicate named
|
|
||||||
* `getAnUltimateSsaDefinition` in this class.
|
|
||||||
*/
|
|
||||||
deprecated Expr getAnUltimateDefinition(StackVariable v) {
|
|
||||||
result = this.getAnUltimateDefiningValue(v)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,10 +114,10 @@ private predicate live_at_exit_of_bb(StackVariable v, BasicBlock b) {
|
|||||||
|
|
||||||
/** Common SSA logic for standard SSA and range-analysis SSA. */
|
/** Common SSA logic for standard SSA and range-analysis SSA. */
|
||||||
cached
|
cached
|
||||||
library class SSAHelper extends int {
|
library class SsaHelper extends int {
|
||||||
/* 0 = StandardSSA, 1 = RangeSSA */
|
/* 0 = StandardSSA, 1 = RangeSSA */
|
||||||
cached
|
cached
|
||||||
SSAHelper() { this in [0 .. 1] }
|
SsaHelper() { this in [0 .. 1] }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override to insert a custom phi node for variable `v` at the start of
|
* Override to insert a custom phi node for variable `v` at the start of
|
||||||
@@ -311,3 +311,6 @@ library class SSAHelper extends int {
|
|||||||
ssa_use(v, result, _, _)
|
ssa_use(v, result, _, _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for SsaHelper */
|
||||||
|
deprecated class SSAHelper = SsaHelper;
|
||||||
|
|||||||
@@ -447,26 +447,6 @@ private predicate skipInitializer(Initializer init) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `e` is an expression in a static initializer that must be evaluated
|
|
||||||
* at run time. This predicate computes "is non-const" instead of "is const" in
|
|
||||||
* order to avoid recursion through forall.
|
|
||||||
*/
|
|
||||||
private predicate runtimeExprInStaticInitializer(Expr e) {
|
|
||||||
inStaticInitializer(e) and
|
|
||||||
if e instanceof AggregateLiteral
|
|
||||||
then runtimeExprInStaticInitializer(e.getAChild())
|
|
||||||
else not e.getFullyConverted().isConstant()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if `e` is part of the initializer of a local static variable. */
|
|
||||||
private predicate inStaticInitializer(Expr e) {
|
|
||||||
exists(LocalVariable local |
|
|
||||||
local.isStatic() and
|
|
||||||
e.getParent+() = local.getInitializer()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the `i`th child of `n` in control-flow order, where the `i`-indexes are
|
* Gets the `i`th child of `n` in control-flow order, where the `i`-indexes are
|
||||||
* contiguous, and the first index is 0.
|
* contiguous, and the first index is 0.
|
||||||
@@ -1379,7 +1359,7 @@ private module Cached {
|
|||||||
* true-successors and false-successors.
|
* true-successors and false-successors.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
predicate qlCFGSuccessor(Node n1, Node n2) {
|
predicate qlCfgSuccessor(Node n1, Node n2) {
|
||||||
exists(Node memberNode, Pos memberPos |
|
exists(Node memberNode, Pos memberPos |
|
||||||
subEdgeIncludingDestructors(any(Pos at | at.isAt()), n1, memberNode, memberPos) and
|
subEdgeIncludingDestructors(any(Pos at | at.isAt()), n1, memberNode, memberPos) and
|
||||||
normalGroupMember(memberNode, memberPos, n2)
|
normalGroupMember(memberNode, memberPos, n2)
|
||||||
@@ -1388,23 +1368,32 @@ private module Cached {
|
|||||||
conditionalSuccessor(n1, _, n2)
|
conditionalSuccessor(n1, _, n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for qlCfgSuccessor */
|
||||||
|
deprecated predicate qlCFGSuccessor = qlCfgSuccessor/2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `n2` is a control-flow node such that the control-flow
|
* Holds if `n2` is a control-flow node such that the control-flow
|
||||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is true.
|
* edge `(n1, n2)` may be taken when `n1` is an expression that is true.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
predicate qlCFGTrueSuccessor(Node n1, Node n2) {
|
predicate qlCfgTrueSuccessor(Node n1, Node n2) {
|
||||||
conditionalSuccessor(n1, true, n2) and
|
conditionalSuccessor(n1, true, n2) and
|
||||||
not conditionalSuccessor(n1, false, n2)
|
not conditionalSuccessor(n1, false, n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for qlCfgTrueSuccessor */
|
||||||
|
deprecated predicate qlCFGTrueSuccessor = qlCfgTrueSuccessor/2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `n2` is a control-flow node such that the control-flow
|
* Holds if `n2` is a control-flow node such that the control-flow
|
||||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is false.
|
* edge `(n1, n2)` may be taken when `n1` is an expression that is false.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
predicate qlCFGFalseSuccessor(Node n1, Node n2) {
|
predicate qlCfgFalseSuccessor(Node n1, Node n2) {
|
||||||
conditionalSuccessor(n1, false, n2) and
|
conditionalSuccessor(n1, false, n2) and
|
||||||
not conditionalSuccessor(n1, true, n2)
|
not conditionalSuccessor(n1, true, n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for qlCfgFalseSuccessor */
|
||||||
|
deprecated predicate qlCFGFalseSuccessor = qlCfgFalseSuccessor/2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,8 +188,8 @@ private predicate nonAnalyzableFunction(Function f) {
|
|||||||
*/
|
*/
|
||||||
private predicate impossibleFalseEdge(Expr condition, Node succ) {
|
private predicate impossibleFalseEdge(Expr condition, Node succ) {
|
||||||
conditionAlwaysTrue(condition) and
|
conditionAlwaysTrue(condition) and
|
||||||
qlCFGFalseSuccessor(condition, succ) and
|
qlCfgFalseSuccessor(condition, succ) and
|
||||||
not qlCFGTrueSuccessor(condition, succ)
|
not qlCfgTrueSuccessor(condition, succ)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -197,8 +197,8 @@ private predicate impossibleFalseEdge(Expr condition, Node succ) {
|
|||||||
*/
|
*/
|
||||||
private predicate impossibleTrueEdge(Expr condition, Node succ) {
|
private predicate impossibleTrueEdge(Expr condition, Node succ) {
|
||||||
conditionAlwaysFalse(condition) and
|
conditionAlwaysFalse(condition) and
|
||||||
qlCFGTrueSuccessor(condition, succ) and
|
qlCfgTrueSuccessor(condition, succ) and
|
||||||
not qlCFGFalseSuccessor(condition, succ)
|
not qlCfgFalseSuccessor(condition, succ)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -960,9 +960,9 @@ library class ConditionEvaluator extends ExprEvaluator {
|
|||||||
ConditionEvaluator() { this = 0 }
|
ConditionEvaluator() { this = 0 }
|
||||||
|
|
||||||
override predicate interesting(Expr e) {
|
override predicate interesting(Expr e) {
|
||||||
qlCFGFalseSuccessor(e, _)
|
qlCfgFalseSuccessor(e, _)
|
||||||
or
|
or
|
||||||
qlCFGTrueSuccessor(e, _)
|
qlCfgTrueSuccessor(e, _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,10 +20,4 @@ import semmle.code.cpp.dataflow.DataFlow2
|
|||||||
|
|
||||||
module TaintTracking {
|
module TaintTracking {
|
||||||
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl
|
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||||
private import semmle.code.cpp.dataflow.TaintTracking2
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use TaintTracking2::Configuration instead.
|
|
||||||
*/
|
|
||||||
deprecated class Configuration2 = TaintTracking2::Configuration;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,12 +87,30 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow into `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow out of `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||||
|
* the flow state is `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||||
* into account in the analysis.
|
* into account in the analysis.
|
||||||
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierIn(n, state)
|
||||||
|
|
|
||||||
|
config.isSource(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierOut(n, state)
|
||||||
|
|
|
||||||
|
config.isSink(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n | node.asNode() = n |
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierIn(n, state) and
|
||||||
|
not config.isSource(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierOut(n, state) and
|
||||||
|
not config.isSink(n, state)
|
||||||
|
or
|
||||||
|
exists(BarrierGuard g |
|
||||||
|
config.isBarrierGuard(g, state) and
|
||||||
|
n = g.getAGuardedNode()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not outBarrier(node1, config) and
|
not fullOutBarrier(node1, config) and
|
||||||
not inBarrier(node2, config) and
|
not fullInBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
@@ -870,8 +920,8 @@ private module Stage1 {
|
|||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not inBarrier(node, config) and
|
not fullInBarrier(node, config) and
|
||||||
not outBarrier(node, config)
|
not fullOutBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not outBarrier(ret, config) and
|
not fullOutBarrier(ret, config) and
|
||||||
not inBarrier(out, config)
|
not fullInBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not outBarrier(arg, config) and
|
not fullOutBarrier(arg, config) and
|
||||||
not inBarrier(p, config)
|
not fullInBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
|
|||||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||||
* flow steps in a dataflow path.
|
* flow steps in a dataflow path.
|
||||||
*/
|
*/
|
||||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
(
|
(
|
||||||
sourceNode(node, state, config) or
|
sourceNode(node, state, config)
|
||||||
jumpStep(_, node, config) or
|
or
|
||||||
additionalJumpStep(_, node, config) or
|
jumpStep(_, node, config)
|
||||||
additionalJumpStateStep(_, _, node, state, config) or
|
or
|
||||||
node instanceof ParamNodeEx or
|
additionalJumpStep(_, node, config)
|
||||||
node.asNode() instanceof OutNodeExt or
|
or
|
||||||
store(_, _, node, _, config) or
|
additionalJumpStateStep(_, _, node, state, config)
|
||||||
read(_, _, node, config) or
|
or
|
||||||
|
node instanceof ParamNodeEx
|
||||||
|
or
|
||||||
|
node.asNode() instanceof OutNodeExt
|
||||||
|
or
|
||||||
|
store(_, _, node, _, config)
|
||||||
|
or
|
||||||
|
read(_, _, node, config)
|
||||||
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
|
or
|
||||||
|
exists(FlowState s |
|
||||||
|
additionalLocalStateStep(_, s, node, state, config) and
|
||||||
|
s != state
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
additionalJumpStateStep(node, state, next, s, config)
|
additionalJumpStateStep(node, state, next, s, config)
|
||||||
|
or
|
||||||
|
additionalLocalStateStep(node, state, next, s, config) and
|
||||||
|
s != state
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate localFlowStepPlus(
|
private predicate localFlowStepPlus(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||||
DataFlowType t, Configuration config, LocalCallContext cc
|
Configuration config, LocalCallContext cc
|
||||||
) {
|
) {
|
||||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||||
(
|
(
|
||||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||||
(
|
(
|
||||||
localFlowStepNodeCand1(node1, node2, config) and
|
localFlowStepNodeCand1(node1, node2, config) and
|
||||||
state1 = state2 and
|
|
||||||
preservesValue = true and
|
preservesValue = true and
|
||||||
t = node1.getDataFlowType() // irrelevant dummy value
|
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||||
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType()
|
t = node2.getDataFlowType()
|
||||||
) and
|
) and
|
||||||
node1 != node2 and
|
node1 != node2 and
|
||||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||||
pragma[only_bind_into](config), cc) and
|
pragma[only_bind_into](config), cc) and
|
||||||
localFlowStepNodeCand1(mid, node2, config) and
|
localFlowStepNodeCand1(mid, node2, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState st |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType() and
|
t = node2.getDataFlowType()
|
||||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
|
|||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||||
callContext) and
|
localFlowExit(node2, state1, config) and
|
||||||
localFlowExit(node2, state2, config)
|
state1 = state2
|
||||||
|
or
|
||||||
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
|
state1 != state2 and
|
||||||
|
preservesValue = false and
|
||||||
|
apf = TFrontNil(node2.getDataFlowType()) and
|
||||||
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
isUnreachableInCallCached(node2.asNode(), call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2695,10 +2769,10 @@ private module Stage4 {
|
|||||||
|
|
||||||
bindingset[node, cc, config]
|
bindingset[node, cc, config]
|
||||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||||
localFlowEntry(node, _, config) and
|
|
||||||
result =
|
result =
|
||||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||||
node.getEnclosingCallable())
|
node.getEnclosingCallable()) and
|
||||||
|
exists(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate localStep(
|
private predicate localStep(
|
||||||
|
|||||||
@@ -87,12 +87,30 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow into `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow out of `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||||
|
* the flow state is `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||||
* into account in the analysis.
|
* into account in the analysis.
|
||||||
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierIn(n, state)
|
||||||
|
|
|
||||||
|
config.isSource(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierOut(n, state)
|
||||||
|
|
|
||||||
|
config.isSink(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n | node.asNode() = n |
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierIn(n, state) and
|
||||||
|
not config.isSource(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierOut(n, state) and
|
||||||
|
not config.isSink(n, state)
|
||||||
|
or
|
||||||
|
exists(BarrierGuard g |
|
||||||
|
config.isBarrierGuard(g, state) and
|
||||||
|
n = g.getAGuardedNode()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not outBarrier(node1, config) and
|
not fullOutBarrier(node1, config) and
|
||||||
not inBarrier(node2, config) and
|
not fullInBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
@@ -870,8 +920,8 @@ private module Stage1 {
|
|||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not inBarrier(node, config) and
|
not fullInBarrier(node, config) and
|
||||||
not outBarrier(node, config)
|
not fullOutBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not outBarrier(ret, config) and
|
not fullOutBarrier(ret, config) and
|
||||||
not inBarrier(out, config)
|
not fullInBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not outBarrier(arg, config) and
|
not fullOutBarrier(arg, config) and
|
||||||
not inBarrier(p, config)
|
not fullInBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
|
|||||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||||
* flow steps in a dataflow path.
|
* flow steps in a dataflow path.
|
||||||
*/
|
*/
|
||||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
(
|
(
|
||||||
sourceNode(node, state, config) or
|
sourceNode(node, state, config)
|
||||||
jumpStep(_, node, config) or
|
or
|
||||||
additionalJumpStep(_, node, config) or
|
jumpStep(_, node, config)
|
||||||
additionalJumpStateStep(_, _, node, state, config) or
|
or
|
||||||
node instanceof ParamNodeEx or
|
additionalJumpStep(_, node, config)
|
||||||
node.asNode() instanceof OutNodeExt or
|
or
|
||||||
store(_, _, node, _, config) or
|
additionalJumpStateStep(_, _, node, state, config)
|
||||||
read(_, _, node, config) or
|
or
|
||||||
|
node instanceof ParamNodeEx
|
||||||
|
or
|
||||||
|
node.asNode() instanceof OutNodeExt
|
||||||
|
or
|
||||||
|
store(_, _, node, _, config)
|
||||||
|
or
|
||||||
|
read(_, _, node, config)
|
||||||
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
|
or
|
||||||
|
exists(FlowState s |
|
||||||
|
additionalLocalStateStep(_, s, node, state, config) and
|
||||||
|
s != state
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
additionalJumpStateStep(node, state, next, s, config)
|
additionalJumpStateStep(node, state, next, s, config)
|
||||||
|
or
|
||||||
|
additionalLocalStateStep(node, state, next, s, config) and
|
||||||
|
s != state
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate localFlowStepPlus(
|
private predicate localFlowStepPlus(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||||
DataFlowType t, Configuration config, LocalCallContext cc
|
Configuration config, LocalCallContext cc
|
||||||
) {
|
) {
|
||||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||||
(
|
(
|
||||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||||
(
|
(
|
||||||
localFlowStepNodeCand1(node1, node2, config) and
|
localFlowStepNodeCand1(node1, node2, config) and
|
||||||
state1 = state2 and
|
|
||||||
preservesValue = true and
|
preservesValue = true and
|
||||||
t = node1.getDataFlowType() // irrelevant dummy value
|
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||||
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType()
|
t = node2.getDataFlowType()
|
||||||
) and
|
) and
|
||||||
node1 != node2 and
|
node1 != node2 and
|
||||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||||
pragma[only_bind_into](config), cc) and
|
pragma[only_bind_into](config), cc) and
|
||||||
localFlowStepNodeCand1(mid, node2, config) and
|
localFlowStepNodeCand1(mid, node2, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState st |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType() and
|
t = node2.getDataFlowType()
|
||||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
|
|||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||||
callContext) and
|
localFlowExit(node2, state1, config) and
|
||||||
localFlowExit(node2, state2, config)
|
state1 = state2
|
||||||
|
or
|
||||||
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
|
state1 != state2 and
|
||||||
|
preservesValue = false and
|
||||||
|
apf = TFrontNil(node2.getDataFlowType()) and
|
||||||
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
isUnreachableInCallCached(node2.asNode(), call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2695,10 +2769,10 @@ private module Stage4 {
|
|||||||
|
|
||||||
bindingset[node, cc, config]
|
bindingset[node, cc, config]
|
||||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||||
localFlowEntry(node, _, config) and
|
|
||||||
result =
|
result =
|
||||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||||
node.getEnclosingCallable())
|
node.getEnclosingCallable()) and
|
||||||
|
exists(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate localStep(
|
private predicate localStep(
|
||||||
|
|||||||
@@ -87,12 +87,30 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow into `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow out of `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||||
|
* the flow state is `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||||
* into account in the analysis.
|
* into account in the analysis.
|
||||||
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierIn(n, state)
|
||||||
|
|
|
||||||
|
config.isSource(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierOut(n, state)
|
||||||
|
|
|
||||||
|
config.isSink(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n | node.asNode() = n |
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierIn(n, state) and
|
||||||
|
not config.isSource(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierOut(n, state) and
|
||||||
|
not config.isSink(n, state)
|
||||||
|
or
|
||||||
|
exists(BarrierGuard g |
|
||||||
|
config.isBarrierGuard(g, state) and
|
||||||
|
n = g.getAGuardedNode()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not outBarrier(node1, config) and
|
not fullOutBarrier(node1, config) and
|
||||||
not inBarrier(node2, config) and
|
not fullInBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
@@ -870,8 +920,8 @@ private module Stage1 {
|
|||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not inBarrier(node, config) and
|
not fullInBarrier(node, config) and
|
||||||
not outBarrier(node, config)
|
not fullOutBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not outBarrier(ret, config) and
|
not fullOutBarrier(ret, config) and
|
||||||
not inBarrier(out, config)
|
not fullInBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not outBarrier(arg, config) and
|
not fullOutBarrier(arg, config) and
|
||||||
not inBarrier(p, config)
|
not fullInBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
|
|||||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||||
* flow steps in a dataflow path.
|
* flow steps in a dataflow path.
|
||||||
*/
|
*/
|
||||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
(
|
(
|
||||||
sourceNode(node, state, config) or
|
sourceNode(node, state, config)
|
||||||
jumpStep(_, node, config) or
|
or
|
||||||
additionalJumpStep(_, node, config) or
|
jumpStep(_, node, config)
|
||||||
additionalJumpStateStep(_, _, node, state, config) or
|
or
|
||||||
node instanceof ParamNodeEx or
|
additionalJumpStep(_, node, config)
|
||||||
node.asNode() instanceof OutNodeExt or
|
or
|
||||||
store(_, _, node, _, config) or
|
additionalJumpStateStep(_, _, node, state, config)
|
||||||
read(_, _, node, config) or
|
or
|
||||||
|
node instanceof ParamNodeEx
|
||||||
|
or
|
||||||
|
node.asNode() instanceof OutNodeExt
|
||||||
|
or
|
||||||
|
store(_, _, node, _, config)
|
||||||
|
or
|
||||||
|
read(_, _, node, config)
|
||||||
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
|
or
|
||||||
|
exists(FlowState s |
|
||||||
|
additionalLocalStateStep(_, s, node, state, config) and
|
||||||
|
s != state
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
additionalJumpStateStep(node, state, next, s, config)
|
additionalJumpStateStep(node, state, next, s, config)
|
||||||
|
or
|
||||||
|
additionalLocalStateStep(node, state, next, s, config) and
|
||||||
|
s != state
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate localFlowStepPlus(
|
private predicate localFlowStepPlus(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||||
DataFlowType t, Configuration config, LocalCallContext cc
|
Configuration config, LocalCallContext cc
|
||||||
) {
|
) {
|
||||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||||
(
|
(
|
||||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||||
(
|
(
|
||||||
localFlowStepNodeCand1(node1, node2, config) and
|
localFlowStepNodeCand1(node1, node2, config) and
|
||||||
state1 = state2 and
|
|
||||||
preservesValue = true and
|
preservesValue = true and
|
||||||
t = node1.getDataFlowType() // irrelevant dummy value
|
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||||
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType()
|
t = node2.getDataFlowType()
|
||||||
) and
|
) and
|
||||||
node1 != node2 and
|
node1 != node2 and
|
||||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||||
pragma[only_bind_into](config), cc) and
|
pragma[only_bind_into](config), cc) and
|
||||||
localFlowStepNodeCand1(mid, node2, config) and
|
localFlowStepNodeCand1(mid, node2, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState st |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType() and
|
t = node2.getDataFlowType()
|
||||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
|
|||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||||
callContext) and
|
localFlowExit(node2, state1, config) and
|
||||||
localFlowExit(node2, state2, config)
|
state1 = state2
|
||||||
|
or
|
||||||
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
|
state1 != state2 and
|
||||||
|
preservesValue = false and
|
||||||
|
apf = TFrontNil(node2.getDataFlowType()) and
|
||||||
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
isUnreachableInCallCached(node2.asNode(), call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2695,10 +2769,10 @@ private module Stage4 {
|
|||||||
|
|
||||||
bindingset[node, cc, config]
|
bindingset[node, cc, config]
|
||||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||||
localFlowEntry(node, _, config) and
|
|
||||||
result =
|
result =
|
||||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||||
node.getEnclosingCallable())
|
node.getEnclosingCallable()) and
|
||||||
|
exists(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate localStep(
|
private predicate localStep(
|
||||||
|
|||||||
@@ -87,12 +87,30 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow into `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow out of `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||||
|
* the flow state is `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||||
* into account in the analysis.
|
* into account in the analysis.
|
||||||
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierIn(n, state)
|
||||||
|
|
|
||||||
|
config.isSource(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierOut(n, state)
|
||||||
|
|
|
||||||
|
config.isSink(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n | node.asNode() = n |
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierIn(n, state) and
|
||||||
|
not config.isSource(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierOut(n, state) and
|
||||||
|
not config.isSink(n, state)
|
||||||
|
or
|
||||||
|
exists(BarrierGuard g |
|
||||||
|
config.isBarrierGuard(g, state) and
|
||||||
|
n = g.getAGuardedNode()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not outBarrier(node1, config) and
|
not fullOutBarrier(node1, config) and
|
||||||
not inBarrier(node2, config) and
|
not fullInBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
@@ -870,8 +920,8 @@ private module Stage1 {
|
|||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not inBarrier(node, config) and
|
not fullInBarrier(node, config) and
|
||||||
not outBarrier(node, config)
|
not fullOutBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not outBarrier(ret, config) and
|
not fullOutBarrier(ret, config) and
|
||||||
not inBarrier(out, config)
|
not fullInBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not outBarrier(arg, config) and
|
not fullOutBarrier(arg, config) and
|
||||||
not inBarrier(p, config)
|
not fullInBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
|
|||||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||||
* flow steps in a dataflow path.
|
* flow steps in a dataflow path.
|
||||||
*/
|
*/
|
||||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
(
|
(
|
||||||
sourceNode(node, state, config) or
|
sourceNode(node, state, config)
|
||||||
jumpStep(_, node, config) or
|
or
|
||||||
additionalJumpStep(_, node, config) or
|
jumpStep(_, node, config)
|
||||||
additionalJumpStateStep(_, _, node, state, config) or
|
or
|
||||||
node instanceof ParamNodeEx or
|
additionalJumpStep(_, node, config)
|
||||||
node.asNode() instanceof OutNodeExt or
|
or
|
||||||
store(_, _, node, _, config) or
|
additionalJumpStateStep(_, _, node, state, config)
|
||||||
read(_, _, node, config) or
|
or
|
||||||
|
node instanceof ParamNodeEx
|
||||||
|
or
|
||||||
|
node.asNode() instanceof OutNodeExt
|
||||||
|
or
|
||||||
|
store(_, _, node, _, config)
|
||||||
|
or
|
||||||
|
read(_, _, node, config)
|
||||||
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
|
or
|
||||||
|
exists(FlowState s |
|
||||||
|
additionalLocalStateStep(_, s, node, state, config) and
|
||||||
|
s != state
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
additionalJumpStateStep(node, state, next, s, config)
|
additionalJumpStateStep(node, state, next, s, config)
|
||||||
|
or
|
||||||
|
additionalLocalStateStep(node, state, next, s, config) and
|
||||||
|
s != state
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate localFlowStepPlus(
|
private predicate localFlowStepPlus(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||||
DataFlowType t, Configuration config, LocalCallContext cc
|
Configuration config, LocalCallContext cc
|
||||||
) {
|
) {
|
||||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||||
(
|
(
|
||||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||||
(
|
(
|
||||||
localFlowStepNodeCand1(node1, node2, config) and
|
localFlowStepNodeCand1(node1, node2, config) and
|
||||||
state1 = state2 and
|
|
||||||
preservesValue = true and
|
preservesValue = true and
|
||||||
t = node1.getDataFlowType() // irrelevant dummy value
|
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||||
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType()
|
t = node2.getDataFlowType()
|
||||||
) and
|
) and
|
||||||
node1 != node2 and
|
node1 != node2 and
|
||||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||||
pragma[only_bind_into](config), cc) and
|
pragma[only_bind_into](config), cc) and
|
||||||
localFlowStepNodeCand1(mid, node2, config) and
|
localFlowStepNodeCand1(mid, node2, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState st |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType() and
|
t = node2.getDataFlowType()
|
||||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
|
|||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||||
callContext) and
|
localFlowExit(node2, state1, config) and
|
||||||
localFlowExit(node2, state2, config)
|
state1 = state2
|
||||||
|
or
|
||||||
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
|
state1 != state2 and
|
||||||
|
preservesValue = false and
|
||||||
|
apf = TFrontNil(node2.getDataFlowType()) and
|
||||||
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
isUnreachableInCallCached(node2.asNode(), call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2695,10 +2769,10 @@ private module Stage4 {
|
|||||||
|
|
||||||
bindingset[node, cc, config]
|
bindingset[node, cc, config]
|
||||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||||
localFlowEntry(node, _, config) and
|
|
||||||
result =
|
result =
|
||||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||||
node.getEnclosingCallable())
|
node.getEnclosingCallable()) and
|
||||||
|
exists(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate localStep(
|
private predicate localStep(
|
||||||
|
|||||||
@@ -87,12 +87,30 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow into `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow out of `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||||
|
* the flow state is `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||||
* into account in the analysis.
|
* into account in the analysis.
|
||||||
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierIn(n, state)
|
||||||
|
|
|
||||||
|
config.isSource(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierOut(n, state)
|
||||||
|
|
|
||||||
|
config.isSink(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n | node.asNode() = n |
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierIn(n, state) and
|
||||||
|
not config.isSource(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierOut(n, state) and
|
||||||
|
not config.isSink(n, state)
|
||||||
|
or
|
||||||
|
exists(BarrierGuard g |
|
||||||
|
config.isBarrierGuard(g, state) and
|
||||||
|
n = g.getAGuardedNode()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not outBarrier(node1, config) and
|
not fullOutBarrier(node1, config) and
|
||||||
not inBarrier(node2, config) and
|
not fullInBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
@@ -870,8 +920,8 @@ private module Stage1 {
|
|||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not inBarrier(node, config) and
|
not fullInBarrier(node, config) and
|
||||||
not outBarrier(node, config)
|
not fullOutBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not outBarrier(ret, config) and
|
not fullOutBarrier(ret, config) and
|
||||||
not inBarrier(out, config)
|
not fullInBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not outBarrier(arg, config) and
|
not fullOutBarrier(arg, config) and
|
||||||
not inBarrier(p, config)
|
not fullInBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
|
|||||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||||
* flow steps in a dataflow path.
|
* flow steps in a dataflow path.
|
||||||
*/
|
*/
|
||||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
(
|
(
|
||||||
sourceNode(node, state, config) or
|
sourceNode(node, state, config)
|
||||||
jumpStep(_, node, config) or
|
or
|
||||||
additionalJumpStep(_, node, config) or
|
jumpStep(_, node, config)
|
||||||
additionalJumpStateStep(_, _, node, state, config) or
|
or
|
||||||
node instanceof ParamNodeEx or
|
additionalJumpStep(_, node, config)
|
||||||
node.asNode() instanceof OutNodeExt or
|
or
|
||||||
store(_, _, node, _, config) or
|
additionalJumpStateStep(_, _, node, state, config)
|
||||||
read(_, _, node, config) or
|
or
|
||||||
|
node instanceof ParamNodeEx
|
||||||
|
or
|
||||||
|
node.asNode() instanceof OutNodeExt
|
||||||
|
or
|
||||||
|
store(_, _, node, _, config)
|
||||||
|
or
|
||||||
|
read(_, _, node, config)
|
||||||
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
|
or
|
||||||
|
exists(FlowState s |
|
||||||
|
additionalLocalStateStep(_, s, node, state, config) and
|
||||||
|
s != state
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
additionalJumpStateStep(node, state, next, s, config)
|
additionalJumpStateStep(node, state, next, s, config)
|
||||||
|
or
|
||||||
|
additionalLocalStateStep(node, state, next, s, config) and
|
||||||
|
s != state
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate localFlowStepPlus(
|
private predicate localFlowStepPlus(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||||
DataFlowType t, Configuration config, LocalCallContext cc
|
Configuration config, LocalCallContext cc
|
||||||
) {
|
) {
|
||||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||||
(
|
(
|
||||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||||
(
|
(
|
||||||
localFlowStepNodeCand1(node1, node2, config) and
|
localFlowStepNodeCand1(node1, node2, config) and
|
||||||
state1 = state2 and
|
|
||||||
preservesValue = true and
|
preservesValue = true and
|
||||||
t = node1.getDataFlowType() // irrelevant dummy value
|
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||||
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType()
|
t = node2.getDataFlowType()
|
||||||
) and
|
) and
|
||||||
node1 != node2 and
|
node1 != node2 and
|
||||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||||
pragma[only_bind_into](config), cc) and
|
pragma[only_bind_into](config), cc) and
|
||||||
localFlowStepNodeCand1(mid, node2, config) and
|
localFlowStepNodeCand1(mid, node2, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState st |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType() and
|
t = node2.getDataFlowType()
|
||||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
|
|||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||||
callContext) and
|
localFlowExit(node2, state1, config) and
|
||||||
localFlowExit(node2, state2, config)
|
state1 = state2
|
||||||
|
or
|
||||||
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
|
state1 != state2 and
|
||||||
|
preservesValue = false and
|
||||||
|
apf = TFrontNil(node2.getDataFlowType()) and
|
||||||
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
isUnreachableInCallCached(node2.asNode(), call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2695,10 +2769,10 @@ private module Stage4 {
|
|||||||
|
|
||||||
bindingset[node, cc, config]
|
bindingset[node, cc, config]
|
||||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||||
localFlowEntry(node, _, config) and
|
|
||||||
result =
|
result =
|
||||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||||
node.getEnclosingCallable())
|
node.getEnclosingCallable()) and
|
||||||
|
exists(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate localStep(
|
private predicate localStep(
|
||||||
|
|||||||
@@ -113,10 +113,6 @@ private module PartialDefinitions {
|
|||||||
abstract class PartialDefinition extends Expr {
|
abstract class PartialDefinition extends Expr {
|
||||||
ControlFlowNode node;
|
ControlFlowNode node;
|
||||||
|
|
||||||
abstract deprecated predicate partiallyDefines(Variable v);
|
|
||||||
|
|
||||||
abstract deprecated predicate partiallyDefinesThis(ThisExpr e);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the subBasicBlock where this `PartialDefinition` is defined.
|
* Gets the subBasicBlock where this `PartialDefinition` is defined.
|
||||||
*/
|
*/
|
||||||
@@ -189,10 +185,6 @@ private module PartialDefinitions {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
deprecated override predicate partiallyDefines(Variable v) { v = collection }
|
|
||||||
|
|
||||||
deprecated override predicate partiallyDefinesThis(ThisExpr e) { none() }
|
|
||||||
|
|
||||||
override predicate definesExpressions(Expr inner, Expr outer) {
|
override predicate definesExpressions(Expr inner, Expr outer) {
|
||||||
inner = innerDefinedExpr and
|
inner = innerDefinedExpr and
|
||||||
outer = this
|
outer = this
|
||||||
@@ -217,12 +209,6 @@ private module PartialDefinitions {
|
|||||||
|
|
||||||
VariablePartialDefinition() { innerDefinedExpr = getInnerDefinedExpr(this, node) }
|
VariablePartialDefinition() { innerDefinedExpr = getInnerDefinedExpr(this, node) }
|
||||||
|
|
||||||
deprecated override predicate partiallyDefines(Variable v) {
|
|
||||||
innerDefinedExpr = v.getAnAccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated override predicate partiallyDefinesThis(ThisExpr e) { innerDefinedExpr = e }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this partial definition may modify `inner` (or what it points
|
* Holds if this partial definition may modify `inner` (or what it points
|
||||||
* to) through `outer`. These expressions will never be `Conversion`s.
|
* to) through `outer`. These expressions will never be `Conversion`s.
|
||||||
|
|||||||
@@ -64,13 +64,30 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
override predicate isSource(DataFlow::Node source) { none() }
|
override predicate isSource(DataFlow::Node source) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `sink` is a relevant taint sink.
|
* Holds if `source` is a relevant taint source with the given initial
|
||||||
|
* `state`.
|
||||||
|
*
|
||||||
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
|
*/
|
||||||
|
// overridden to provide taint-tracking specific qldoc
|
||||||
|
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `sink` is a relevant taint sink
|
||||||
*
|
*
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
*/
|
*/
|
||||||
// overridden to provide taint-tracking specific qldoc
|
// overridden to provide taint-tracking specific qldoc
|
||||||
override predicate isSink(DataFlow::Node sink) { none() }
|
override predicate isSink(DataFlow::Node sink) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `sink` is a relevant taint sink accepting `state`.
|
||||||
|
*
|
||||||
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
|
*/
|
||||||
|
// overridden to provide taint-tracking specific qldoc
|
||||||
|
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if the node `node` is a taint sanitizer. */
|
/** Holds if the node `node` is a taint sanitizer. */
|
||||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
@@ -79,9 +96,29 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
defaultTaintSanitizer(node)
|
defaultTaintSanitizer(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the node `node` is a taint sanitizer when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizer(node, state)
|
||||||
|
}
|
||||||
|
|
||||||
/** Holds if taint propagation into `node` is prohibited. */
|
/** Holds if taint propagation into `node` is prohibited. */
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint propagation into `node` is prohibited when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizerIn(node, state)
|
||||||
|
}
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
/** Holds if taint propagation out of `node` is prohibited. */
|
||||||
@@ -89,6 +126,16 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint propagation out of `node` is prohibited when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizerOut(node, state)
|
||||||
|
}
|
||||||
|
|
||||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -96,6 +143,16 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||||
|
* when the flow state is `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizerGuard(guard, state)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||||
* must be taken into account in the analysis.
|
* must be taken into account in the analysis.
|
||||||
@@ -107,6 +164,25 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
defaultAdditionalTaintStep(node1, node2)
|
defaultAdditionalTaintStep(node1, node2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||||
|
* must be taken into account in the analysis. This step is only applicable
|
||||||
|
* in `state1` and updates the flow state to `state2`.
|
||||||
|
*/
|
||||||
|
predicate isAdditionalTaintStep(
|
||||||
|
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||||
|
DataFlow::FlowState state2
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
final override predicate isAdditionalFlowStep(
|
||||||
|
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||||
|
DataFlow::FlowState state2
|
||||||
|
) {
|
||||||
|
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||||
|
}
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||||
defaultImplicitTaintRead(node, c)
|
defaultImplicitTaintRead(node, c)
|
||||||
|
|||||||
@@ -64,13 +64,30 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
override predicate isSource(DataFlow::Node source) { none() }
|
override predicate isSource(DataFlow::Node source) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `sink` is a relevant taint sink.
|
* Holds if `source` is a relevant taint source with the given initial
|
||||||
|
* `state`.
|
||||||
|
*
|
||||||
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
|
*/
|
||||||
|
// overridden to provide taint-tracking specific qldoc
|
||||||
|
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `sink` is a relevant taint sink
|
||||||
*
|
*
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
*/
|
*/
|
||||||
// overridden to provide taint-tracking specific qldoc
|
// overridden to provide taint-tracking specific qldoc
|
||||||
override predicate isSink(DataFlow::Node sink) { none() }
|
override predicate isSink(DataFlow::Node sink) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `sink` is a relevant taint sink accepting `state`.
|
||||||
|
*
|
||||||
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
|
*/
|
||||||
|
// overridden to provide taint-tracking specific qldoc
|
||||||
|
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if the node `node` is a taint sanitizer. */
|
/** Holds if the node `node` is a taint sanitizer. */
|
||||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
@@ -79,9 +96,29 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
defaultTaintSanitizer(node)
|
defaultTaintSanitizer(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the node `node` is a taint sanitizer when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizer(node, state)
|
||||||
|
}
|
||||||
|
|
||||||
/** Holds if taint propagation into `node` is prohibited. */
|
/** Holds if taint propagation into `node` is prohibited. */
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint propagation into `node` is prohibited when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizerIn(node, state)
|
||||||
|
}
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
/** Holds if taint propagation out of `node` is prohibited. */
|
||||||
@@ -89,6 +126,16 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint propagation out of `node` is prohibited when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizerOut(node, state)
|
||||||
|
}
|
||||||
|
|
||||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -96,6 +143,16 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||||
|
* when the flow state is `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizerGuard(guard, state)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||||
* must be taken into account in the analysis.
|
* must be taken into account in the analysis.
|
||||||
@@ -107,6 +164,25 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
defaultAdditionalTaintStep(node1, node2)
|
defaultAdditionalTaintStep(node1, node2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||||
|
* must be taken into account in the analysis. This step is only applicable
|
||||||
|
* in `state1` and updates the flow state to `state2`.
|
||||||
|
*/
|
||||||
|
predicate isAdditionalTaintStep(
|
||||||
|
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||||
|
DataFlow::FlowState state2
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
final override predicate isAdditionalFlowStep(
|
||||||
|
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||||
|
DataFlow::FlowState state2
|
||||||
|
) {
|
||||||
|
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||||
|
}
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||||
defaultImplicitTaintRead(node, c)
|
defaultImplicitTaintRead(node, c)
|
||||||
|
|||||||
@@ -226,13 +226,6 @@ class AssignPointerSubExpr extends AssignOperation, @assignpsubexpr {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class ConditionDeclExpr extends Expr, @condition_decl {
|
class ConditionDeclExpr extends Expr, @condition_decl {
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `getVariableAccess()` or `getInitializingExpr()` instead.
|
|
||||||
*
|
|
||||||
* Gets the access using the condition for this declaration.
|
|
||||||
*/
|
|
||||||
deprecated Expr getExpr() { result = this.getChild(0) }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "ConditionDeclExpr" }
|
override string getAPrimaryQlClass() { result = "ConditionDeclExpr" }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -118,11 +118,6 @@ class BuiltInNoOp extends BuiltInOperation, @noopexpr {
|
|||||||
override string getAPrimaryQlClass() { result = "BuiltInNoOp" }
|
override string getAPrimaryQlClass() { result = "BuiltInNoOp" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `BuiltInOperationBuiltInOffsetOf` instead.
|
|
||||||
*/
|
|
||||||
deprecated class BuiltInOperationOffsetOf = BuiltInOperationBuiltInOffsetOf;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A C/C++ `__builtin_offsetof` built-in operation (used by some implementations
|
* A C/C++ `__builtin_offsetof` built-in operation (used by some implementations
|
||||||
* of `offsetof`). The operation retains its semantics even in the presence
|
* of `offsetof`). The operation retains its semantics even in the presence
|
||||||
@@ -465,11 +460,6 @@ class BuiltInOperationIsUnion extends BuiltInOperation, @isunionexpr {
|
|||||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsUnion" }
|
override string getAPrimaryQlClass() { result = "BuiltInOperationIsUnion" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `BuiltInOperationBuiltInTypesCompatibleP` instead.
|
|
||||||
*/
|
|
||||||
deprecated class BuiltInOperationBuiltInTypes = BuiltInOperationBuiltInTypesCompatibleP;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A C++ `__builtin_types_compatible_p` built-in operation (used by some
|
* A C++ `__builtin_types_compatible_p` built-in operation (used by some
|
||||||
* implementations of the `<type_traits>` header).
|
* implementations of the `<type_traits>` header).
|
||||||
|
|||||||
@@ -666,13 +666,6 @@ class TypeidOperator extends Expr, @type_id {
|
|||||||
*/
|
*/
|
||||||
Type getResultType() { typeid_bind(underlyingElement(this), unresolveElement(result)) }
|
Type getResultType() { typeid_bind(underlyingElement(this), unresolveElement(result)) }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `getResultType()` instead.
|
|
||||||
*
|
|
||||||
* Gets the type that is returned by this typeid expression.
|
|
||||||
*/
|
|
||||||
deprecated Type getSpecifiedType() { result = this.getResultType() }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "TypeidOperator" }
|
override string getAPrimaryQlClass() { result = "TypeidOperator" }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -731,13 +724,6 @@ class SizeofExprOperator extends SizeofOperator {
|
|||||||
/** Gets the contained expression. */
|
/** Gets the contained expression. */
|
||||||
Expr getExprOperand() { result = this.getChild(0) }
|
Expr getExprOperand() { result = this.getChild(0) }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `getExprOperand()` instead
|
|
||||||
*
|
|
||||||
* Gets the contained expression.
|
|
||||||
*/
|
|
||||||
deprecated Expr getExpr() { result = this.getExprOperand() }
|
|
||||||
|
|
||||||
override string toString() { result = "sizeof(<expr>)" }
|
override string toString() { result = "sizeof(<expr>)" }
|
||||||
|
|
||||||
override predicate mayBeImpure() { this.getExprOperand().mayBeImpure() }
|
override predicate mayBeImpure() { this.getExprOperand().mayBeImpure() }
|
||||||
@@ -759,13 +745,6 @@ class SizeofTypeOperator extends SizeofOperator {
|
|||||||
/** Gets the contained type. */
|
/** Gets the contained type. */
|
||||||
Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `getTypeOperand()` instead
|
|
||||||
*
|
|
||||||
* Gets the contained type.
|
|
||||||
*/
|
|
||||||
deprecated Type getSpecifiedType() { result = this.getTypeOperand() }
|
|
||||||
|
|
||||||
override string toString() { result = "sizeof(" + this.getTypeOperand().getName() + ")" }
|
override string toString() { result = "sizeof(" + this.getTypeOperand().getName() + ")" }
|
||||||
|
|
||||||
override predicate mayBeImpure() { none() }
|
override predicate mayBeImpure() { none() }
|
||||||
@@ -794,11 +773,6 @@ class AlignofExprOperator extends AlignofOperator {
|
|||||||
*/
|
*/
|
||||||
Expr getExprOperand() { result = this.getChild(0) }
|
Expr getExprOperand() { result = this.getChild(0) }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `getExprOperand()` instead.
|
|
||||||
*/
|
|
||||||
deprecated Expr getExpr() { result = this.getExprOperand() }
|
|
||||||
|
|
||||||
override string toString() { result = "alignof(<expr>)" }
|
override string toString() { result = "alignof(<expr>)" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,11 +788,6 @@ class AlignofTypeOperator extends AlignofOperator {
|
|||||||
/** Gets the contained type. */
|
/** Gets the contained type. */
|
||||||
Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `getTypeOperand()` instead.
|
|
||||||
*/
|
|
||||||
deprecated Type getSpecifiedType() { result = this.getTypeOperand() }
|
|
||||||
|
|
||||||
override string toString() { result = "alignof(" + this.getTypeOperand().getName() + ")" }
|
override string toString() { result = "alignof(" + this.getTypeOperand().getName() + ")" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,16 +48,6 @@ class NEExpr extends EqualityOperation, @neexpr {
|
|||||||
class RelationalOperation extends ComparisonOperation, @rel_op_expr {
|
class RelationalOperation extends ComparisonOperation, @rel_op_expr {
|
||||||
override int getPrecedence() { result = 10 }
|
override int getPrecedence() { result = 10 }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `getGreaterOperand()` instead.
|
|
||||||
*/
|
|
||||||
deprecated Expr getLarge() { result = getGreaterOperand() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `getLesserOperand()` instead.
|
|
||||||
*/
|
|
||||||
deprecated Expr getSmall() { result = getLesserOperand() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the operand on the "greater" (or "greater-or-equal") side
|
* Gets the operand on the "greater" (or "greater-or-equal") side
|
||||||
* of this relational expression, that is, the side that is larger
|
* of this relational expression, that is, the side that is larger
|
||||||
|
|||||||
@@ -114,13 +114,6 @@ class Expr extends StmtParent, @expr {
|
|||||||
*/
|
*/
|
||||||
Type getUnspecifiedType() { result = this.getType().getUnspecifiedType() }
|
Type getUnspecifiedType() { result = this.getType().getUnspecifiedType() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an integer indicating the type of expression that this represents.
|
|
||||||
*
|
|
||||||
* DEPRECATED: use the subclasses of `Expr` rather than relying on this predicate.
|
|
||||||
*/
|
|
||||||
deprecated int getKind() { exprs(underlyingElement(this), result, _) }
|
|
||||||
|
|
||||||
/** Gets a textual representation of this expression. */
|
/** Gets a textual representation of this expression. */
|
||||||
override string toString() { none() }
|
override string toString() { none() }
|
||||||
|
|
||||||
|
|||||||
@@ -164,16 +164,6 @@ class HexLiteral extends Literal {
|
|||||||
class AggregateLiteral extends Expr, @aggregateliteral {
|
class AggregateLiteral extends Expr, @aggregateliteral {
|
||||||
override string getAPrimaryQlClass() { result = "AggregateLiteral" }
|
override string getAPrimaryQlClass() { result = "AggregateLiteral" }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use ClassAggregateLiteral.getFieldExpr() instead.
|
|
||||||
*
|
|
||||||
* Gets the expression within the aggregate literal that is used to initialise field `f`,
|
|
||||||
* if this literal is being used to initialise a class/struct instance.
|
|
||||||
*/
|
|
||||||
deprecated Expr getCorrespondingExpr(Field f) {
|
|
||||||
result = this.(ClassAggregateLiteral).getFieldExpr(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate mayBeImpure() { this.getAChild().mayBeImpure() }
|
override predicate mayBeImpure() { this.getAChild().mayBeImpure() }
|
||||||
|
|
||||||
override predicate mayBeGloballyImpure() { this.getAChild().mayBeGloballyImpure() }
|
override predicate mayBeGloballyImpure() { this.getAChild().mayBeGloballyImpure() }
|
||||||
|
|||||||
@@ -1,297 +0,0 @@
|
|||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import semmle.code.cpp.exprs.Expr
|
|
||||||
import semmle.code.cpp.Class
|
|
||||||
import semmle.code.cpp.ObjectiveC
|
|
||||||
private import semmle.code.cpp.internal.ResolveClass
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C message expression, for example `[myColor changeColorToRed:5.0 green:2.0 blue:6.0]`.
|
|
||||||
*/
|
|
||||||
deprecated class MessageExpr extends Expr, Call {
|
|
||||||
MessageExpr() { none() }
|
|
||||||
|
|
||||||
override string toString() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the selector of this message expression, for example `-changeColorToRed:green:blue:`.
|
|
||||||
*/
|
|
||||||
string getSelector() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the function invoked by this message expression, as inferred by the compiler.
|
|
||||||
*
|
|
||||||
* If the compiler could infer the type of the receiver, and that type had a method
|
|
||||||
* whose name matched the selector, then the result of this predicate is said method.
|
|
||||||
* Otherwise this predicate has no result.
|
|
||||||
*
|
|
||||||
* In all cases, actual function dispatch isn't performed until runtime, but the
|
|
||||||
* lack of a static target is often cause for concern.
|
|
||||||
*/
|
|
||||||
MemberFunction getStaticTarget() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provided for compatibility with Call. It is the same as the static target.
|
|
||||||
*/
|
|
||||||
override MemberFunction getTarget() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the compiler could infer a function as the target of this message.
|
|
||||||
*
|
|
||||||
* In all cases, actual function dispatch isn't performed until runtime, but the
|
|
||||||
* lack of a static target is often cause for concern.
|
|
||||||
*/
|
|
||||||
predicate hasStaticTarget() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the number of arguments passed by this message expression.
|
|
||||||
*
|
|
||||||
* In most cases, this equals the number of colons in the selector, but this needn't be the
|
|
||||||
* case for variadic methods like "-initWithFormat:", which can have more than one argument.
|
|
||||||
*/
|
|
||||||
override int getNumberOfArguments() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an argument passed by this message expression.
|
|
||||||
*/
|
|
||||||
override Expr getAnArgument() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the nth argument passed by this message expression.
|
|
||||||
*
|
|
||||||
* The range of `n` is [`0` .. `getNumberOfArguments()`].
|
|
||||||
*/
|
|
||||||
override Expr getArgument(int n) { none() }
|
|
||||||
|
|
||||||
override int getPrecedence() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C message expression whose receiver is `super`, for example `[super init]`.
|
|
||||||
*/
|
|
||||||
deprecated class SuperMessageExpr extends MessageExpr {
|
|
||||||
SuperMessageExpr() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C message expression whose receiver is the name of a class, and
|
|
||||||
* is therefore calling a class method rather than an instance method. This occurs
|
|
||||||
* most commonly for the "+alloc", "+new", and "+class" selectors.
|
|
||||||
*/
|
|
||||||
deprecated class ClassMessageExpr extends MessageExpr {
|
|
||||||
ClassMessageExpr() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the class which is the receiver of this message.
|
|
||||||
*/
|
|
||||||
Type getReceiver() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C message expression whose receiver is an expression (which includes the
|
|
||||||
* common case of the receiver being "self").
|
|
||||||
*/
|
|
||||||
deprecated class ExprMessageExpr extends MessageExpr {
|
|
||||||
ExprMessageExpr() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the expression which gives the receiver of this message.
|
|
||||||
*/
|
|
||||||
Expr getReceiver() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the Objective C class of which the receiving expression is an instance.
|
|
||||||
*
|
|
||||||
* If the receiving expression has type `id` or type `id<P>` for some protocol `P`,
|
|
||||||
* then there will be no result. If the receiving expression has type `C*` or type
|
|
||||||
* `C<P>*` for some protocol `P`, then the result will be the type `C`.
|
|
||||||
*/
|
|
||||||
ObjectiveClass getReceiverClass() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the Objective C classes and/or protocols which are statically implemented
|
|
||||||
* by the receiving expression.
|
|
||||||
*
|
|
||||||
* If the receiving expression has type `id`, then there will be no result.
|
|
||||||
* If the receiving expression has type `id<P>`, then `P` will be the sole result.
|
|
||||||
* If the receiving expression has type `C*`, then `C` will be the sole result.
|
|
||||||
* If the receiving expression has type `C<P>*`, then `C` and `P` will both be results.
|
|
||||||
*/
|
|
||||||
Class getAReceiverClassOrProtocol() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An access to an Objective C property using dot syntax.
|
|
||||||
*
|
|
||||||
* Such accesses are de-sugared into a message expression to the property's getter or setter.
|
|
||||||
*/
|
|
||||||
deprecated class PropertyAccess extends ExprMessageExpr {
|
|
||||||
PropertyAccess() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the property being accessed by this expression.
|
|
||||||
*/
|
|
||||||
Property getProperty() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C `@selector` expression, for example `@selector(driveForDistance:)`.
|
|
||||||
*/
|
|
||||||
deprecated class AtSelectorExpr extends Expr {
|
|
||||||
AtSelectorExpr() { none() }
|
|
||||||
|
|
||||||
override string toString() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the selector of this `@selector` expression, for example `driveForDistance:`.
|
|
||||||
*/
|
|
||||||
string getSelector() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C `@protocol` expression, for example `@protocol(SomeProtocol)`.
|
|
||||||
*/
|
|
||||||
deprecated class AtProtocolExpr extends Expr {
|
|
||||||
AtProtocolExpr() { none() }
|
|
||||||
|
|
||||||
override string toString() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the protocol of this `@protocol` expression, for example `SomeProtocol`.
|
|
||||||
*/
|
|
||||||
Protocol getProtocol() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C `@encode` expression, for example `@encode(int *)`.
|
|
||||||
*/
|
|
||||||
deprecated class AtEncodeExpr extends Expr {
|
|
||||||
AtEncodeExpr() { none() }
|
|
||||||
|
|
||||||
override string toString() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the type this `@encode` expression encodes, for example `int *`.
|
|
||||||
*/
|
|
||||||
Type getEncodedType() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C throw expression.
|
|
||||||
*/
|
|
||||||
deprecated class ObjcThrowExpr extends ThrowExpr {
|
|
||||||
ObjcThrowExpr() { none() }
|
|
||||||
|
|
||||||
override string toString() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C throw expression with no argument (which causes the
|
|
||||||
* current exception to be re-thrown).
|
|
||||||
*/
|
|
||||||
deprecated class ObjcReThrowExpr extends ReThrowExpr, ObjcThrowExpr {
|
|
||||||
ObjcReThrowExpr() { none() }
|
|
||||||
|
|
||||||
override string toString() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C @ expression which boxes a single value, such as @(22).
|
|
||||||
*/
|
|
||||||
deprecated class AtExpr extends UnaryOperation {
|
|
||||||
AtExpr() { none() }
|
|
||||||
|
|
||||||
override string toString() { none() }
|
|
||||||
|
|
||||||
override string getOperator() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C @[...] literal.
|
|
||||||
*/
|
|
||||||
deprecated class ArrayLiteral extends Expr {
|
|
||||||
ArrayLiteral() { none() }
|
|
||||||
|
|
||||||
/** Gets a textual representation of this array literal. */
|
|
||||||
override string toString() { none() }
|
|
||||||
|
|
||||||
/** An element of the array */
|
|
||||||
Expr getElement(int i) { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C @{...} literal.
|
|
||||||
*/
|
|
||||||
deprecated class DictionaryLiteral extends Expr {
|
|
||||||
DictionaryLiteral() { none() }
|
|
||||||
|
|
||||||
/** Gets a textual representation of this dictionary literal. */
|
|
||||||
override string toString() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C @"..." string literal.
|
|
||||||
*/
|
|
||||||
deprecated class ObjCLiteralString extends TextLiteral {
|
|
||||||
ObjCLiteralString() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C/C++ overloaded subscripting access expression.
|
|
||||||
*
|
|
||||||
* Either
|
|
||||||
* obj[idx]
|
|
||||||
* or
|
|
||||||
* obj[idx] = expr
|
|
||||||
*/
|
|
||||||
deprecated class SubscriptExpr extends Expr {
|
|
||||||
SubscriptExpr() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the object expression being subscripted.
|
|
||||||
*/
|
|
||||||
Expr getSubscriptBase() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the expression giving the index into the object.
|
|
||||||
*/
|
|
||||||
Expr getSubscriptIndex() { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the expression being assigned (if this is an assignment).
|
|
||||||
*/
|
|
||||||
Expr getAssignedExpr() { none() }
|
|
||||||
|
|
||||||
override string toString() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Objective-C is no longer supported.
|
|
||||||
* An Objective C _cmd expression.
|
|
||||||
*/
|
|
||||||
deprecated class CmdExpr extends Expr {
|
|
||||||
CmdExpr() { none() }
|
|
||||||
|
|
||||||
override string toString() { none() }
|
|
||||||
|
|
||||||
override predicate mayBeImpure() { none() }
|
|
||||||
|
|
||||||
override predicate mayBeGloballyImpure() { none() }
|
|
||||||
}
|
|
||||||
@@ -39,19 +39,6 @@ class CorrectIncludeGuard extends IncludeGuardedHeader {
|
|||||||
PreprocessorEndif getEndif() { correctIncludeGuard(this, _, _, result, _) }
|
PreprocessorEndif getEndif() { correctIncludeGuard(this, _, _, result, _) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: no longer useful.
|
|
||||||
*/
|
|
||||||
deprecated class NotIncludedGuard extends IncludeGuardedHeader {
|
|
||||||
NotIncludedGuard() { none() }
|
|
||||||
|
|
||||||
/** Gets the `#ifndef` directive used to prevent multiple inclusion of this file. */
|
|
||||||
PreprocessorIfndef getIfndef() { result.getFile() = this }
|
|
||||||
|
|
||||||
/** Gets the `#endif` directive closing this file. */
|
|
||||||
PreprocessorEndif getEndif() { result.getFile() = this }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A file with no code in it.
|
* A file with no code in it.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -129,11 +129,11 @@ private class FromGlobalVarTaintTrackingCfg extends TaintTracking2::Configuratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
private predicate readsVariable(LoadInstruction load, Variable var) {
|
private predicate readsVariable(LoadInstruction load, Variable var) {
|
||||||
load.getSourceAddress().(VariableAddressInstruction).getASTVariable() = var
|
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate writesVariable(StoreInstruction store, Variable var) {
|
private predicate writesVariable(StoreInstruction store, Variable var) {
|
||||||
store.getDestinationAddress().(VariableAddressInstruction).getASTVariable() = var
|
store.getDestinationAddress().(VariableAddressInstruction).getAstVariable() = var
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -489,9 +489,9 @@ module TaintedWithPath {
|
|||||||
/** Gets the element that `pathNode` wraps, if any. */
|
/** Gets the element that `pathNode` wraps, if any. */
|
||||||
Element getElementFromPathNode(PathNode pathNode) {
|
Element getElementFromPathNode(PathNode pathNode) {
|
||||||
exists(DataFlow::Node node | node = pathNode.(WrapPathNode).inner().getNode() |
|
exists(DataFlow::Node node | node = pathNode.(WrapPathNode).inner().getNode() |
|
||||||
result = node.asInstruction().getAST()
|
result = node.asInstruction().getAst()
|
||||||
or
|
or
|
||||||
result = node.asOperand().getDef().getAST()
|
result = node.asOperand().getDef().getAst()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
result = pathNode.(EndpointPathNode).inner()
|
result = pathNode.(EndpointPathNode).inner()
|
||||||
|
|||||||
270
cpp/ql/lib/semmle/code/cpp/ir/dataflow/MustFlow.qll
Normal file
270
cpp/ql/lib/semmle/code/cpp/ir/dataflow/MustFlow.qll
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
/**
|
||||||
|
* This file provides a library for inter-procedural must-flow data flow analysis.
|
||||||
|
* Unlike `DataFlow.qll`, the analysis provided by this file checks whether data _must_ flow
|
||||||
|
* from a source to a _sink_.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private import cpp
|
||||||
|
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||||
|
private import semmle.code.cpp.ir.IR
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A configuration of a data flow analysis that performs must-flow analysis. This is different
|
||||||
|
* from `DataFlow.qll` which performs may-flow analysis (i.e., it finds paths where the source _may_
|
||||||
|
* flow to the sink).
|
||||||
|
*
|
||||||
|
* Like in `DataFlow.qll`, each use of the `MustFlow.qll` library must define its own unique extension
|
||||||
|
* of this abstract class. To create a configuration, extend this class with a subclass whose
|
||||||
|
* characteristic predicate is a unique singleton string and override `isSource`, `isSink` (and
|
||||||
|
* `isAdditionalFlowStep` if additional steps are required).
|
||||||
|
*/
|
||||||
|
abstract class MustFlowConfiguration extends string {
|
||||||
|
bindingset[this]
|
||||||
|
MustFlowConfiguration() { any() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `source` is a relevant data flow source.
|
||||||
|
*/
|
||||||
|
abstract predicate isSource(DataFlow::Node source);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `sink` is a relevant data flow sink.
|
||||||
|
*/
|
||||||
|
abstract predicate isSink(DataFlow::Node sink);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||||
|
* into account in the analysis.
|
||||||
|
*/
|
||||||
|
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data must flow from `source` to `sink` for this configuration.
|
||||||
|
*
|
||||||
|
* The corresponding paths are generated from the end-points and the graph
|
||||||
|
* included in the module `PathGraph`.
|
||||||
|
*/
|
||||||
|
final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) {
|
||||||
|
this.isSource(source.getNode()) and
|
||||||
|
source.getASuccessor+() = sink
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `node` flows from a source. */
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowsFromSource(DataFlow::Node node, MustFlowConfiguration config) {
|
||||||
|
config.isSource(node)
|
||||||
|
or
|
||||||
|
exists(DataFlow::Node mid |
|
||||||
|
step(mid, node, config) and
|
||||||
|
flowsFromSource(mid, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `node` flows to a sink. */
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowsToSink(DataFlow::Node node, MustFlowConfiguration config) {
|
||||||
|
flowsFromSource(node, pragma[only_bind_into](config)) and
|
||||||
|
(
|
||||||
|
config.isSink(node)
|
||||||
|
or
|
||||||
|
exists(DataFlow::Node mid |
|
||||||
|
step(node, mid, config) and
|
||||||
|
flowsToSink(mid, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
cached
|
||||||
|
private module Cached {
|
||||||
|
/** Holds if `p` is the `n`'th parameter of the non-virtual function `f`. */
|
||||||
|
private predicate parameterOf(Parameter p, Function f, int n) {
|
||||||
|
not f.isVirtual() and f.getParameter(n) = p
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `instr` is the `n`'th argument to a call to the non-virtual function `f`, and
|
||||||
|
* `init` is the corresponding initialization instruction that receives the value of `instr` in `f`.
|
||||||
|
*/
|
||||||
|
private predicate flowIntoParameter(
|
||||||
|
Function f, int n, CallInstruction call, Instruction instr, InitializeParameterInstruction init
|
||||||
|
) {
|
||||||
|
not f.isVirtual() and
|
||||||
|
call.getPositionalArgument(n) = instr and
|
||||||
|
f = call.getStaticCallTarget() and
|
||||||
|
getEnclosingNonVirtualFunctionInitializeParameter(init, f) and
|
||||||
|
init.getParameter().getIndex() = pragma[only_bind_into](pragma[only_bind_out](n))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `instr` is an argument to a call to the function `f`, and `init` is the
|
||||||
|
* corresponding initialization instruction that receives the value of `instr` in `f`.
|
||||||
|
*/
|
||||||
|
pragma[noinline]
|
||||||
|
private predicate getPositionalArgumentInitParam(
|
||||||
|
CallInstruction call, Instruction instr, InitializeParameterInstruction init, Function f
|
||||||
|
) {
|
||||||
|
exists(int n |
|
||||||
|
parameterOf(_, f, n) and
|
||||||
|
flowIntoParameter(f, pragma[only_bind_into](pragma[only_bind_out](n)), call, instr, init)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `instr` is the qualifier to a call to the non-virtual function `f`, and
|
||||||
|
* `init` is the corresponding initialization instruction that receives the value of
|
||||||
|
* `instr` in `f`.
|
||||||
|
*/
|
||||||
|
pragma[noinline]
|
||||||
|
private predicate getThisArgumentInitParam(
|
||||||
|
CallInstruction call, Instruction instr, InitializeParameterInstruction init, Function f
|
||||||
|
) {
|
||||||
|
not f.isVirtual() and
|
||||||
|
call.getStaticCallTarget() = f and
|
||||||
|
getEnclosingNonVirtualFunctionInitializeParameter(init, f) and
|
||||||
|
call.getThisArgument() = instr and
|
||||||
|
init.getIRVariable() instanceof IRThisVariable
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `f` is the enclosing non-virtual function of `init`. */
|
||||||
|
private predicate getEnclosingNonVirtualFunctionInitializeParameter(
|
||||||
|
InitializeParameterInstruction init, Function f
|
||||||
|
) {
|
||||||
|
not f.isVirtual() and
|
||||||
|
init.getEnclosingFunction() = f
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `f` is the enclosing non-virtual function of `init`. */
|
||||||
|
private predicate getEnclosingNonVirtualFunctionInitializeIndirection(
|
||||||
|
InitializeIndirectionInstruction init, Function f
|
||||||
|
) {
|
||||||
|
not f.isVirtual() and
|
||||||
|
init.getEnclosingFunction() = f
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `instr` is an argument (or argument indirection) to a call, and
|
||||||
|
* `succ` is the corresponding initialization instruction in the call target.
|
||||||
|
*/
|
||||||
|
private predicate flowThroughCallable(Instruction argument, Instruction parameter) {
|
||||||
|
// Flow from an argument to a parameter
|
||||||
|
exists(CallInstruction call, InitializeParameterInstruction init | init = parameter |
|
||||||
|
getPositionalArgumentInitParam(call, argument, init, call.getStaticCallTarget())
|
||||||
|
or
|
||||||
|
getThisArgumentInitParam(call, argument, init, call.getStaticCallTarget())
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Flow from argument indirection to parameter indirection
|
||||||
|
exists(
|
||||||
|
CallInstruction call, ReadSideEffectInstruction read, InitializeIndirectionInstruction init
|
||||||
|
|
|
||||||
|
init = parameter and
|
||||||
|
read.getPrimaryInstruction() = call and
|
||||||
|
getEnclosingNonVirtualFunctionInitializeIndirection(init, call.getStaticCallTarget())
|
||||||
|
|
|
||||||
|
exists(int n |
|
||||||
|
read.getSideEffectOperand().getAnyDef() = argument and
|
||||||
|
read.getIndex() = pragma[only_bind_into](n) and
|
||||||
|
init.getParameter().getIndex() = pragma[only_bind_into](n)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
call.getThisArgument() = argument and
|
||||||
|
init.getIRVariable() instanceof IRThisVariable
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate instructionToOperandStep(Instruction instr, Operand operand) {
|
||||||
|
operand.getDef() = instr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flows from `operand` to `instr`.
|
||||||
|
*
|
||||||
|
* This predicate ignores flow through `PhiInstruction`s to create a 'must flow' relation.
|
||||||
|
*/
|
||||||
|
private predicate operandToInstructionStep(Operand operand, Instruction instr) {
|
||||||
|
instr.(CopyInstruction).getSourceValueOperand() = operand
|
||||||
|
or
|
||||||
|
instr.(ConvertInstruction).getUnaryOperand() = operand
|
||||||
|
or
|
||||||
|
instr.(CheckedConvertOrNullInstruction).getUnaryOperand() = operand
|
||||||
|
or
|
||||||
|
instr.(InheritanceConversionInstruction).getUnaryOperand() = operand
|
||||||
|
or
|
||||||
|
instr.(ChiInstruction).getTotalOperand() = operand
|
||||||
|
}
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||||
|
instructionToOperandStep(nodeFrom.asInstruction(), nodeTo.asOperand())
|
||||||
|
or
|
||||||
|
flowThroughCallable(nodeFrom.asInstruction(), nodeTo.asInstruction())
|
||||||
|
or
|
||||||
|
operandToInstructionStep(nodeFrom.asOperand(), nodeTo.asInstruction())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `nodeFrom` flows to `nodeTo`. */
|
||||||
|
private predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, MustFlowConfiguration config) {
|
||||||
|
exists(config) and
|
||||||
|
Cached::step(nodeFrom, nodeTo)
|
||||||
|
or
|
||||||
|
config.isAdditionalFlowStep(nodeFrom, nodeTo)
|
||||||
|
}
|
||||||
|
|
||||||
|
private newtype TLocalPathNode =
|
||||||
|
MkLocalPathNode(DataFlow::Node n, MustFlowConfiguration config) {
|
||||||
|
flowsToSink(n, config) and
|
||||||
|
(
|
||||||
|
config.isSource(n)
|
||||||
|
or
|
||||||
|
exists(MustFlowPathNode mid | step(mid.getNode(), n, config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A `Node` that is in a path from a source to a sink. */
|
||||||
|
class MustFlowPathNode extends TLocalPathNode {
|
||||||
|
DataFlow::Node n;
|
||||||
|
|
||||||
|
MustFlowPathNode() { this = MkLocalPathNode(n, _) }
|
||||||
|
|
||||||
|
/** Gets the underlying node. */
|
||||||
|
DataFlow::Node getNode() { result = n }
|
||||||
|
|
||||||
|
/** Gets a textual representation of this node. */
|
||||||
|
string toString() { result = n.toString() }
|
||||||
|
|
||||||
|
/** Gets the location of this element. */
|
||||||
|
Location getLocation() { result = n.getLocation() }
|
||||||
|
|
||||||
|
/** Gets a successor node, if any. */
|
||||||
|
MustFlowPathNode getASuccessor() {
|
||||||
|
step(this.getNode(), result.getNode(), this.getConfiguration())
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the associated configuration. */
|
||||||
|
MustFlowConfiguration getConfiguration() { this = MkLocalPathNode(_, result) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MustFlowPathSink extends MustFlowPathNode {
|
||||||
|
MustFlowPathSink() { this.getConfiguration().isSink(this.getNode()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||||
|
*/
|
||||||
|
module PathGraph {
|
||||||
|
private predicate reach(MustFlowPathNode n) {
|
||||||
|
n instanceof MustFlowPathSink or reach(n.getASuccessor())
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||||
|
query predicate edges(MustFlowPathNode a, MustFlowPathNode b) {
|
||||||
|
a.getASuccessor() = b and reach(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||||
|
query predicate nodes(MustFlowPathNode n, string key, string val) {
|
||||||
|
reach(n) and key = "semmle.label" and val = n.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ private import semmle.code.cpp.ir.IR
|
|||||||
*/
|
*/
|
||||||
Function resolveCall(Call call) {
|
Function resolveCall(Call call) {
|
||||||
exists(CallInstruction callInstruction |
|
exists(CallInstruction callInstruction |
|
||||||
callInstruction.getAST() = call and
|
callInstruction.getAst() = call and
|
||||||
result = viableCallable(callInstruction)
|
result = viableCallable(callInstruction)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,4 @@ import semmle.code.cpp.ir.dataflow.DataFlow2
|
|||||||
|
|
||||||
module TaintTracking {
|
module TaintTracking {
|
||||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl
|
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||||
private import semmle.code.cpp.ir.dataflow.TaintTracking2
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use TaintTracking2::Configuration instead.
|
|
||||||
*/
|
|
||||||
deprecated class Configuration2 = TaintTracking2::Configuration;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,12 +116,12 @@ private module VirtualDispatch {
|
|||||||
/** Holds if `addressInstr` is an instruction that produces the address of `var`. */
|
/** Holds if `addressInstr` is an instruction that produces the address of `var`. */
|
||||||
private predicate addressOfGlobal(Instruction addressInstr, GlobalOrNamespaceVariable var) {
|
private predicate addressOfGlobal(Instruction addressInstr, GlobalOrNamespaceVariable var) {
|
||||||
// Access directly to the global variable
|
// Access directly to the global variable
|
||||||
addressInstr.(VariableAddressInstruction).getASTVariable() = var
|
addressInstr.(VariableAddressInstruction).getAstVariable() = var
|
||||||
or
|
or
|
||||||
// Access to a field on a global union
|
// Access to a field on a global union
|
||||||
exists(FieldAddressInstruction fa |
|
exists(FieldAddressInstruction fa |
|
||||||
fa = addressInstr and
|
fa = addressInstr and
|
||||||
fa.getObjectAddress().(VariableAddressInstruction).getASTVariable() = var and
|
fa.getObjectAddress().(VariableAddressInstruction).getAstVariable() = var and
|
||||||
fa.getField().getDeclaringType() instanceof Union
|
fa.getField().getDeclaringType() instanceof Union
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,12 +87,30 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow into `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow out of `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||||
|
* the flow state is `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||||
* into account in the analysis.
|
* into account in the analysis.
|
||||||
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierIn(n, state)
|
||||||
|
|
|
||||||
|
config.isSource(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierOut(n, state)
|
||||||
|
|
|
||||||
|
config.isSink(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n | node.asNode() = n |
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierIn(n, state) and
|
||||||
|
not config.isSource(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierOut(n, state) and
|
||||||
|
not config.isSink(n, state)
|
||||||
|
or
|
||||||
|
exists(BarrierGuard g |
|
||||||
|
config.isBarrierGuard(g, state) and
|
||||||
|
n = g.getAGuardedNode()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not outBarrier(node1, config) and
|
not fullOutBarrier(node1, config) and
|
||||||
not inBarrier(node2, config) and
|
not fullInBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
@@ -870,8 +920,8 @@ private module Stage1 {
|
|||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not inBarrier(node, config) and
|
not fullInBarrier(node, config) and
|
||||||
not outBarrier(node, config)
|
not fullOutBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not outBarrier(ret, config) and
|
not fullOutBarrier(ret, config) and
|
||||||
not inBarrier(out, config)
|
not fullInBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not outBarrier(arg, config) and
|
not fullOutBarrier(arg, config) and
|
||||||
not inBarrier(p, config)
|
not fullInBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
|
|||||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||||
* flow steps in a dataflow path.
|
* flow steps in a dataflow path.
|
||||||
*/
|
*/
|
||||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
(
|
(
|
||||||
sourceNode(node, state, config) or
|
sourceNode(node, state, config)
|
||||||
jumpStep(_, node, config) or
|
or
|
||||||
additionalJumpStep(_, node, config) or
|
jumpStep(_, node, config)
|
||||||
additionalJumpStateStep(_, _, node, state, config) or
|
or
|
||||||
node instanceof ParamNodeEx or
|
additionalJumpStep(_, node, config)
|
||||||
node.asNode() instanceof OutNodeExt or
|
or
|
||||||
store(_, _, node, _, config) or
|
additionalJumpStateStep(_, _, node, state, config)
|
||||||
read(_, _, node, config) or
|
or
|
||||||
|
node instanceof ParamNodeEx
|
||||||
|
or
|
||||||
|
node.asNode() instanceof OutNodeExt
|
||||||
|
or
|
||||||
|
store(_, _, node, _, config)
|
||||||
|
or
|
||||||
|
read(_, _, node, config)
|
||||||
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
|
or
|
||||||
|
exists(FlowState s |
|
||||||
|
additionalLocalStateStep(_, s, node, state, config) and
|
||||||
|
s != state
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
additionalJumpStateStep(node, state, next, s, config)
|
additionalJumpStateStep(node, state, next, s, config)
|
||||||
|
or
|
||||||
|
additionalLocalStateStep(node, state, next, s, config) and
|
||||||
|
s != state
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate localFlowStepPlus(
|
private predicate localFlowStepPlus(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||||
DataFlowType t, Configuration config, LocalCallContext cc
|
Configuration config, LocalCallContext cc
|
||||||
) {
|
) {
|
||||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||||
(
|
(
|
||||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||||
(
|
(
|
||||||
localFlowStepNodeCand1(node1, node2, config) and
|
localFlowStepNodeCand1(node1, node2, config) and
|
||||||
state1 = state2 and
|
|
||||||
preservesValue = true and
|
preservesValue = true and
|
||||||
t = node1.getDataFlowType() // irrelevant dummy value
|
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||||
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType()
|
t = node2.getDataFlowType()
|
||||||
) and
|
) and
|
||||||
node1 != node2 and
|
node1 != node2 and
|
||||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||||
pragma[only_bind_into](config), cc) and
|
pragma[only_bind_into](config), cc) and
|
||||||
localFlowStepNodeCand1(mid, node2, config) and
|
localFlowStepNodeCand1(mid, node2, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState st |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType() and
|
t = node2.getDataFlowType()
|
||||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
|
|||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||||
callContext) and
|
localFlowExit(node2, state1, config) and
|
||||||
localFlowExit(node2, state2, config)
|
state1 = state2
|
||||||
|
or
|
||||||
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
|
state1 != state2 and
|
||||||
|
preservesValue = false and
|
||||||
|
apf = TFrontNil(node2.getDataFlowType()) and
|
||||||
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
isUnreachableInCallCached(node2.asNode(), call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2695,10 +2769,10 @@ private module Stage4 {
|
|||||||
|
|
||||||
bindingset[node, cc, config]
|
bindingset[node, cc, config]
|
||||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||||
localFlowEntry(node, _, config) and
|
|
||||||
result =
|
result =
|
||||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||||
node.getEnclosingCallable())
|
node.getEnclosingCallable()) and
|
||||||
|
exists(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate localStep(
|
private predicate localStep(
|
||||||
|
|||||||
@@ -87,12 +87,30 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow into `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow out of `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||||
|
* the flow state is `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||||
* into account in the analysis.
|
* into account in the analysis.
|
||||||
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierIn(n, state)
|
||||||
|
|
|
||||||
|
config.isSource(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierOut(n, state)
|
||||||
|
|
|
||||||
|
config.isSink(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n | node.asNode() = n |
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierIn(n, state) and
|
||||||
|
not config.isSource(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierOut(n, state) and
|
||||||
|
not config.isSink(n, state)
|
||||||
|
or
|
||||||
|
exists(BarrierGuard g |
|
||||||
|
config.isBarrierGuard(g, state) and
|
||||||
|
n = g.getAGuardedNode()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not outBarrier(node1, config) and
|
not fullOutBarrier(node1, config) and
|
||||||
not inBarrier(node2, config) and
|
not fullInBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
@@ -870,8 +920,8 @@ private module Stage1 {
|
|||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not inBarrier(node, config) and
|
not fullInBarrier(node, config) and
|
||||||
not outBarrier(node, config)
|
not fullOutBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not outBarrier(ret, config) and
|
not fullOutBarrier(ret, config) and
|
||||||
not inBarrier(out, config)
|
not fullInBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not outBarrier(arg, config) and
|
not fullOutBarrier(arg, config) and
|
||||||
not inBarrier(p, config)
|
not fullInBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
|
|||||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||||
* flow steps in a dataflow path.
|
* flow steps in a dataflow path.
|
||||||
*/
|
*/
|
||||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
(
|
(
|
||||||
sourceNode(node, state, config) or
|
sourceNode(node, state, config)
|
||||||
jumpStep(_, node, config) or
|
or
|
||||||
additionalJumpStep(_, node, config) or
|
jumpStep(_, node, config)
|
||||||
additionalJumpStateStep(_, _, node, state, config) or
|
or
|
||||||
node instanceof ParamNodeEx or
|
additionalJumpStep(_, node, config)
|
||||||
node.asNode() instanceof OutNodeExt or
|
or
|
||||||
store(_, _, node, _, config) or
|
additionalJumpStateStep(_, _, node, state, config)
|
||||||
read(_, _, node, config) or
|
or
|
||||||
|
node instanceof ParamNodeEx
|
||||||
|
or
|
||||||
|
node.asNode() instanceof OutNodeExt
|
||||||
|
or
|
||||||
|
store(_, _, node, _, config)
|
||||||
|
or
|
||||||
|
read(_, _, node, config)
|
||||||
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
|
or
|
||||||
|
exists(FlowState s |
|
||||||
|
additionalLocalStateStep(_, s, node, state, config) and
|
||||||
|
s != state
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
additionalJumpStateStep(node, state, next, s, config)
|
additionalJumpStateStep(node, state, next, s, config)
|
||||||
|
or
|
||||||
|
additionalLocalStateStep(node, state, next, s, config) and
|
||||||
|
s != state
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate localFlowStepPlus(
|
private predicate localFlowStepPlus(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||||
DataFlowType t, Configuration config, LocalCallContext cc
|
Configuration config, LocalCallContext cc
|
||||||
) {
|
) {
|
||||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||||
(
|
(
|
||||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||||
(
|
(
|
||||||
localFlowStepNodeCand1(node1, node2, config) and
|
localFlowStepNodeCand1(node1, node2, config) and
|
||||||
state1 = state2 and
|
|
||||||
preservesValue = true and
|
preservesValue = true and
|
||||||
t = node1.getDataFlowType() // irrelevant dummy value
|
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||||
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType()
|
t = node2.getDataFlowType()
|
||||||
) and
|
) and
|
||||||
node1 != node2 and
|
node1 != node2 and
|
||||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||||
pragma[only_bind_into](config), cc) and
|
pragma[only_bind_into](config), cc) and
|
||||||
localFlowStepNodeCand1(mid, node2, config) and
|
localFlowStepNodeCand1(mid, node2, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState st |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType() and
|
t = node2.getDataFlowType()
|
||||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
|
|||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||||
callContext) and
|
localFlowExit(node2, state1, config) and
|
||||||
localFlowExit(node2, state2, config)
|
state1 = state2
|
||||||
|
or
|
||||||
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
|
state1 != state2 and
|
||||||
|
preservesValue = false and
|
||||||
|
apf = TFrontNil(node2.getDataFlowType()) and
|
||||||
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
isUnreachableInCallCached(node2.asNode(), call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2695,10 +2769,10 @@ private module Stage4 {
|
|||||||
|
|
||||||
bindingset[node, cc, config]
|
bindingset[node, cc, config]
|
||||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||||
localFlowEntry(node, _, config) and
|
|
||||||
result =
|
result =
|
||||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||||
node.getEnclosingCallable())
|
node.getEnclosingCallable()) and
|
||||||
|
exists(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate localStep(
|
private predicate localStep(
|
||||||
|
|||||||
@@ -87,12 +87,30 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow into `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow out of `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||||
|
* the flow state is `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||||
* into account in the analysis.
|
* into account in the analysis.
|
||||||
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierIn(n, state)
|
||||||
|
|
|
||||||
|
config.isSource(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierOut(n, state)
|
||||||
|
|
|
||||||
|
config.isSink(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n | node.asNode() = n |
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierIn(n, state) and
|
||||||
|
not config.isSource(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierOut(n, state) and
|
||||||
|
not config.isSink(n, state)
|
||||||
|
or
|
||||||
|
exists(BarrierGuard g |
|
||||||
|
config.isBarrierGuard(g, state) and
|
||||||
|
n = g.getAGuardedNode()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not outBarrier(node1, config) and
|
not fullOutBarrier(node1, config) and
|
||||||
not inBarrier(node2, config) and
|
not fullInBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
@@ -870,8 +920,8 @@ private module Stage1 {
|
|||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not inBarrier(node, config) and
|
not fullInBarrier(node, config) and
|
||||||
not outBarrier(node, config)
|
not fullOutBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not outBarrier(ret, config) and
|
not fullOutBarrier(ret, config) and
|
||||||
not inBarrier(out, config)
|
not fullInBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not outBarrier(arg, config) and
|
not fullOutBarrier(arg, config) and
|
||||||
not inBarrier(p, config)
|
not fullInBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
|
|||||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||||
* flow steps in a dataflow path.
|
* flow steps in a dataflow path.
|
||||||
*/
|
*/
|
||||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
(
|
(
|
||||||
sourceNode(node, state, config) or
|
sourceNode(node, state, config)
|
||||||
jumpStep(_, node, config) or
|
or
|
||||||
additionalJumpStep(_, node, config) or
|
jumpStep(_, node, config)
|
||||||
additionalJumpStateStep(_, _, node, state, config) or
|
or
|
||||||
node instanceof ParamNodeEx or
|
additionalJumpStep(_, node, config)
|
||||||
node.asNode() instanceof OutNodeExt or
|
or
|
||||||
store(_, _, node, _, config) or
|
additionalJumpStateStep(_, _, node, state, config)
|
||||||
read(_, _, node, config) or
|
or
|
||||||
|
node instanceof ParamNodeEx
|
||||||
|
or
|
||||||
|
node.asNode() instanceof OutNodeExt
|
||||||
|
or
|
||||||
|
store(_, _, node, _, config)
|
||||||
|
or
|
||||||
|
read(_, _, node, config)
|
||||||
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
|
or
|
||||||
|
exists(FlowState s |
|
||||||
|
additionalLocalStateStep(_, s, node, state, config) and
|
||||||
|
s != state
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
additionalJumpStateStep(node, state, next, s, config)
|
additionalJumpStateStep(node, state, next, s, config)
|
||||||
|
or
|
||||||
|
additionalLocalStateStep(node, state, next, s, config) and
|
||||||
|
s != state
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate localFlowStepPlus(
|
private predicate localFlowStepPlus(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||||
DataFlowType t, Configuration config, LocalCallContext cc
|
Configuration config, LocalCallContext cc
|
||||||
) {
|
) {
|
||||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||||
(
|
(
|
||||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||||
(
|
(
|
||||||
localFlowStepNodeCand1(node1, node2, config) and
|
localFlowStepNodeCand1(node1, node2, config) and
|
||||||
state1 = state2 and
|
|
||||||
preservesValue = true and
|
preservesValue = true and
|
||||||
t = node1.getDataFlowType() // irrelevant dummy value
|
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||||
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType()
|
t = node2.getDataFlowType()
|
||||||
) and
|
) and
|
||||||
node1 != node2 and
|
node1 != node2 and
|
||||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||||
pragma[only_bind_into](config), cc) and
|
pragma[only_bind_into](config), cc) and
|
||||||
localFlowStepNodeCand1(mid, node2, config) and
|
localFlowStepNodeCand1(mid, node2, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState st |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType() and
|
t = node2.getDataFlowType()
|
||||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
|
|||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||||
callContext) and
|
localFlowExit(node2, state1, config) and
|
||||||
localFlowExit(node2, state2, config)
|
state1 = state2
|
||||||
|
or
|
||||||
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
|
state1 != state2 and
|
||||||
|
preservesValue = false and
|
||||||
|
apf = TFrontNil(node2.getDataFlowType()) and
|
||||||
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
isUnreachableInCallCached(node2.asNode(), call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2695,10 +2769,10 @@ private module Stage4 {
|
|||||||
|
|
||||||
bindingset[node, cc, config]
|
bindingset[node, cc, config]
|
||||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||||
localFlowEntry(node, _, config) and
|
|
||||||
result =
|
result =
|
||||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||||
node.getEnclosingCallable())
|
node.getEnclosingCallable()) and
|
||||||
|
exists(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate localStep(
|
private predicate localStep(
|
||||||
|
|||||||
@@ -87,12 +87,30 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow into `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow out of `node` is prohibited when the flow state is
|
||||||
|
* `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||||
|
* the flow state is `state`
|
||||||
|
*/
|
||||||
|
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||||
* into account in the analysis.
|
* into account in the analysis.
|
||||||
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierIn(n, state)
|
||||||
|
|
|
||||||
|
config.isSource(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
exists(Node n |
|
||||||
|
node.asNode() = n and
|
||||||
|
config.isBarrierOut(n, state)
|
||||||
|
|
|
||||||
|
config.isSink(n, state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n | node.asNode() = n |
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierIn(n, state) and
|
||||||
|
not config.isSource(n, state)
|
||||||
|
or
|
||||||
|
config.isBarrierOut(n, state) and
|
||||||
|
not config.isSink(n, state)
|
||||||
|
or
|
||||||
|
exists(BarrierGuard g |
|
||||||
|
config.isBarrierGuard(g, state) and
|
||||||
|
n = g.getAGuardedNode()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not outBarrier(node1, config) and
|
not fullOutBarrier(node1, config) and
|
||||||
not inBarrier(node2, config) and
|
not fullInBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
|
not stateOutBarrier(node1, s1, config) and
|
||||||
|
not stateInBarrier(node2, s2, config) and
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
@@ -870,8 +920,8 @@ private module Stage1 {
|
|||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not inBarrier(node, config) and
|
not fullInBarrier(node, config) and
|
||||||
not outBarrier(node, config)
|
not fullOutBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not outBarrier(ret, config) and
|
not fullOutBarrier(ret, config) and
|
||||||
not inBarrier(out, config)
|
not fullInBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not outBarrier(arg, config) and
|
not fullOutBarrier(arg, config) and
|
||||||
not inBarrier(p, config)
|
not fullInBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
|
|||||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||||
* flow steps in a dataflow path.
|
* flow steps in a dataflow path.
|
||||||
*/
|
*/
|
||||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
(
|
(
|
||||||
sourceNode(node, state, config) or
|
sourceNode(node, state, config)
|
||||||
jumpStep(_, node, config) or
|
or
|
||||||
additionalJumpStep(_, node, config) or
|
jumpStep(_, node, config)
|
||||||
additionalJumpStateStep(_, _, node, state, config) or
|
or
|
||||||
node instanceof ParamNodeEx or
|
additionalJumpStep(_, node, config)
|
||||||
node.asNode() instanceof OutNodeExt or
|
or
|
||||||
store(_, _, node, _, config) or
|
additionalJumpStateStep(_, _, node, state, config)
|
||||||
read(_, _, node, config) or
|
or
|
||||||
|
node instanceof ParamNodeEx
|
||||||
|
or
|
||||||
|
node.asNode() instanceof OutNodeExt
|
||||||
|
or
|
||||||
|
store(_, _, node, _, config)
|
||||||
|
or
|
||||||
|
read(_, _, node, config)
|
||||||
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
|
or
|
||||||
|
exists(FlowState s |
|
||||||
|
additionalLocalStateStep(_, s, node, state, config) and
|
||||||
|
s != state
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
additionalJumpStateStep(node, state, next, s, config)
|
additionalJumpStateStep(node, state, next, s, config)
|
||||||
|
or
|
||||||
|
additionalLocalStateStep(node, state, next, s, config) and
|
||||||
|
s != state
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
Stage2::revFlow(node, state, config) and
|
Stage2::revFlow(node, state, config) and
|
||||||
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate localFlowStepPlus(
|
private predicate localFlowStepPlus(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||||
DataFlowType t, Configuration config, LocalCallContext cc
|
Configuration config, LocalCallContext cc
|
||||||
) {
|
) {
|
||||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||||
(
|
(
|
||||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||||
(
|
(
|
||||||
localFlowStepNodeCand1(node1, node2, config) and
|
localFlowStepNodeCand1(node1, node2, config) and
|
||||||
state1 = state2 and
|
|
||||||
preservesValue = true and
|
preservesValue = true and
|
||||||
t = node1.getDataFlowType() // irrelevant dummy value
|
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||||
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType()
|
t = node2.getDataFlowType()
|
||||||
) and
|
) and
|
||||||
node1 != node2 and
|
node1 != node2 and
|
||||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||||
pragma[only_bind_into](config), cc) and
|
pragma[only_bind_into](config), cc) and
|
||||||
localFlowStepNodeCand1(mid, node2, config) and
|
localFlowStepNodeCand1(mid, node2, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState st |
|
exists(NodeEx mid |
|
||||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||||
not mid instanceof FlowCheckNode and
|
not mid instanceof FlowCheckNode and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
t = node2.getDataFlowType() and
|
t = node2.getDataFlowType()
|
||||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
|
|||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||||
callContext) and
|
localFlowExit(node2, state1, config) and
|
||||||
localFlowExit(node2, state2, config)
|
state1 = state2
|
||||||
|
or
|
||||||
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
|
state1 != state2 and
|
||||||
|
preservesValue = false and
|
||||||
|
apf = TFrontNil(node2.getDataFlowType()) and
|
||||||
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
isUnreachableInCallCached(node2.asNode(), call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2695,10 +2769,10 @@ private module Stage4 {
|
|||||||
|
|
||||||
bindingset[node, cc, config]
|
bindingset[node, cc, config]
|
||||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||||
localFlowEntry(node, _, config) and
|
|
||||||
result =
|
result =
|
||||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||||
node.getEnclosingCallable())
|
node.getEnclosingCallable()) and
|
||||||
|
exists(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate localStep(
|
private predicate localStep(
|
||||||
|
|||||||
@@ -158,14 +158,6 @@ class Node extends TIRDataFlowNode {
|
|||||||
*/
|
*/
|
||||||
Expr asPartialDefinition() { result = this.(PartialDefinitionNode).getDefinedExpr() }
|
Expr asPartialDefinition() { result = this.(PartialDefinitionNode).getDefinedExpr() }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: See UninitializedNode.
|
|
||||||
*
|
|
||||||
* Gets the uninitialized local variable corresponding to this node, if
|
|
||||||
* any.
|
|
||||||
*/
|
|
||||||
deprecated LocalVariable asUninitialized() { none() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an upper bound on the type of this node.
|
* Gets an upper bound on the type of this node.
|
||||||
*/
|
*/
|
||||||
@@ -439,7 +431,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
|||||||
|
|
||||||
SsaPhiNode() { this = TSsaPhiNode(phi) }
|
SsaPhiNode() { this = TSsaPhiNode(phi) }
|
||||||
|
|
||||||
/* Get the phi node associated with this node. */
|
/** Gets the phi node associated with this node. */
|
||||||
Ssa::PhiNode getPhiNode() { result = phi }
|
Ssa::PhiNode getPhiNode() { result = phi }
|
||||||
|
|
||||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||||
@@ -560,22 +552,6 @@ class ParameterIndirectionNode extends ParameterNode {
|
|||||||
override string toString() { result = "*" + instr.getIRVariable().toString() }
|
override string toString() { result = "*" + instr.getIRVariable().toString() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Data flow was never an accurate way to determine what
|
|
||||||
* expressions might be uninitialized. It errs on the side of saying that
|
|
||||||
* everything is uninitialized, and this is even worse in the IR because the IR
|
|
||||||
* doesn't use syntactic hints to rule out variables that are definitely
|
|
||||||
* initialized.
|
|
||||||
*
|
|
||||||
* The value of an uninitialized local variable, viewed as a node in a data
|
|
||||||
* flow graph.
|
|
||||||
*/
|
|
||||||
deprecated class UninitializedNode extends Node {
|
|
||||||
UninitializedNode() { none() }
|
|
||||||
|
|
||||||
LocalVariable getLocalVariable() { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node associated with an object after an operation that might have
|
* A node associated with an object after an operation that might have
|
||||||
* changed its state.
|
* changed its state.
|
||||||
@@ -725,14 +701,6 @@ InstructionNode instructionNode(Instruction instr) { result.getInstruction() = i
|
|||||||
*/
|
*/
|
||||||
OperandNode operandNode(Operand operand) { result.getOperand() = operand }
|
OperandNode operandNode(Operand operand) { result.getOperand() = operand }
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: use `definitionByReferenceNodeFromArgument` instead.
|
|
||||||
*
|
|
||||||
* Gets the `Node` corresponding to a definition by reference of the variable
|
|
||||||
* that is passed as `argument` of a call.
|
|
||||||
*/
|
|
||||||
deprecated DefinitionByReferenceNode definitionByReferenceNode(Expr e) { result.getArgument() = e }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the `Node` corresponding to the value of evaluating `e` or any of its
|
* Gets the `Node` corresponding to the value of evaluating `e` or any of its
|
||||||
* conversions. There is no result if `e` is a `Conversion`. For data flowing
|
* conversions. There is no result if `e` is a `Conversion`. For data flowing
|
||||||
|
|||||||
@@ -287,20 +287,6 @@ private module SsaDefReaches {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the SSA definition of `v` at `def` reaches uncertain SSA definition
|
|
||||||
* `redef` in the same basic block, without crossing another SSA definition of `v`.
|
|
||||||
*/
|
|
||||||
predicate ssaDefReachesUncertainDefWithinBlock(
|
|
||||||
SourceVariable v, Definition def, UncertainWriteDefinition redef
|
|
||||||
) {
|
|
||||||
exists(BasicBlock bb, int rnk, int i |
|
|
||||||
ssaDefReachesRank(bb, def, rnk, v) and
|
|
||||||
rnk = ssaRefRank(bb, i, v, SsaDef()) - 1 and
|
|
||||||
redef.definesAt(v, bb, i)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -64,13 +64,30 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
override predicate isSource(DataFlow::Node source) { none() }
|
override predicate isSource(DataFlow::Node source) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `sink` is a relevant taint sink.
|
* Holds if `source` is a relevant taint source with the given initial
|
||||||
|
* `state`.
|
||||||
|
*
|
||||||
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
|
*/
|
||||||
|
// overridden to provide taint-tracking specific qldoc
|
||||||
|
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `sink` is a relevant taint sink
|
||||||
*
|
*
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
*/
|
*/
|
||||||
// overridden to provide taint-tracking specific qldoc
|
// overridden to provide taint-tracking specific qldoc
|
||||||
override predicate isSink(DataFlow::Node sink) { none() }
|
override predicate isSink(DataFlow::Node sink) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `sink` is a relevant taint sink accepting `state`.
|
||||||
|
*
|
||||||
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
|
*/
|
||||||
|
// overridden to provide taint-tracking specific qldoc
|
||||||
|
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if the node `node` is a taint sanitizer. */
|
/** Holds if the node `node` is a taint sanitizer. */
|
||||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
@@ -79,9 +96,29 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
defaultTaintSanitizer(node)
|
defaultTaintSanitizer(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the node `node` is a taint sanitizer when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizer(node, state)
|
||||||
|
}
|
||||||
|
|
||||||
/** Holds if taint propagation into `node` is prohibited. */
|
/** Holds if taint propagation into `node` is prohibited. */
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint propagation into `node` is prohibited when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizerIn(node, state)
|
||||||
|
}
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
/** Holds if taint propagation out of `node` is prohibited. */
|
||||||
@@ -89,6 +126,16 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint propagation out of `node` is prohibited when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizerOut(node, state)
|
||||||
|
}
|
||||||
|
|
||||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -96,6 +143,16 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||||
|
* when the flow state is `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizerGuard(guard, state)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||||
* must be taken into account in the analysis.
|
* must be taken into account in the analysis.
|
||||||
@@ -107,6 +164,25 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
defaultAdditionalTaintStep(node1, node2)
|
defaultAdditionalTaintStep(node1, node2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||||
|
* must be taken into account in the analysis. This step is only applicable
|
||||||
|
* in `state1` and updates the flow state to `state2`.
|
||||||
|
*/
|
||||||
|
predicate isAdditionalTaintStep(
|
||||||
|
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||||
|
DataFlow::FlowState state2
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
final override predicate isAdditionalFlowStep(
|
||||||
|
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||||
|
DataFlow::FlowState state2
|
||||||
|
) {
|
||||||
|
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||||
|
}
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||||
defaultImplicitTaintRead(node, c)
|
defaultImplicitTaintRead(node, c)
|
||||||
|
|||||||
@@ -64,13 +64,30 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
override predicate isSource(DataFlow::Node source) { none() }
|
override predicate isSource(DataFlow::Node source) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `sink` is a relevant taint sink.
|
* Holds if `source` is a relevant taint source with the given initial
|
||||||
|
* `state`.
|
||||||
|
*
|
||||||
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
|
*/
|
||||||
|
// overridden to provide taint-tracking specific qldoc
|
||||||
|
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `sink` is a relevant taint sink
|
||||||
*
|
*
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
*/
|
*/
|
||||||
// overridden to provide taint-tracking specific qldoc
|
// overridden to provide taint-tracking specific qldoc
|
||||||
override predicate isSink(DataFlow::Node sink) { none() }
|
override predicate isSink(DataFlow::Node sink) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `sink` is a relevant taint sink accepting `state`.
|
||||||
|
*
|
||||||
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
|
*/
|
||||||
|
// overridden to provide taint-tracking specific qldoc
|
||||||
|
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if the node `node` is a taint sanitizer. */
|
/** Holds if the node `node` is a taint sanitizer. */
|
||||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
@@ -79,9 +96,29 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
defaultTaintSanitizer(node)
|
defaultTaintSanitizer(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the node `node` is a taint sanitizer when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizer(node, state)
|
||||||
|
}
|
||||||
|
|
||||||
/** Holds if taint propagation into `node` is prohibited. */
|
/** Holds if taint propagation into `node` is prohibited. */
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint propagation into `node` is prohibited when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizerIn(node, state)
|
||||||
|
}
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
/** Holds if taint propagation out of `node` is prohibited. */
|
||||||
@@ -89,6 +126,16 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint propagation out of `node` is prohibited when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizerOut(node, state)
|
||||||
|
}
|
||||||
|
|
||||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -96,6 +143,16 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||||
|
* when the flow state is `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizerGuard(guard, state)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||||
* must be taken into account in the analysis.
|
* must be taken into account in the analysis.
|
||||||
@@ -107,6 +164,25 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
defaultAdditionalTaintStep(node1, node2)
|
defaultAdditionalTaintStep(node1, node2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||||
|
* must be taken into account in the analysis. This step is only applicable
|
||||||
|
* in `state1` and updates the flow state to `state2`.
|
||||||
|
*/
|
||||||
|
predicate isAdditionalTaintStep(
|
||||||
|
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||||
|
DataFlow::FlowState state2
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
final override predicate isAdditionalFlowStep(
|
||||||
|
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||||
|
DataFlow::FlowState state2
|
||||||
|
) {
|
||||||
|
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||||
|
}
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||||
defaultImplicitTaintRead(node, c)
|
defaultImplicitTaintRead(node, c)
|
||||||
|
|||||||
@@ -64,13 +64,30 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
override predicate isSource(DataFlow::Node source) { none() }
|
override predicate isSource(DataFlow::Node source) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `sink` is a relevant taint sink.
|
* Holds if `source` is a relevant taint source with the given initial
|
||||||
|
* `state`.
|
||||||
|
*
|
||||||
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
|
*/
|
||||||
|
// overridden to provide taint-tracking specific qldoc
|
||||||
|
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `sink` is a relevant taint sink
|
||||||
*
|
*
|
||||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
*/
|
*/
|
||||||
// overridden to provide taint-tracking specific qldoc
|
// overridden to provide taint-tracking specific qldoc
|
||||||
override predicate isSink(DataFlow::Node sink) { none() }
|
override predicate isSink(DataFlow::Node sink) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `sink` is a relevant taint sink accepting `state`.
|
||||||
|
*
|
||||||
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
|
*/
|
||||||
|
// overridden to provide taint-tracking specific qldoc
|
||||||
|
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
/** Holds if the node `node` is a taint sanitizer. */
|
/** Holds if the node `node` is a taint sanitizer. */
|
||||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
@@ -79,9 +96,29 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
defaultTaintSanitizer(node)
|
defaultTaintSanitizer(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the node `node` is a taint sanitizer when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizer(node, state)
|
||||||
|
}
|
||||||
|
|
||||||
/** Holds if taint propagation into `node` is prohibited. */
|
/** Holds if taint propagation into `node` is prohibited. */
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint propagation into `node` is prohibited when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizerIn(node, state)
|
||||||
|
}
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
/** Holds if taint propagation out of `node` is prohibited. */
|
||||||
@@ -89,6 +126,16 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint propagation out of `node` is prohibited when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizerOut(node, state)
|
||||||
|
}
|
||||||
|
|
||||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -96,6 +143,16 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||||
|
* when the flow state is `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizerGuard(guard, state)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||||
* must be taken into account in the analysis.
|
* must be taken into account in the analysis.
|
||||||
@@ -107,6 +164,25 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
defaultAdditionalTaintStep(node1, node2)
|
defaultAdditionalTaintStep(node1, node2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||||
|
* must be taken into account in the analysis. This step is only applicable
|
||||||
|
* in `state1` and updates the flow state to `state2`.
|
||||||
|
*/
|
||||||
|
predicate isAdditionalTaintStep(
|
||||||
|
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||||
|
DataFlow::FlowState state2
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
final override predicate isAdditionalFlowStep(
|
||||||
|
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||||
|
DataFlow::FlowState state2
|
||||||
|
) {
|
||||||
|
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||||
|
}
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||||
defaultImplicitTaintRead(node, c)
|
defaultImplicitTaintRead(node, c)
|
||||||
|
|||||||
@@ -55,7 +55,10 @@ class IRVariable extends TIRVariable {
|
|||||||
* Gets the AST node that declared this variable, or that introduced this
|
* Gets the AST node that declared this variable, or that introduced this
|
||||||
* variable as part of the AST-to-IR translation.
|
* variable as part of the AST-to-IR translation.
|
||||||
*/
|
*/
|
||||||
Language::AST getAST() { none() }
|
Language::AST getAst() { none() }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated Language::AST getAST() { result = getAst() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an identifier string for the variable. This identifier is unique
|
* Gets an identifier string for the variable. This identifier is unique
|
||||||
@@ -66,7 +69,7 @@ class IRVariable extends TIRVariable {
|
|||||||
/**
|
/**
|
||||||
* Gets the source location of this variable.
|
* Gets the source location of this variable.
|
||||||
*/
|
*/
|
||||||
final Language::Location getLocation() { result = getAST().getLocation() }
|
final Language::Location getLocation() { result = getAst().getLocation() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the IR for the function that references this variable.
|
* Gets the IR for the function that references this variable.
|
||||||
@@ -90,7 +93,10 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
|||||||
|
|
||||||
final override string toString() { result = getVariable().toString() }
|
final override string toString() { result = getVariable().toString() }
|
||||||
|
|
||||||
final override Language::AST getAST() { result = var }
|
final override Language::AST getAst() { result = var }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated override Language::AST getAST() { result = getAst() }
|
||||||
|
|
||||||
final override string getUniqueId() {
|
final override string getUniqueId() {
|
||||||
result = getVariable().toString() + " " + getVariable().getLocation().toString()
|
result = getVariable().toString() + " " + getVariable().getLocation().toString()
|
||||||
@@ -157,7 +163,10 @@ class IRGeneratedVariable extends IRVariable {
|
|||||||
|
|
||||||
final override Language::LanguageType getLanguageType() { result = type }
|
final override Language::LanguageType getLanguageType() { result = type }
|
||||||
|
|
||||||
final override Language::AST getAST() { result = ast }
|
final override Language::AST getAst() { result = ast }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated override Language::AST getAST() { result = getAst() }
|
||||||
|
|
||||||
override string toString() { result = getBaseString() + getLocationString() }
|
override string toString() { result = getBaseString() + getLocationString() }
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class Instruction extends Construction::TStageInstruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a textual representation of this element. */
|
/** Gets a textual representation of this element. */
|
||||||
final string toString() { result = this.getOpcode().toString() + ": " + this.getAST().toString() }
|
final string toString() { result = this.getOpcode().toString() + ": " + this.getAst().toString() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a string showing the result, opcode, and operands of the instruction, equivalent to what
|
* Gets a string showing the result, opcode, and operands of the instruction, equivalent to what
|
||||||
@@ -136,7 +136,7 @@ class Instruction extends Construction::TStageInstruction {
|
|||||||
string getResultId() {
|
string getResultId() {
|
||||||
this.shouldGenerateDumpStrings() and
|
this.shouldGenerateDumpStrings() and
|
||||||
result =
|
result =
|
||||||
this.getResultPrefix() + this.getAST().getLocation().getStartLine() + "_" + this.getLineRank()
|
this.getResultPrefix() + this.getAst().getLocation().getStartLine() + "_" + this.getLineRank()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -208,12 +208,15 @@ class Instruction extends Construction::TStageInstruction {
|
|||||||
/**
|
/**
|
||||||
* Gets the AST that caused this instruction to be generated.
|
* Gets the AST that caused this instruction to be generated.
|
||||||
*/
|
*/
|
||||||
final Language::AST getAST() { result = Construction::getInstructionAST(this) }
|
final Language::AST getAst() { result = Construction::getInstructionAst(this) }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated Language::AST getAST() { result = this.getAst() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the location of the source code for this instruction.
|
* Gets the location of the source code for this instruction.
|
||||||
*/
|
*/
|
||||||
final Language::Location getLocation() { result = this.getAST().getLocation() }
|
final Language::Location getLocation() { result = this.getAst().getLocation() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the `Expr` whose result is computed by this instruction, if any. The `Expr` may be a
|
* Gets the `Expr` whose result is computed by this instruction, if any. The `Expr` may be a
|
||||||
@@ -459,7 +462,10 @@ class VariableInstruction extends Instruction {
|
|||||||
/**
|
/**
|
||||||
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
|
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
|
||||||
*/
|
*/
|
||||||
final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() }
|
final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAstVariable */
|
||||||
|
deprecated Language::Variable getASTVariable() { result = this.getAstVariable() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ private import internal.OperandInternal
|
|||||||
* of `TOperand` that are used in this stage.
|
* of `TOperand` that are used in this stage.
|
||||||
*/
|
*/
|
||||||
private class TStageOperand =
|
private class TStageOperand =
|
||||||
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
|
TRegisterOperand or TNonSsaMemoryOperand or TPhiOperand or TChiOperand;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as
|
* A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as
|
||||||
@@ -38,7 +38,7 @@ class Operand extends TStageOperand {
|
|||||||
// Ensure that the operand does not refer to instructions from earlier stages that are unreachable here
|
// Ensure that the operand does not refer to instructions from earlier stages that are unreachable here
|
||||||
exists(Instruction use, Instruction def | this = registerOperand(use, _, def))
|
exists(Instruction use, Instruction def | this = registerOperand(use, _, def))
|
||||||
or
|
or
|
||||||
exists(Instruction use | this = nonSSAMemoryOperand(use, _))
|
exists(Instruction use | this = nonSsaMemoryOperand(use, _))
|
||||||
or
|
or
|
||||||
exists(Instruction use, Instruction def, IRBlock predecessorBlock |
|
exists(Instruction use, Instruction def, IRBlock predecessorBlock |
|
||||||
this = phiOperand(use, def, predecessorBlock, _) or
|
this = phiOperand(use, def, predecessorBlock, _) or
|
||||||
@@ -209,7 +209,7 @@ class Operand extends TStageOperand {
|
|||||||
class MemoryOperand extends Operand {
|
class MemoryOperand extends Operand {
|
||||||
cached
|
cached
|
||||||
MemoryOperand() {
|
MemoryOperand() {
|
||||||
this instanceof TNonSSAMemoryOperand or
|
this instanceof TNonSsaMemoryOperand or
|
||||||
this instanceof TPhiOperand or
|
this instanceof TPhiOperand or
|
||||||
this instanceof TChiOperand
|
this instanceof TChiOperand
|
||||||
}
|
}
|
||||||
@@ -249,7 +249,7 @@ class NonPhiOperand extends Operand {
|
|||||||
|
|
||||||
NonPhiOperand() {
|
NonPhiOperand() {
|
||||||
this = registerOperand(useInstr, tag, _) or
|
this = registerOperand(useInstr, tag, _) or
|
||||||
this = nonSSAMemoryOperand(useInstr, tag) or
|
this = nonSsaMemoryOperand(useInstr, tag) or
|
||||||
this = chiOperand(useInstr, tag)
|
this = chiOperand(useInstr, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +299,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
|||||||
|
|
||||||
cached
|
cached
|
||||||
NonPhiMemoryOperand() {
|
NonPhiMemoryOperand() {
|
||||||
this = nonSSAMemoryOperand(useInstr, tag)
|
this = nonSsaMemoryOperand(useInstr, tag)
|
||||||
or
|
or
|
||||||
this = chiOperand(useInstr, tag)
|
this = chiOperand(useInstr, tag)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ private predicate filteredNumberableInstruction(Instruction instr) {
|
|||||||
// count rather than strictcount to handle missing AST elements
|
// count rather than strictcount to handle missing AST elements
|
||||||
// separate instanceof and inline casts to avoid failed casts with a count of 0
|
// separate instanceof and inline casts to avoid failed casts with a count of 0
|
||||||
instr instanceof VariableAddressInstruction and
|
instr instanceof VariableAddressInstruction and
|
||||||
count(instr.(VariableAddressInstruction).getIRVariable().getAST()) != 1
|
count(instr.(VariableAddressInstruction).getIRVariable().getAst()) != 1
|
||||||
or
|
or
|
||||||
instr instanceof ConstantInstruction and
|
instr instanceof ConstantInstruction and
|
||||||
count(instr.getResultIRType()) != 1
|
count(instr.getResultIRType()) != 1
|
||||||
@@ -121,7 +121,7 @@ private predicate variableAddressValueNumber(
|
|||||||
// The underlying AST element is used as value-numbering key instead of the
|
// The underlying AST element is used as value-numbering key instead of the
|
||||||
// `IRVariable` to work around a problem where a variable or expression with
|
// `IRVariable` to work around a problem where a variable or expression with
|
||||||
// multiple types gives rise to multiple `IRVariable`s.
|
// multiple types gives rise to multiple `IRVariable`s.
|
||||||
unique( | | instr.getIRVariable().getAST()) = ast
|
unique( | | instr.getIRVariable().getAst()) = ast
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate initializeParameterValueNumber(
|
private predicate initializeParameterValueNumber(
|
||||||
@@ -131,7 +131,7 @@ private predicate initializeParameterValueNumber(
|
|||||||
// The underlying AST element is used as value-numbering key instead of the
|
// The underlying AST element is used as value-numbering key instead of the
|
||||||
// `IRVariable` to work around a problem where a variable or expression with
|
// `IRVariable` to work around a problem where a variable or expression with
|
||||||
// multiple types gives rise to multiple `IRVariable`s.
|
// multiple types gives rise to multiple `IRVariable`s.
|
||||||
instr.getIRVariable().getAST() = var
|
instr.getIRVariable().getAst() = var
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate constantValueNumber(
|
private predicate constantValueNumber(
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ private import AliasConfigurationInternal
|
|||||||
private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR
|
private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR
|
||||||
private import cpp
|
private import cpp
|
||||||
private import AliasAnalysis
|
private import AliasAnalysis
|
||||||
private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SimpleSSA as UnaliasedSSA
|
private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SimpleSSA as UnaliasedSsa
|
||||||
|
|
||||||
private newtype TAllocation =
|
private newtype TAllocation =
|
||||||
TVariableAllocation(IRVariable var) {
|
TVariableAllocation(IRVariable var) {
|
||||||
// Only model variables that were not already handled in unaliased SSA.
|
// Only model variables that were not already handled in unaliased SSA.
|
||||||
not UnaliasedSSA::canReuseSSAForVariable(var)
|
not UnaliasedSsa::canReuseSsaForVariable(var)
|
||||||
} or
|
} or
|
||||||
TIndirectParameterAllocation(IRAutomaticVariable var) {
|
TIndirectParameterAllocation(IRAutomaticVariable var) {
|
||||||
exists(InitializeIndirectionInstruction instr | instr.getIRVariable() = var)
|
exists(InitializeIndirectionInstruction instr | instr.getIRVariable() = var)
|
||||||
|
|||||||
@@ -133,7 +133,10 @@ abstract class MemoryLocation extends TMemoryLocation {
|
|||||||
*/
|
*/
|
||||||
predicate isAlwaysAllocatedOnStack() { none() }
|
predicate isAlwaysAllocatedOnStack() { none() }
|
||||||
|
|
||||||
final predicate canReuseSSA() { none() }
|
final predicate canReuseSsa() { none() }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for canReuseSsa */
|
||||||
|
deprecated predicate canReuseSSA() { canReuseSsa() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -569,13 +572,16 @@ private Overlap getVariableMemoryLocationOverlap(
|
|||||||
* Holds if the def/use information for the result of `instr` can be reused from the previous
|
* Holds if the def/use information for the result of `instr` can be reused from the previous
|
||||||
* iteration of the IR.
|
* iteration of the IR.
|
||||||
*/
|
*/
|
||||||
predicate canReuseSSAForOldResult(Instruction instr) { OldSSA::canReuseSSAForMemoryResult(instr) }
|
predicate canReuseSsaForOldResult(Instruction instr) { OldSSA::canReuseSsaForMemoryResult(instr) }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for canReuseSsaForOldResult */
|
||||||
|
deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1;
|
||||||
|
|
||||||
bindingset[result, b]
|
bindingset[result, b]
|
||||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||||
|
|
||||||
MemoryLocation getResultMemoryLocation(Instruction instr) {
|
MemoryLocation getResultMemoryLocation(Instruction instr) {
|
||||||
not canReuseSSAForOldResult(instr) and
|
not canReuseSsaForOldResult(instr) and
|
||||||
exists(MemoryAccessKind kind, boolean isMayAccess |
|
exists(MemoryAccessKind kind, boolean isMayAccess |
|
||||||
kind = instr.getResultMemoryAccess() and
|
kind = instr.getResultMemoryAccess() and
|
||||||
(if instr.hasResultMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and
|
(if instr.hasResultMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and
|
||||||
@@ -608,7 +614,7 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
||||||
not canReuseSSAForOldResult(operand.getAnyDef()) and
|
not canReuseSsaForOldResult(operand.getAnyDef()) and
|
||||||
exists(MemoryAccessKind kind, boolean isMayAccess |
|
exists(MemoryAccessKind kind, boolean isMayAccess |
|
||||||
kind = operand.getMemoryAccess() and
|
kind = operand.getMemoryAccess() and
|
||||||
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
|
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
private import semmle.code.cpp.ir.implementation.internal.TOperand
|
private import semmle.code.cpp.ir.implementation.internal.TOperand
|
||||||
import AliasedSSAOperands
|
import AliasedSsaOperands
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ private import SSAConstructionInternal
|
|||||||
private import OldIR
|
private import OldIR
|
||||||
private import Alias
|
private import Alias
|
||||||
private import SSAConstruction
|
private import SSAConstruction
|
||||||
private import DebugSSA
|
private import DebugSsa
|
||||||
|
|
||||||
bindingset[offset]
|
bindingset[offset]
|
||||||
private string getKeySuffixForOffset(int offset) {
|
private string getKeySuffixForOffset(int offset) {
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
private import SSAConstruction as SSA
|
private import SSAConstruction as SSA
|
||||||
import SSA::SSAConsistency
|
import SSA::SsaConsistency
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ private module Cached {
|
|||||||
exists(Alias::getResultMemoryLocation(oldInstruction))
|
exists(Alias::getResultMemoryLocation(oldInstruction))
|
||||||
or
|
or
|
||||||
// This result was already modeled by a previous iteration of SSA.
|
// This result was already modeled by a previous iteration of SSA.
|
||||||
Alias::canReuseSSAForOldResult(oldInstruction)
|
Alias::canReuseSsaForOldResult(oldInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
@@ -182,7 +182,7 @@ private module Cached {
|
|||||||
* unreachable, this predicate will recurse through any degenerate `Phi` instructions to find the
|
* unreachable, this predicate will recurse through any degenerate `Phi` instructions to find the
|
||||||
* true definition.
|
* true definition.
|
||||||
*/
|
*/
|
||||||
private Instruction getNewDefinitionFromOldSSA(OldIR::MemoryOperand oldOperand, Overlap overlap) {
|
private Instruction getNewDefinitionFromOldSsa(OldIR::MemoryOperand oldOperand, Overlap overlap) {
|
||||||
exists(Overlap originalOverlap |
|
exists(Overlap originalOverlap |
|
||||||
originalOverlap = oldOperand.getDefinitionOverlap() and
|
originalOverlap = oldOperand.getDefinitionOverlap() and
|
||||||
(
|
(
|
||||||
@@ -191,7 +191,7 @@ private module Cached {
|
|||||||
or
|
or
|
||||||
exists(OldIR::PhiInputOperand phiOperand, Overlap phiOperandOverlap |
|
exists(OldIR::PhiInputOperand phiOperand, Overlap phiOperandOverlap |
|
||||||
phiOperand = getDegeneratePhiOperand(oldOperand.getAnyDef()) and
|
phiOperand = getDegeneratePhiOperand(oldOperand.getAnyDef()) and
|
||||||
result = getNewDefinitionFromOldSSA(phiOperand, phiOperandOverlap) and
|
result = getNewDefinitionFromOldSsa(phiOperand, phiOperandOverlap) and
|
||||||
overlap =
|
overlap =
|
||||||
combineOverlap(pragma[only_bind_out](phiOperandOverlap),
|
combineOverlap(pragma[only_bind_out](phiOperandOverlap),
|
||||||
pragma[only_bind_out](originalOverlap))
|
pragma[only_bind_out](originalOverlap))
|
||||||
@@ -233,7 +233,7 @@ private module Cached {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(OldIR::NonPhiMemoryOperand oldOperand |
|
exists(OldIR::NonPhiMemoryOperand oldOperand |
|
||||||
result = getNewDefinitionFromOldSSA(oldOperand, overlap) and
|
result = getNewDefinitionFromOldSsa(oldOperand, overlap) and
|
||||||
oldOperand.getUse() = instruction and
|
oldOperand.getUse() = instruction and
|
||||||
tag = oldOperand.getOperandTag()
|
tag = oldOperand.getOperandTag()
|
||||||
)
|
)
|
||||||
@@ -307,13 +307,13 @@ private module Cached {
|
|||||||
* Gets the new definition instruction for the operand of `instr` that flows from the block
|
* Gets the new definition instruction for the operand of `instr` that flows from the block
|
||||||
* `newPredecessorBlock`, based on that operand's definition in the old IR.
|
* `newPredecessorBlock`, based on that operand's definition in the old IR.
|
||||||
*/
|
*/
|
||||||
private Instruction getNewPhiOperandDefinitionFromOldSSA(
|
private Instruction getNewPhiOperandDefinitionFromOldSsa(
|
||||||
Instruction instr, IRBlock newPredecessorBlock, Overlap overlap
|
Instruction instr, IRBlock newPredecessorBlock, Overlap overlap
|
||||||
) {
|
) {
|
||||||
exists(OldIR::PhiInstruction oldPhi, OldIR::PhiInputOperand oldOperand |
|
exists(OldIR::PhiInstruction oldPhi, OldIR::PhiInputOperand oldOperand |
|
||||||
oldPhi = getOldInstruction(instr) and
|
oldPhi = getOldInstruction(instr) and
|
||||||
oldOperand = oldPhi.getInputOperand(getOldBlock(newPredecessorBlock)) and
|
oldOperand = oldPhi.getInputOperand(getOldBlock(newPredecessorBlock)) and
|
||||||
result = getNewDefinitionFromOldSSA(oldOperand, overlap)
|
result = getNewDefinitionFromOldSsa(oldOperand, overlap)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +333,7 @@ private module Cached {
|
|||||||
overlap = Alias::getOverlap(actualDefLocation, useLocation)
|
overlap = Alias::getOverlap(actualDefLocation, useLocation)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
result = getNewPhiOperandDefinitionFromOldSSA(instr, newPredecessorBlock, overlap)
|
result = getNewPhiOperandDefinitionFromOldSsa(instr, newPredecessorBlock, overlap)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
@@ -412,17 +412,17 @@ private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
Language::AST getInstructionAST(Instruction instr) {
|
Language::AST getInstructionAst(Instruction instr) {
|
||||||
result = getOldInstruction(instr).getAST()
|
result = getOldInstruction(instr).getAst()
|
||||||
or
|
or
|
||||||
exists(RawIR::Instruction blockStartInstr |
|
exists(RawIR::Instruction blockStartInstr |
|
||||||
instr = phiInstruction(blockStartInstr, _) and
|
instr = phiInstruction(blockStartInstr, _) and
|
||||||
result = blockStartInstr.getAST()
|
result = blockStartInstr.getAst()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(RawIR::Instruction primaryInstr |
|
exists(RawIR::Instruction primaryInstr |
|
||||||
instr = chiInstruction(primaryInstr) and
|
instr = chiInstruction(primaryInstr) and
|
||||||
result = primaryInstr.getAST()
|
result = primaryInstr.getAst()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(IRFunctionBase irFunc |
|
exists(IRFunctionBase irFunc |
|
||||||
@@ -430,6 +430,12 @@ private module Cached {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getInstructionAst */
|
||||||
|
cached
|
||||||
|
deprecated Language::AST getInstructionAST(Instruction instr) {
|
||||||
|
result = getInstructionAst(instr)
|
||||||
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
Language::LanguageType getInstructionResultType(Instruction instr) {
|
Language::LanguageType getInstructionResultType(Instruction instr) {
|
||||||
result = instr.(RawIR::Instruction).getResultLanguageType()
|
result = instr.(RawIR::Instruction).getResultLanguageType()
|
||||||
@@ -975,35 +981,41 @@ module DefUse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate canReuseSSAForMemoryResult(Instruction instruction) {
|
predicate canReuseSsaForMemoryResult(Instruction instruction) {
|
||||||
exists(OldInstruction oldInstruction |
|
exists(OldInstruction oldInstruction |
|
||||||
oldInstruction = getOldInstruction(instruction) and
|
oldInstruction = getOldInstruction(instruction) and
|
||||||
(
|
(
|
||||||
// The previous iteration said it was reusable, so we should mark it as reusable as well.
|
// The previous iteration said it was reusable, so we should mark it as reusable as well.
|
||||||
Alias::canReuseSSAForOldResult(oldInstruction)
|
Alias::canReuseSsaForOldResult(oldInstruction)
|
||||||
or
|
or
|
||||||
// The current alias analysis says it is reusable.
|
// The current alias analysis says it is reusable.
|
||||||
Alias::getResultMemoryLocation(oldInstruction).canReuseSSA()
|
Alias::getResultMemoryLocation(oldInstruction).canReuseSsa()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(Alias::MemoryLocation defLocation |
|
exists(Alias::MemoryLocation defLocation |
|
||||||
// This is a `Phi` for a reusable location, so the result of the `Phi` is reusable as well.
|
// This is a `Phi` for a reusable location, so the result of the `Phi` is reusable as well.
|
||||||
instruction = phiInstruction(_, defLocation) and
|
instruction = phiInstruction(_, defLocation) and
|
||||||
defLocation.canReuseSSA()
|
defLocation.canReuseSsa()
|
||||||
)
|
)
|
||||||
// We don't support reusing SSA for any location that could create a `Chi` instruction.
|
// We don't support reusing SSA for any location that could create a `Chi` instruction.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for canReuseSsaForMemoryResult */
|
||||||
|
deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expose some of the internal predicates to PrintSSA.qll. We do this by publically importing those modules in the
|
* Expose some of the internal predicates to PrintSSA.qll. We do this by publically importing those modules in the
|
||||||
* `DebugSSA` module, which is then imported by PrintSSA.
|
* `DebugSSA` module, which is then imported by PrintSSA.
|
||||||
*/
|
*/
|
||||||
module DebugSSA {
|
module DebugSsa {
|
||||||
import PhiInsertion
|
import PhiInsertion
|
||||||
import DefUse
|
import DefUse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for DebugSsa */
|
||||||
|
deprecated module DebugSSA = DebugSsa;
|
||||||
|
|
||||||
import CachedForDebugging
|
import CachedForDebugging
|
||||||
|
|
||||||
cached
|
cached
|
||||||
@@ -1038,7 +1050,7 @@ private module CachedForDebugging {
|
|||||||
|
|
||||||
private OldIR::IRTempVariable getOldTempVariable(IRTempVariable var) {
|
private OldIR::IRTempVariable getOldTempVariable(IRTempVariable var) {
|
||||||
result.getEnclosingFunction() = var.getEnclosingFunction() and
|
result.getEnclosingFunction() = var.getEnclosingFunction() and
|
||||||
result.getAST() = var.getAST() and
|
result.getAst() = var.getAst() and
|
||||||
result.getTag() = var.getTag()
|
result.getTag() = var.getTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1061,7 +1073,7 @@ private module CachedForDebugging {
|
|||||||
int maxValue() { result = 2147483647 }
|
int maxValue() { result = 2147483647 }
|
||||||
}
|
}
|
||||||
|
|
||||||
module SSAConsistency {
|
module SsaConsistency {
|
||||||
/**
|
/**
|
||||||
* Holds if a `MemoryOperand` has more than one `MemoryLocation` assigned by alias analysis.
|
* Holds if a `MemoryOperand` has more than one `MemoryLocation` assigned by alias analysis.
|
||||||
*/
|
*/
|
||||||
@@ -1114,6 +1126,9 @@ module SSAConsistency {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for SsaConsistency */
|
||||||
|
deprecated module SSAConsistency = SsaConsistency;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the portion of the parameterized IR interface that is used to construct the SSA stages
|
* Provides the portion of the parameterized IR interface that is used to construct the SSA stages
|
||||||
* of the IR. The raw stage of the IR does not expose these predicates.
|
* of the IR. The raw stage of the IR does not expose these predicates.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as OldIR
|
|||||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability
|
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability
|
||||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance
|
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance
|
||||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
|
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
|
||||||
import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSSAInstructions as SSAInstructions
|
import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSsaInstructions as SSAInstructions
|
||||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
import AliasedSSA as Alias
|
import AliasedSSA as Alias
|
||||||
import semmle.code.cpp.ir.implementation.internal.TOperand::AliasedSSAOperands as SSAOperands
|
import semmle.code.cpp.ir.implementation.internal.TOperand::AliasedSsaOperands as SSAOperands
|
||||||
|
|||||||
@@ -19,24 +19,24 @@ newtype TInstruction =
|
|||||||
) {
|
) {
|
||||||
IRConstruction::Raw::hasInstruction(tag1, tag2)
|
IRConstruction::Raw::hasInstruction(tag1, tag2)
|
||||||
} or
|
} or
|
||||||
TUnaliasedSSAPhiInstruction(
|
TUnaliasedSsaPhiInstruction(
|
||||||
TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation
|
TRawInstruction blockStartInstr, UnaliasedSsa::SSA::MemoryLocation memoryLocation
|
||||||
) {
|
) {
|
||||||
UnaliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
UnaliasedSsa::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
||||||
} or
|
} or
|
||||||
TUnaliasedSSAChiInstruction(TRawInstruction primaryInstruction) { none() } or
|
TUnaliasedSsaChiInstruction(TRawInstruction primaryInstruction) { none() } or
|
||||||
TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) {
|
TUnaliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
|
||||||
UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc)
|
UnaliasedSsa::SSA::hasUnreachedInstruction(irFunc)
|
||||||
} or
|
} or
|
||||||
TAliasedSSAPhiInstruction(
|
TAliasedSsaPhiInstruction(
|
||||||
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
|
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
|
||||||
) {
|
) {
|
||||||
AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
||||||
} or
|
} or
|
||||||
TAliasedSSAChiInstruction(TRawInstruction primaryInstruction) {
|
TAliasedSsaChiInstruction(TRawInstruction primaryInstruction) {
|
||||||
AliasedSSA::SSA::hasChiInstruction(primaryInstruction)
|
AliasedSSA::SSA::hasChiInstruction(primaryInstruction)
|
||||||
} or
|
} or
|
||||||
TAliasedSSAUnreachedInstruction(IRFunctionBase irFunc) {
|
TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
|
||||||
AliasedSSA::SSA::hasUnreachedInstruction(irFunc)
|
AliasedSSA::SSA::hasUnreachedInstruction(irFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,58 +46,64 @@ newtype TInstruction =
|
|||||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||||
* a class alias.
|
* a class alias.
|
||||||
*/
|
*/
|
||||||
module UnaliasedSSAInstructions {
|
module UnaliasedSsaInstructions {
|
||||||
class TPhiInstruction = TUnaliasedSSAPhiInstruction;
|
class TPhiInstruction = TUnaliasedSsaPhiInstruction;
|
||||||
|
|
||||||
TPhiInstruction phiInstruction(
|
TPhiInstruction phiInstruction(
|
||||||
TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation
|
TRawInstruction blockStartInstr, UnaliasedSsa::SSA::MemoryLocation memoryLocation
|
||||||
) {
|
) {
|
||||||
result = TUnaliasedSSAPhiInstruction(blockStartInstr, memoryLocation)
|
result = TUnaliasedSsaPhiInstruction(blockStartInstr, memoryLocation)
|
||||||
}
|
}
|
||||||
|
|
||||||
TRawInstruction reusedPhiInstruction(TRawInstruction blockStartInstr) { none() }
|
TRawInstruction reusedPhiInstruction(TRawInstruction blockStartInstr) { none() }
|
||||||
|
|
||||||
class TChiInstruction = TUnaliasedSSAChiInstruction;
|
class TChiInstruction = TUnaliasedSsaChiInstruction;
|
||||||
|
|
||||||
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
|
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
|
||||||
result = TUnaliasedSSAChiInstruction(primaryInstruction)
|
result = TUnaliasedSsaChiInstruction(primaryInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
class TUnreachedInstruction = TUnaliasedSSAUnreachedInstruction;
|
class TUnreachedInstruction = TUnaliasedSsaUnreachedInstruction;
|
||||||
|
|
||||||
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
|
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
|
||||||
result = TUnaliasedSSAUnreachedInstruction(irFunc)
|
result = TUnaliasedSsaUnreachedInstruction(irFunc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for UnaliasedSsaInstructions */
|
||||||
|
deprecated module UnaliasedSSAInstructions = UnaliasedSsaInstructions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides wrappers for the constructors of each branch of `TInstruction` that is used by the
|
* Provides wrappers for the constructors of each branch of `TInstruction` that is used by the
|
||||||
* aliased SSA stage.
|
* aliased SSA stage.
|
||||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||||
* a class alias.
|
* a class alias.
|
||||||
*/
|
*/
|
||||||
module AliasedSSAInstructions {
|
module AliasedSsaInstructions {
|
||||||
class TPhiInstruction = TAliasedSSAPhiInstruction or TUnaliasedSSAPhiInstruction;
|
class TPhiInstruction = TAliasedSsaPhiInstruction or TUnaliasedSsaPhiInstruction;
|
||||||
|
|
||||||
TPhiInstruction phiInstruction(
|
TPhiInstruction phiInstruction(
|
||||||
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
|
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
|
||||||
) {
|
) {
|
||||||
result = TAliasedSSAPhiInstruction(blockStartInstr, memoryLocation)
|
result = TAliasedSsaPhiInstruction(blockStartInstr, memoryLocation)
|
||||||
}
|
}
|
||||||
|
|
||||||
TPhiInstruction reusedPhiInstruction(TRawInstruction blockStartInstr) {
|
TPhiInstruction reusedPhiInstruction(TRawInstruction blockStartInstr) {
|
||||||
result = TUnaliasedSSAPhiInstruction(blockStartInstr, _)
|
result = TUnaliasedSsaPhiInstruction(blockStartInstr, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
class TChiInstruction = TAliasedSSAChiInstruction;
|
class TChiInstruction = TAliasedSsaChiInstruction;
|
||||||
|
|
||||||
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
|
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
|
||||||
result = TAliasedSSAChiInstruction(primaryInstruction)
|
result = TAliasedSsaChiInstruction(primaryInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
class TUnreachedInstruction = TAliasedSSAUnreachedInstruction;
|
class TUnreachedInstruction = TAliasedSsaUnreachedInstruction;
|
||||||
|
|
||||||
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
|
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
|
||||||
result = TAliasedSSAUnreachedInstruction(irFunc)
|
result = TAliasedSsaUnreachedInstruction(irFunc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for AliasedSsaInstructions */
|
||||||
|
deprecated module AliasedSSAInstructions = AliasedSsaInstructions;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSSA
|
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSsa
|
||||||
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSSA
|
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSSA
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ private module Internal {
|
|||||||
TNoOperand() { none() } or
|
TNoOperand() { none() } or
|
||||||
// Can be "removed" later when there's unreachable code
|
// Can be "removed" later when there's unreachable code
|
||||||
// These operands can be reused across all three stages. They just get different defs.
|
// These operands can be reused across all three stages. They just get different defs.
|
||||||
TNonSSAMemoryOperand(Raw::Instruction useInstr, MemoryOperandTag tag) {
|
TNonSsaMemoryOperand(Raw::Instruction useInstr, MemoryOperandTag tag) {
|
||||||
// Has no definition in raw but will get definitions later
|
// Has no definition in raw but will get definitions later
|
||||||
useInstr.getOpcode().hasOperand(tag)
|
useInstr.getOpcode().hasOperand(tag)
|
||||||
} or
|
} or
|
||||||
@@ -49,11 +49,11 @@ private module Internal {
|
|||||||
// important that we use the same definition of "is variable aliased" across
|
// important that we use the same definition of "is variable aliased" across
|
||||||
// the phases.
|
// the phases.
|
||||||
TAliasedPhiOperand(
|
TAliasedPhiOperand(
|
||||||
TAliasedSSAPhiInstruction useInstr, Aliased::IRBlock predecessorBlock, Overlap overlap
|
TAliasedSsaPhiInstruction useInstr, Aliased::IRBlock predecessorBlock, Overlap overlap
|
||||||
) {
|
) {
|
||||||
exists(AliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap))
|
exists(AliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap))
|
||||||
} or
|
} or
|
||||||
TAliasedChiOperand(TAliasedSSAChiInstruction useInstr, ChiOperandTag tag) { any() }
|
TAliasedChiOperand(TAliasedSsaChiInstruction useInstr, ChiOperandTag tag) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,13 +72,21 @@ private module Shared {
|
|||||||
result = Internal::TRegisterOperand(useInstr, tag, defInstr)
|
result = Internal::TRegisterOperand(useInstr, tag, defInstr)
|
||||||
}
|
}
|
||||||
|
|
||||||
class TNonSSAMemoryOperand = Internal::TNonSSAMemoryOperand;
|
class TNonSsaMemoryOperand = Internal::TNonSsaMemoryOperand;
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for TNonSsaMemoryOperand */
|
||||||
|
deprecated class TNonSSAMemoryOperand = TNonSsaMemoryOperand;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the non-Phi memory operand with the specified parameters.
|
* Returns the non-Phi memory operand with the specified parameters.
|
||||||
*/
|
*/
|
||||||
TNonSSAMemoryOperand nonSSAMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) {
|
TNonSsaMemoryOperand nonSsaMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) {
|
||||||
result = Internal::TNonSSAMemoryOperand(useInstr, tag)
|
result = Internal::TNonSsaMemoryOperand(useInstr, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for nonSsaMemoryOperand */
|
||||||
|
deprecated TNonSSAMemoryOperand nonSSAMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) {
|
||||||
|
result = nonSsaMemoryOperand(useInstr, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +103,7 @@ module RawOperands {
|
|||||||
|
|
||||||
class TChiOperand = Internal::TNoOperand;
|
class TChiOperand = Internal::TNoOperand;
|
||||||
|
|
||||||
class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand;
|
class TNonPhiMemoryOperand = TNonSsaMemoryOperand or TChiOperand;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Phi operand with the specified parameters.
|
* Returns the Phi operand with the specified parameters.
|
||||||
@@ -126,14 +134,14 @@ module RawOperands {
|
|||||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||||
* a class alias.
|
* a class alias.
|
||||||
*/
|
*/
|
||||||
module UnaliasedSSAOperands {
|
module UnaliasedSsaOperands {
|
||||||
import Shared
|
import Shared
|
||||||
|
|
||||||
class TPhiOperand = Internal::TUnaliasedPhiOperand;
|
class TPhiOperand = Internal::TUnaliasedPhiOperand;
|
||||||
|
|
||||||
class TChiOperand = Internal::TNoOperand;
|
class TChiOperand = Internal::TNoOperand;
|
||||||
|
|
||||||
class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand;
|
class TNonPhiMemoryOperand = TNonSsaMemoryOperand or TChiOperand;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Phi operand with the specified parameters.
|
* Returns the Phi operand with the specified parameters.
|
||||||
@@ -159,20 +167,23 @@ module UnaliasedSSAOperands {
|
|||||||
TChiOperand chiOperand(Unaliased::Instruction useInstr, ChiOperandTag tag) { none() }
|
TChiOperand chiOperand(Unaliased::Instruction useInstr, ChiOperandTag tag) { none() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for UnaliasedSsaOperands */
|
||||||
|
deprecated module UnaliasedSSAOperands = UnaliasedSsaOperands;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides wrappers for the constructors of each branch of `TOperand` that is used by the
|
* Provides wrappers for the constructors of each branch of `TOperand` that is used by the
|
||||||
* asliased SSA stage.
|
* asliased SSA stage.
|
||||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||||
* a class alias.
|
* a class alias.
|
||||||
*/
|
*/
|
||||||
module AliasedSSAOperands {
|
module AliasedSsaOperands {
|
||||||
import Shared
|
import Shared
|
||||||
|
|
||||||
class TPhiOperand = Internal::TAliasedPhiOperand or Internal::TUnaliasedPhiOperand;
|
class TPhiOperand = Internal::TAliasedPhiOperand or Internal::TUnaliasedPhiOperand;
|
||||||
|
|
||||||
class TChiOperand = Internal::TAliasedChiOperand;
|
class TChiOperand = Internal::TAliasedChiOperand;
|
||||||
|
|
||||||
class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand;
|
class TNonPhiMemoryOperand = TNonSsaMemoryOperand or TChiOperand;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Phi operand with the specified parameters.
|
* Returns the Phi operand with the specified parameters.
|
||||||
@@ -202,7 +213,10 @@ module AliasedSSAOperands {
|
|||||||
/**
|
/**
|
||||||
* Returns the Chi operand with the specified parameters.
|
* Returns the Chi operand with the specified parameters.
|
||||||
*/
|
*/
|
||||||
TChiOperand chiOperand(TAliasedSSAChiInstruction useInstr, ChiOperandTag tag) {
|
TChiOperand chiOperand(TAliasedSsaChiInstruction useInstr, ChiOperandTag tag) {
|
||||||
result = Internal::TAliasedChiOperand(useInstr, tag)
|
result = Internal::TAliasedChiOperand(useInstr, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for AliasedSsaOperands */
|
||||||
|
deprecated module AliasedSSAOperands = AliasedSsaOperands;
|
||||||
|
|||||||
@@ -55,7 +55,10 @@ class IRVariable extends TIRVariable {
|
|||||||
* Gets the AST node that declared this variable, or that introduced this
|
* Gets the AST node that declared this variable, or that introduced this
|
||||||
* variable as part of the AST-to-IR translation.
|
* variable as part of the AST-to-IR translation.
|
||||||
*/
|
*/
|
||||||
Language::AST getAST() { none() }
|
Language::AST getAst() { none() }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated Language::AST getAST() { result = getAst() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an identifier string for the variable. This identifier is unique
|
* Gets an identifier string for the variable. This identifier is unique
|
||||||
@@ -66,7 +69,7 @@ class IRVariable extends TIRVariable {
|
|||||||
/**
|
/**
|
||||||
* Gets the source location of this variable.
|
* Gets the source location of this variable.
|
||||||
*/
|
*/
|
||||||
final Language::Location getLocation() { result = getAST().getLocation() }
|
final Language::Location getLocation() { result = getAst().getLocation() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the IR for the function that references this variable.
|
* Gets the IR for the function that references this variable.
|
||||||
@@ -90,7 +93,10 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
|||||||
|
|
||||||
final override string toString() { result = getVariable().toString() }
|
final override string toString() { result = getVariable().toString() }
|
||||||
|
|
||||||
final override Language::AST getAST() { result = var }
|
final override Language::AST getAst() { result = var }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated override Language::AST getAST() { result = getAst() }
|
||||||
|
|
||||||
final override string getUniqueId() {
|
final override string getUniqueId() {
|
||||||
result = getVariable().toString() + " " + getVariable().getLocation().toString()
|
result = getVariable().toString() + " " + getVariable().getLocation().toString()
|
||||||
@@ -157,7 +163,10 @@ class IRGeneratedVariable extends IRVariable {
|
|||||||
|
|
||||||
final override Language::LanguageType getLanguageType() { result = type }
|
final override Language::LanguageType getLanguageType() { result = type }
|
||||||
|
|
||||||
final override Language::AST getAST() { result = ast }
|
final override Language::AST getAst() { result = ast }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated override Language::AST getAST() { result = getAst() }
|
||||||
|
|
||||||
override string toString() { result = getBaseString() + getLocationString() }
|
override string toString() { result = getBaseString() + getLocationString() }
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class Instruction extends Construction::TStageInstruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a textual representation of this element. */
|
/** Gets a textual representation of this element. */
|
||||||
final string toString() { result = this.getOpcode().toString() + ": " + this.getAST().toString() }
|
final string toString() { result = this.getOpcode().toString() + ": " + this.getAst().toString() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a string showing the result, opcode, and operands of the instruction, equivalent to what
|
* Gets a string showing the result, opcode, and operands of the instruction, equivalent to what
|
||||||
@@ -136,7 +136,7 @@ class Instruction extends Construction::TStageInstruction {
|
|||||||
string getResultId() {
|
string getResultId() {
|
||||||
this.shouldGenerateDumpStrings() and
|
this.shouldGenerateDumpStrings() and
|
||||||
result =
|
result =
|
||||||
this.getResultPrefix() + this.getAST().getLocation().getStartLine() + "_" + this.getLineRank()
|
this.getResultPrefix() + this.getAst().getLocation().getStartLine() + "_" + this.getLineRank()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -208,12 +208,15 @@ class Instruction extends Construction::TStageInstruction {
|
|||||||
/**
|
/**
|
||||||
* Gets the AST that caused this instruction to be generated.
|
* Gets the AST that caused this instruction to be generated.
|
||||||
*/
|
*/
|
||||||
final Language::AST getAST() { result = Construction::getInstructionAST(this) }
|
final Language::AST getAst() { result = Construction::getInstructionAst(this) }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated Language::AST getAST() { result = this.getAst() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the location of the source code for this instruction.
|
* Gets the location of the source code for this instruction.
|
||||||
*/
|
*/
|
||||||
final Language::Location getLocation() { result = this.getAST().getLocation() }
|
final Language::Location getLocation() { result = this.getAst().getLocation() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the `Expr` whose result is computed by this instruction, if any. The `Expr` may be a
|
* Gets the `Expr` whose result is computed by this instruction, if any. The `Expr` may be a
|
||||||
@@ -459,7 +462,10 @@ class VariableInstruction extends Instruction {
|
|||||||
/**
|
/**
|
||||||
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
|
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
|
||||||
*/
|
*/
|
||||||
final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() }
|
final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAstVariable */
|
||||||
|
deprecated Language::Variable getASTVariable() { result = this.getAstVariable() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ private import internal.OperandInternal
|
|||||||
* of `TOperand` that are used in this stage.
|
* of `TOperand` that are used in this stage.
|
||||||
*/
|
*/
|
||||||
private class TStageOperand =
|
private class TStageOperand =
|
||||||
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
|
TRegisterOperand or TNonSsaMemoryOperand or TPhiOperand or TChiOperand;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as
|
* A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as
|
||||||
@@ -38,7 +38,7 @@ class Operand extends TStageOperand {
|
|||||||
// Ensure that the operand does not refer to instructions from earlier stages that are unreachable here
|
// Ensure that the operand does not refer to instructions from earlier stages that are unreachable here
|
||||||
exists(Instruction use, Instruction def | this = registerOperand(use, _, def))
|
exists(Instruction use, Instruction def | this = registerOperand(use, _, def))
|
||||||
or
|
or
|
||||||
exists(Instruction use | this = nonSSAMemoryOperand(use, _))
|
exists(Instruction use | this = nonSsaMemoryOperand(use, _))
|
||||||
or
|
or
|
||||||
exists(Instruction use, Instruction def, IRBlock predecessorBlock |
|
exists(Instruction use, Instruction def, IRBlock predecessorBlock |
|
||||||
this = phiOperand(use, def, predecessorBlock, _) or
|
this = phiOperand(use, def, predecessorBlock, _) or
|
||||||
@@ -209,7 +209,7 @@ class Operand extends TStageOperand {
|
|||||||
class MemoryOperand extends Operand {
|
class MemoryOperand extends Operand {
|
||||||
cached
|
cached
|
||||||
MemoryOperand() {
|
MemoryOperand() {
|
||||||
this instanceof TNonSSAMemoryOperand or
|
this instanceof TNonSsaMemoryOperand or
|
||||||
this instanceof TPhiOperand or
|
this instanceof TPhiOperand or
|
||||||
this instanceof TChiOperand
|
this instanceof TChiOperand
|
||||||
}
|
}
|
||||||
@@ -249,7 +249,7 @@ class NonPhiOperand extends Operand {
|
|||||||
|
|
||||||
NonPhiOperand() {
|
NonPhiOperand() {
|
||||||
this = registerOperand(useInstr, tag, _) or
|
this = registerOperand(useInstr, tag, _) or
|
||||||
this = nonSSAMemoryOperand(useInstr, tag) or
|
this = nonSsaMemoryOperand(useInstr, tag) or
|
||||||
this = chiOperand(useInstr, tag)
|
this = chiOperand(useInstr, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +299,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
|||||||
|
|
||||||
cached
|
cached
|
||||||
NonPhiMemoryOperand() {
|
NonPhiMemoryOperand() {
|
||||||
this = nonSSAMemoryOperand(useInstr, tag)
|
this = nonSsaMemoryOperand(useInstr, tag)
|
||||||
or
|
or
|
||||||
this = chiOperand(useInstr, tag)
|
this = chiOperand(useInstr, tag)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ private predicate filteredNumberableInstruction(Instruction instr) {
|
|||||||
// count rather than strictcount to handle missing AST elements
|
// count rather than strictcount to handle missing AST elements
|
||||||
// separate instanceof and inline casts to avoid failed casts with a count of 0
|
// separate instanceof and inline casts to avoid failed casts with a count of 0
|
||||||
instr instanceof VariableAddressInstruction and
|
instr instanceof VariableAddressInstruction and
|
||||||
count(instr.(VariableAddressInstruction).getIRVariable().getAST()) != 1
|
count(instr.(VariableAddressInstruction).getIRVariable().getAst()) != 1
|
||||||
or
|
or
|
||||||
instr instanceof ConstantInstruction and
|
instr instanceof ConstantInstruction and
|
||||||
count(instr.getResultIRType()) != 1
|
count(instr.getResultIRType()) != 1
|
||||||
@@ -121,7 +121,7 @@ private predicate variableAddressValueNumber(
|
|||||||
// The underlying AST element is used as value-numbering key instead of the
|
// The underlying AST element is used as value-numbering key instead of the
|
||||||
// `IRVariable` to work around a problem where a variable or expression with
|
// `IRVariable` to work around a problem where a variable or expression with
|
||||||
// multiple types gives rise to multiple `IRVariable`s.
|
// multiple types gives rise to multiple `IRVariable`s.
|
||||||
unique( | | instr.getIRVariable().getAST()) = ast
|
unique( | | instr.getIRVariable().getAst()) = ast
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate initializeParameterValueNumber(
|
private predicate initializeParameterValueNumber(
|
||||||
@@ -131,7 +131,7 @@ private predicate initializeParameterValueNumber(
|
|||||||
// The underlying AST element is used as value-numbering key instead of the
|
// The underlying AST element is used as value-numbering key instead of the
|
||||||
// `IRVariable` to work around a problem where a variable or expression with
|
// `IRVariable` to work around a problem where a variable or expression with
|
||||||
// multiple types gives rise to multiple `IRVariable`s.
|
// multiple types gives rise to multiple `IRVariable`s.
|
||||||
instr.getIRVariable().getAST() = var
|
instr.getIRVariable().getAst() = var
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate constantValueNumber(
|
private predicate constantValueNumber(
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ module Raw {
|
|||||||
cached
|
cached
|
||||||
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, CppType type) {
|
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, CppType type) {
|
||||||
exists(TranslatedElement element |
|
exists(TranslatedElement element |
|
||||||
element.getAST() = ast and
|
element.getAst() = ast and
|
||||||
func = element.getFunction() and
|
func = element.getFunction() and
|
||||||
element.hasTempVariable(tag, type)
|
element.hasTempVariable(tag, type)
|
||||||
)
|
)
|
||||||
@@ -75,7 +75,7 @@ module Raw {
|
|||||||
tag = getInstructionTag(instruction) and
|
tag = getInstructionTag(instruction) and
|
||||||
(
|
(
|
||||||
result = element.getInstructionVariable(tag) or
|
result = element.getInstructionVariable(tag) or
|
||||||
result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag)
|
result.(IRStringLiteral).getAst() = element.getInstructionStringLiteral(tag)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -339,7 +339,7 @@ Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind ki
|
|||||||
// such a `goto` creates a back edge.
|
// such a `goto` creates a back edge.
|
||||||
exists(TranslatedElement s, GotoStmt goto |
|
exists(TranslatedElement s, GotoStmt goto |
|
||||||
not isStrictlyForwardGoto(goto) and
|
not isStrictlyForwardGoto(goto) and
|
||||||
goto = s.getAST() and
|
goto = s.getAst() and
|
||||||
exists(InstructionTag tag |
|
exists(InstructionTag tag |
|
||||||
result = s.getInstructionSuccessor(tag, kind) and
|
result = s.getInstructionSuccessor(tag, kind) and
|
||||||
instruction = s.getInstruction(tag)
|
instruction = s.getInstruction(tag)
|
||||||
@@ -352,8 +352,13 @@ private predicate isStrictlyForwardGoto(GotoStmt goto) {
|
|||||||
goto.getLocation().isBefore(goto.getTarget().getLocation())
|
goto.getLocation().isBefore(goto.getTarget().getLocation())
|
||||||
}
|
}
|
||||||
|
|
||||||
Locatable getInstructionAST(TStageInstruction instr) {
|
Locatable getInstructionAst(TStageInstruction instr) {
|
||||||
result = getInstructionTranslatedElement(instr).getAST()
|
result = getInstructionTranslatedElement(instr).getAst()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getInstructionAst */
|
||||||
|
deprecated Locatable getInstructionAST(TStageInstruction instr) {
|
||||||
|
result = getInstructionAst(instr)
|
||||||
}
|
}
|
||||||
|
|
||||||
CppType getInstructionResultType(TStageInstruction instr) {
|
CppType getInstructionResultType(TStageInstruction instr) {
|
||||||
|
|||||||
@@ -175,7 +175,10 @@ abstract class TranslatedSideEffects extends TranslatedElement {
|
|||||||
/** Gets the expression whose side effects are being modeled. */
|
/** Gets the expression whose side effects are being modeled. */
|
||||||
abstract Expr getExpr();
|
abstract Expr getExpr();
|
||||||
|
|
||||||
final override Locatable getAST() { result = getExpr() }
|
final override Locatable getAst() { result = getExpr() }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated override Locatable getAST() { result = getAst() }
|
||||||
|
|
||||||
final override Function getFunction() { result = getExpr().getEnclosingFunction() }
|
final override Function getFunction() { result = getExpr().getEnclosingFunction() }
|
||||||
|
|
||||||
@@ -522,7 +525,10 @@ class TranslatedArgumentExprSideEffect extends TranslatedArgumentSideEffect,
|
|||||||
this = TTranslatedArgumentExprSideEffect(call, arg, index, sideEffectOpcode)
|
this = TTranslatedArgumentExprSideEffect(call, arg, index, sideEffectOpcode)
|
||||||
}
|
}
|
||||||
|
|
||||||
final override Locatable getAST() { result = arg }
|
final override Locatable getAst() { result = arg }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated override Locatable getAST() { result = getAst() }
|
||||||
|
|
||||||
final override Type getIndirectionType() {
|
final override Type getIndirectionType() {
|
||||||
result = arg.getUnspecifiedType().(DerivedType).getBaseType()
|
result = arg.getUnspecifiedType().(DerivedType).getBaseType()
|
||||||
@@ -553,7 +559,10 @@ class TranslatedStructorQualifierSideEffect extends TranslatedArgumentSideEffect
|
|||||||
index = -1
|
index = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
final override Locatable getAST() { result = call }
|
final override Locatable getAst() { result = call }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated override Locatable getAST() { result = getAst() }
|
||||||
|
|
||||||
final override Type getIndirectionType() { result = call.getTarget().getDeclaringType() }
|
final override Type getIndirectionType() { result = call.getTarget().getDeclaringType() }
|
||||||
|
|
||||||
@@ -574,7 +583,10 @@ class TranslatedCallSideEffect extends TranslatedSideEffect, TTranslatedCallSide
|
|||||||
|
|
||||||
TranslatedCallSideEffect() { this = TTranslatedCallSideEffect(expr, sideEffectOpcode) }
|
TranslatedCallSideEffect() { this = TTranslatedCallSideEffect(expr, sideEffectOpcode) }
|
||||||
|
|
||||||
override Locatable getAST() { result = expr }
|
override Locatable getAst() { result = expr }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated override Locatable getAST() { result = getAst() }
|
||||||
|
|
||||||
override Expr getPrimaryExpr() { result = expr }
|
override Expr getPrimaryExpr() { result = expr }
|
||||||
|
|
||||||
@@ -612,7 +624,10 @@ class TranslatedAllocationSideEffect extends TranslatedSideEffect, TTranslatedAl
|
|||||||
|
|
||||||
TranslatedAllocationSideEffect() { this = TTranslatedAllocationSideEffect(expr) }
|
TranslatedAllocationSideEffect() { this = TTranslatedAllocationSideEffect(expr) }
|
||||||
|
|
||||||
override Locatable getAST() { result = expr }
|
override Locatable getAst() { result = expr }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated override Locatable getAST() { result = getAst() }
|
||||||
|
|
||||||
override Expr getPrimaryExpr() { result = expr }
|
override Expr getPrimaryExpr() { result = expr }
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ abstract class TranslatedCondition extends TranslatedElement {
|
|||||||
|
|
||||||
final override string toString() { result = expr.toString() }
|
final override string toString() { result = expr.toString() }
|
||||||
|
|
||||||
final override Locatable getAST() { result = expr }
|
final override Locatable getAst() { result = expr }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated override Locatable getAST() { result = getAst() }
|
||||||
|
|
||||||
final ConditionContext getConditionContext() { result = getParent() }
|
final ConditionContext getConditionContext() { result = getParent() }
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ private import TranslatedInitialization
|
|||||||
* `entry`.
|
* `entry`.
|
||||||
*/
|
*/
|
||||||
TranslatedDeclarationEntry getTranslatedDeclarationEntry(DeclarationEntry entry) {
|
TranslatedDeclarationEntry getTranslatedDeclarationEntry(DeclarationEntry entry) {
|
||||||
result.getAST() = entry
|
result.getAst() = entry
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,7 +37,10 @@ abstract class TranslatedDeclarationEntry extends TranslatedElement, TTranslated
|
|||||||
|
|
||||||
final override string toString() { result = entry.toString() }
|
final override string toString() { result = entry.toString() }
|
||||||
|
|
||||||
final override Locatable getAST() { result = entry }
|
final override Locatable getAst() { result = entry }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated override Locatable getAST() { result = getAst() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -223,7 +226,10 @@ class TranslatedStaticLocalVariableInitialization extends TranslatedElement,
|
|||||||
|
|
||||||
final override string toString() { result = "init: " + entry.toString() }
|
final override string toString() { result = "init: " + entry.toString() }
|
||||||
|
|
||||||
final override Locatable getAST() { result = entry }
|
final override Locatable getAst() { result = entry }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated override Locatable getAST() { result = getAst() }
|
||||||
|
|
||||||
final override LocalVariable getVariable() { result = var }
|
final override LocalVariable getVariable() { result = var }
|
||||||
|
|
||||||
@@ -254,7 +260,10 @@ class TranslatedRangeBasedForVariableDeclaration extends TranslatedLocalVariable
|
|||||||
|
|
||||||
override string toString() { result = var.toString() }
|
override string toString() { result = var.toString() }
|
||||||
|
|
||||||
override Locatable getAST() { result = var }
|
override Locatable getAst() { result = var }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated override Locatable getAST() { result = getAst() }
|
||||||
|
|
||||||
override Function getFunction() { result = forStmt.getEnclosingFunction() }
|
override Function getFunction() { result = forStmt.getEnclosingFunction() }
|
||||||
|
|
||||||
@@ -262,7 +271,7 @@ class TranslatedRangeBasedForVariableDeclaration extends TranslatedLocalVariable
|
|||||||
}
|
}
|
||||||
|
|
||||||
TranslatedConditionDecl getTranslatedConditionDecl(ConditionDeclExpr expr) {
|
TranslatedConditionDecl getTranslatedConditionDecl(ConditionDeclExpr expr) {
|
||||||
result.getAST() = expr
|
result.getAst() = expr
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -280,7 +289,10 @@ class TranslatedConditionDecl extends TranslatedLocalVariableDeclaration, TTrans
|
|||||||
|
|
||||||
override string toString() { result = "decl: " + conditionDeclExpr.toString() }
|
override string toString() { result = "decl: " + conditionDeclExpr.toString() }
|
||||||
|
|
||||||
override Locatable getAST() { result = conditionDeclExpr }
|
override Locatable getAst() { result = conditionDeclExpr }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getAst */
|
||||||
|
deprecated override Locatable getAST() { result = getAst() }
|
||||||
|
|
||||||
override Function getFunction() { result = conditionDeclExpr.getEnclosingFunction() }
|
override Function getFunction() { result = conditionDeclExpr.getEnclosingFunction() }
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user