mirror of
https://github.com/github/codeql.git
synced 2026-05-18 21:27:08 +02:00
Compare commits
1 Commits
codeql-cli
...
smowton/ad
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a7d27a976 |
50
.github/workflows/check-qldoc.yml
vendored
50
.github/workflows/check-qldoc.yml
vendored
@@ -1,50 +0,0 @@
|
||||
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}"
|
||||
@@ -27,8 +27,7 @@
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll"
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll"
|
||||
],
|
||||
"DataFlow Java/C++/C#/Python Common": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
|
||||
@@ -55,8 +54,7 @@
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking4/TaintTrackingImpl.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforlibraries/TaintTrackingImpl.qll"
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
|
||||
],
|
||||
"DataFlow Java/C++/C#/Python Consistency checks": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll",
|
||||
@@ -75,14 +73,6 @@
|
||||
"java/ql/lib/semmle/code/java/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#": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll"
|
||||
@@ -517,13 +507,5 @@
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/AccessPathSyntax.qll",
|
||||
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/AccessPathSyntax.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/AccessPathSyntax.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"
|
||||
]
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
description: Remove uniqueness constraint from the uuid property
|
||||
compatibility: full
|
||||
@@ -1,30 +1,3 @@
|
||||
## 0.0.12
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* 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.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* 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.
|
||||
|
||||
### New Features
|
||||
|
||||
* 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.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* `DefaultOptions::exits` now holds for C11 functions with the `_Noreturn` or `noreturn` specifier.
|
||||
* `hasImplicitCopyConstructor` and `hasImplicitCopyAssignmentOperator` now correctly handle implicitly-deleted operators in templates.
|
||||
* All deprecated predicates/classes/modules that have been deprecated for over a year have been deleted.
|
||||
|
||||
## 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
|
||||
|
||||
### New Features
|
||||
@@ -33,7 +6,6 @@
|
||||
|
||||
## 0.0.9
|
||||
|
||||
|
||||
## 0.0.8
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
@@ -54,13 +54,11 @@ class Options extends string {
|
||||
*
|
||||
* By default, this holds for `exit`, `_exit`, `abort`, `__assert_fail`,
|
||||
* `longjmp`, `__builtin_unreachable` and any function with a
|
||||
* `noreturn` attribute or specifier.
|
||||
* `noreturn` attribute.
|
||||
*/
|
||||
predicate exits(Function f) {
|
||||
f.getAnAttribute().hasName("noreturn")
|
||||
or
|
||||
f.getASpecifier().hasName("noreturn")
|
||||
or
|
||||
f.hasGlobalOrStdName([
|
||||
"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`,
|
||||
* `longjmp`, `error`, `__builtin_unreachable` and any function with a
|
||||
* `noreturn` attribute or specifier.
|
||||
* `noreturn` attribute.
|
||||
*/
|
||||
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.
|
||||
@@ -1,5 +1,4 @@
|
||||
## 0.0.11
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Many queries now support structured bindings, as structured bindings are now handled in the IR translation.
|
||||
@@ -1,20 +0,0 @@
|
||||
## 0.0.12
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* 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.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* 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.
|
||||
|
||||
### New Features
|
||||
|
||||
* 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.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* `DefaultOptions::exits` now holds for C11 functions with the `_Noreturn` or `noreturn` specifier.
|
||||
* `hasImplicitCopyConstructor` and `hasImplicitCopyAssignmentOperator` now correctly handle implicitly-deleted operators in templates.
|
||||
* All deprecated predicates/classes/modules that have been deprecated for over a year have been deleted.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.12
|
||||
lastReleaseVersion: 0.0.10
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.0.12
|
||||
version: 0.0.11-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -251,16 +251,6 @@ class Class extends UserType {
|
||||
not this.implicitCopyConstructorDeleted() and
|
||||
forall(CopyConstructor cc | cc = this.getAMemberFunction() |
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -276,18 +266,6 @@ class Class extends UserType {
|
||||
not this.implicitCopyAssignmentOperatorDeleted() and
|
||||
forall(CopyAssignmentOperator ca | ca = this.getAMemberFunction() |
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@ private import PrintAST
|
||||
private predicate shouldPrintDeclaration(Declaration decl) {
|
||||
not decl instanceof Function
|
||||
or
|
||||
not exists(PrintAstConfiguration c)
|
||||
not exists(PrintASTConfiguration c)
|
||||
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
|
||||
* printed.
|
||||
*/
|
||||
class Cfg extends PrintAstConfiguration {
|
||||
class Cfg extends PrintASTConfiguration {
|
||||
/**
|
||||
* TWEAK THIS PREDICATE AS NEEDED.
|
||||
* Holds if the AST for `func` should be printed.
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
import cpp
|
||||
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.
|
||||
*/
|
||||
class PrintAstConfiguration extends TPrintAstConfiguration {
|
||||
class PrintASTConfiguration extends TPrintASTConfiguration {
|
||||
/**
|
||||
* Gets a textual representation of this `PrintASTConfiguration`.
|
||||
*/
|
||||
@@ -27,11 +27,8 @@ class PrintAstConfiguration extends TPrintAstConfiguration {
|
||||
predicate shouldPrintFunction(Function func) { any() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for PrintAstConfiguration */
|
||||
deprecated class PrintASTConfiguration = PrintAstConfiguration;
|
||||
|
||||
private predicate shouldPrintFunction(Function func) {
|
||||
exists(PrintAstConfiguration config | config.shouldPrintFunction(func))
|
||||
exists(PrintASTConfiguration config | config.shouldPrintFunction(func))
|
||||
}
|
||||
|
||||
bindingset[s]
|
||||
@@ -88,8 +85,8 @@ private Function getEnclosingFunction(Locatable ast) {
|
||||
* Most nodes are just a wrapper around `Locatable`, but we do synthesize new
|
||||
* nodes for things like parameter lists and constructor init lists.
|
||||
*/
|
||||
private newtype TPrintAstNode =
|
||||
TAstNode(Locatable ast) { shouldPrintFunction(getEnclosingFunction(ast)) } or
|
||||
private newtype TPrintASTNode =
|
||||
TASTNode(Locatable ast) { shouldPrintFunction(getEnclosingFunction(ast)) } or
|
||||
TDeclarationEntryNode(DeclStmt stmt, DeclarationEntry entry) {
|
||||
// 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.
|
||||
@@ -109,7 +106,7 @@ private newtype TPrintAstNode =
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -119,17 +116,17 @@ class PrintAstNode extends TPrintAstNode {
|
||||
* Gets the child node at index `childIndex`. Child indices must be unique,
|
||||
* but need not be contiguous.
|
||||
*/
|
||||
abstract PrintAstNode getChildInternal(int childIndex);
|
||||
abstract PrintASTNode getChildInternal(int childIndex);
|
||||
|
||||
/**
|
||||
* Gets the child node at index `childIndex`.
|
||||
* Adds edges to fully converted expressions, that are not part of the
|
||||
* 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.
|
||||
result =
|
||||
rank[childIndex](PrintAstNode child, int nonConvertedIndex, boolean isConverted |
|
||||
rank[childIndex](PrintASTNode child, int nonConvertedIndex, boolean isConverted |
|
||||
childAndAccessorPredicate(child, _, nonConvertedIndex, isConverted)
|
||||
|
|
||||
// Unconverted children come first, then sort by original child index within each group.
|
||||
@@ -141,11 +138,11 @@ class PrintAstNode extends TPrintAstNode {
|
||||
* Gets the node for the `.getFullyConverted()` version of the child originally at index
|
||||
* `childIndex`, if that node has any conversions.
|
||||
*/
|
||||
private PrintAstNode getConvertedChild(int childIndex) {
|
||||
private PrintASTNode getConvertedChild(int childIndex) {
|
||||
exists(Expr expr |
|
||||
expr = getChildInternal(childIndex).(AstNode).getAst() and
|
||||
expr = getChildInternal(childIndex).(ASTNode).getAST() and
|
||||
expr.getFullyConverted() instanceof Conversion and
|
||||
result.(AstNode).getAst() = expr.getFullyConverted() and
|
||||
result.(ASTNode).getAST() = expr.getFullyConverted() and
|
||||
not expr instanceof Conversion
|
||||
)
|
||||
}
|
||||
@@ -169,12 +166,12 @@ class PrintAstNode extends TPrintAstNode {
|
||||
/**
|
||||
* Gets the children of this node.
|
||||
*/
|
||||
final PrintAstNode getAChild() { result = getChild(_) }
|
||||
final PrintASTNode getAChild() { result = getChild(_) }
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -199,7 +196,7 @@ class PrintAstNode extends TPrintAstNode {
|
||||
* one result tuple, with `isConverted = false`.
|
||||
*/
|
||||
private predicate childAndAccessorPredicate(
|
||||
PrintAstNode child, string childPredicate, int nonConvertedIndex, boolean isConverted
|
||||
PrintASTNode child, string childPredicate, int nonConvertedIndex, boolean isConverted
|
||||
) {
|
||||
child = getChildInternal(nonConvertedIndex) and
|
||||
childPredicate = getChildAccessorPredicateInternal(nonConvertedIndex) and
|
||||
@@ -237,15 +234,12 @@ class PrintAstNode extends TPrintAstNode {
|
||||
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.
|
||||
*/
|
||||
private class PrintableElement extends Element {
|
||||
PrintableElement() {
|
||||
exists(TAstNode(this))
|
||||
exists(TASTNode(this))
|
||||
or
|
||||
exists(TDeclarationEntryNode(_, this))
|
||||
or
|
||||
@@ -268,7 +262,7 @@ private string qlClass(PrintableElement el) {
|
||||
/**
|
||||
* A node representing an AST node.
|
||||
*/
|
||||
abstract class BaseAstNode extends PrintAstNode {
|
||||
abstract class BaseASTNode extends PrintASTNode {
|
||||
Locatable ast;
|
||||
|
||||
override string toString() { result = qlClass(ast) + ast.toString() }
|
||||
@@ -278,34 +272,25 @@ abstract class BaseAstNode extends PrintAstNode {
|
||||
/**
|
||||
* Gets the AST represented by this node.
|
||||
*/
|
||||
final Locatable getAst() { result = ast }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Locatable getAST() { result = getAst() }
|
||||
final Locatable getAST() { result = ast }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for BaseAstNode */
|
||||
deprecated class BaseASTNode = BaseAstNode;
|
||||
|
||||
/**
|
||||
* A node representing an AST node other than a `DeclarationEntry`.
|
||||
*/
|
||||
abstract class AstNode extends BaseAstNode, TAstNode {
|
||||
AstNode() { this = TAstNode(ast) }
|
||||
abstract class ASTNode extends BaseASTNode, TASTNode {
|
||||
ASTNode() { this = TASTNode(ast) }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for AstNode */
|
||||
deprecated class ASTNode = AstNode;
|
||||
|
||||
/**
|
||||
* A node representing an `Expr`.
|
||||
*/
|
||||
class ExprNode extends AstNode {
|
||||
class ExprNode extends ASTNode {
|
||||
Expr expr;
|
||||
|
||||
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) {
|
||||
result = super.getProperty(key)
|
||||
@@ -321,7 +306,7 @@ class ExprNode extends AstNode {
|
||||
}
|
||||
|
||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
result = getChildAccessorWithoutConversions(ast, getChildInternal(childIndex).getAst())
|
||||
result = getChildAccessorWithoutConversions(ast, getChildInternal(childIndex).getAST())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,9 +334,9 @@ class ConversionNode extends ExprNode {
|
||||
|
||||
ConversionNode() { conv = expr }
|
||||
|
||||
override AstNode getChildInternal(int childIndex) {
|
||||
override ASTNode getChildInternal(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result.getAst() = conv.getExpr() and
|
||||
result.getAST() = conv.getExpr() and
|
||||
conv.getExpr() instanceof Conversion
|
||||
}
|
||||
}
|
||||
@@ -378,27 +363,27 @@ class CastNode extends ConversionNode {
|
||||
class StmtExprNode extends ExprNode {
|
||||
override StmtExpr expr;
|
||||
|
||||
override AstNode getChildInternal(int childIndex) {
|
||||
override ASTNode getChildInternal(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result.getAst() = expr.getStmt()
|
||||
result.getAST() = expr.getStmt()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `DeclarationEntry`.
|
||||
*/
|
||||
class DeclarationEntryNode extends BaseAstNode, TDeclarationEntryNode {
|
||||
class DeclarationEntryNode extends BaseASTNode, TDeclarationEntryNode {
|
||||
override DeclarationEntry ast;
|
||||
DeclStmt declStmt;
|
||||
|
||||
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 getProperty(string key) {
|
||||
result = BaseAstNode.super.getProperty(key)
|
||||
result = BaseASTNode.super.getProperty(key)
|
||||
or
|
||||
key = "Type" and
|
||||
result = qlClass(ast.getType()) + ast.getType().toString()
|
||||
@@ -411,9 +396,9 @@ class DeclarationEntryNode extends BaseAstNode, TDeclarationEntryNode {
|
||||
class VariableDeclarationEntryNode extends DeclarationEntryNode {
|
||||
override VariableDeclarationEntry ast;
|
||||
|
||||
override AstNode getChildInternal(int childIndex) {
|
||||
override ASTNode getChildInternal(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result.getAst() = ast.getVariable().getInitializer()
|
||||
result.getAST() = ast.getVariable().getInitializer()
|
||||
}
|
||||
|
||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
@@ -425,23 +410,23 @@ class VariableDeclarationEntryNode extends DeclarationEntryNode {
|
||||
/**
|
||||
* A node representing a `Stmt`.
|
||||
*/
|
||||
class StmtNode extends AstNode {
|
||||
class StmtNode extends ASTNode {
|
||||
Stmt stmt;
|
||||
|
||||
StmtNode() { stmt = ast }
|
||||
|
||||
override BaseAstNode getChildInternal(int childIndex) {
|
||||
override BaseASTNode getChildInternal(int childIndex) {
|
||||
exists(Locatable child |
|
||||
child = stmt.getChild(childIndex) and
|
||||
(
|
||||
result.getAst() = child.(Expr) or
|
||||
result.getAst() = child.(Stmt)
|
||||
result.getAST() = child.(Expr) or
|
||||
result.getAST() = child.(Stmt)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
result = getChildAccessorWithoutConversions(ast, getChildInternal(childIndex).getAst())
|
||||
result = getChildAccessorWithoutConversions(ast, getChildInternal(childIndex).getAST())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,12 +449,12 @@ class DeclStmtNode extends StmtNode {
|
||||
/**
|
||||
* A node representing a `Parameter`.
|
||||
*/
|
||||
class ParameterNode extends AstNode {
|
||||
class ParameterNode extends ASTNode {
|
||||
Parameter param;
|
||||
|
||||
ParameterNode() { param = ast }
|
||||
|
||||
final override PrintAstNode getChildInternal(int childIndex) { none() }
|
||||
final override PrintASTNode getChildInternal(int childIndex) { none() }
|
||||
|
||||
final override string getChildAccessorPredicateInternal(int childIndex) { none() }
|
||||
|
||||
@@ -484,14 +469,14 @@ class ParameterNode extends AstNode {
|
||||
/**
|
||||
* A node representing an `Initializer`.
|
||||
*/
|
||||
class InitializerNode extends AstNode {
|
||||
class InitializerNode extends ASTNode {
|
||||
Initializer init;
|
||||
|
||||
InitializerNode() { init = ast }
|
||||
|
||||
override AstNode getChildInternal(int childIndex) {
|
||||
override ASTNode getChildInternal(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result.getAst() = init.getExpr()
|
||||
result.getAST() = init.getExpr()
|
||||
}
|
||||
|
||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
@@ -503,7 +488,7 @@ class InitializerNode extends AstNode {
|
||||
/**
|
||||
* A node representing the parameters of a `Function`.
|
||||
*/
|
||||
class ParametersNode extends PrintAstNode, TParametersNode {
|
||||
class ParametersNode extends PrintASTNode, TParametersNode {
|
||||
Function func;
|
||||
|
||||
ParametersNode() { this = TParametersNode(func) }
|
||||
@@ -512,8 +497,8 @@ class ParametersNode extends PrintAstNode, TParametersNode {
|
||||
|
||||
final override Location getLocation() { result = getRepresentativeLocation(func) }
|
||||
|
||||
override AstNode getChildInternal(int childIndex) {
|
||||
result.getAst() = func.getParameter(childIndex)
|
||||
override ASTNode getChildInternal(int childIndex) {
|
||||
result.getAST() = func.getParameter(childIndex)
|
||||
}
|
||||
|
||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
@@ -530,7 +515,7 @@ class ParametersNode extends PrintAstNode, TParametersNode {
|
||||
/**
|
||||
* A node representing the initializer list of a `Constructor`.
|
||||
*/
|
||||
class ConstructorInitializersNode extends PrintAstNode, TConstructorInitializersNode {
|
||||
class ConstructorInitializersNode extends PrintASTNode, TConstructorInitializersNode {
|
||||
Constructor ctor;
|
||||
|
||||
ConstructorInitializersNode() { this = TConstructorInitializersNode(ctor) }
|
||||
@@ -539,8 +524,8 @@ class ConstructorInitializersNode extends PrintAstNode, TConstructorInitializers
|
||||
|
||||
final override Location getLocation() { result = getRepresentativeLocation(ctor) }
|
||||
|
||||
final override AstNode getChildInternal(int childIndex) {
|
||||
result.getAst() = ctor.getInitializer(childIndex)
|
||||
final override ASTNode getChildInternal(int childIndex) {
|
||||
result.getAST() = ctor.getInitializer(childIndex)
|
||||
}
|
||||
|
||||
final override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
@@ -557,7 +542,7 @@ class ConstructorInitializersNode extends PrintAstNode, TConstructorInitializers
|
||||
/**
|
||||
* A node representing the destruction list of a `Destructor`.
|
||||
*/
|
||||
class DestructorDestructionsNode extends PrintAstNode, TDestructorDestructionsNode {
|
||||
class DestructorDestructionsNode extends PrintASTNode, TDestructorDestructionsNode {
|
||||
Destructor dtor;
|
||||
|
||||
DestructorDestructionsNode() { this = TDestructorDestructionsNode(dtor) }
|
||||
@@ -566,8 +551,8 @@ class DestructorDestructionsNode extends PrintAstNode, TDestructorDestructionsNo
|
||||
|
||||
final override Location getLocation() { result = getRepresentativeLocation(dtor) }
|
||||
|
||||
final override AstNode getChildInternal(int childIndex) {
|
||||
result.getAst() = dtor.getDestruction(childIndex)
|
||||
final override ASTNode getChildInternal(int childIndex) {
|
||||
result.getAST() = dtor.getDestruction(childIndex)
|
||||
}
|
||||
|
||||
final override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
@@ -584,14 +569,14 @@ class DestructorDestructionsNode extends PrintAstNode, TDestructorDestructionsNo
|
||||
/**
|
||||
* A node representing a `Function`.
|
||||
*/
|
||||
class FunctionNode extends AstNode {
|
||||
class FunctionNode extends ASTNode {
|
||||
Function func;
|
||||
|
||||
FunctionNode() { func = ast }
|
||||
|
||||
override string toString() { result = qlClass(func) + getIdentityString(func) }
|
||||
|
||||
override PrintAstNode getChildInternal(int childIndex) {
|
||||
override PrintASTNode getChildInternal(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result.(ParametersNode).getFunction() = func
|
||||
or
|
||||
@@ -599,7 +584,7 @@ class FunctionNode extends AstNode {
|
||||
result.(ConstructorInitializersNode).getConstructor() = func
|
||||
or
|
||||
childIndex = 2 and
|
||||
result.(AstNode).getAst() = func.getEntryPoint()
|
||||
result.(ASTNode).getAST() = func.getEntryPoint()
|
||||
or
|
||||
childIndex = 3 and
|
||||
result.(DestructorDestructionsNode).getDestructor() = func
|
||||
@@ -618,7 +603,7 @@ class FunctionNode extends AstNode {
|
||||
private int getOrder() {
|
||||
this =
|
||||
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)
|
||||
|
|
||||
node order by file, line, column, getIdentityString(function)
|
||||
@@ -871,7 +856,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`. */
|
||||
query predicate nodes(PrintAstNode node, string key, string value) {
|
||||
query predicate nodes(PrintASTNode node, string key, string value) {
|
||||
node.shouldPrint() and
|
||||
value = node.getProperty(key)
|
||||
}
|
||||
@@ -880,7 +865,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
|
||||
* 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 |
|
||||
source.shouldPrint() and
|
||||
target.shouldPrint() and
|
||||
|
||||
@@ -38,7 +38,7 @@ class FunctionSpecifier extends Specifier {
|
||||
|
||||
/**
|
||||
* A C/C++ storage class specifier: `auto`, `register`, `static`, `extern`,
|
||||
* or `mutable`.
|
||||
* or `mutable".
|
||||
*/
|
||||
class StorageClassSpecifier extends Specifier {
|
||||
StorageClassSpecifier() { this.hasName(["auto", "register", "static", "extern", "mutable"]) }
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
import semmle.files.FileSystem
|
||||
|
||||
private class TXmlLocatable =
|
||||
private class TXMLLocatable =
|
||||
@xmldtd or @xmlelement or @xmlattribute or @xmlnamespace or @xmlcomment or @xmlcharacters;
|
||||
|
||||
/** An XML element that has a location. */
|
||||
class XMLLocatable extends @xmllocatable, TXmlLocatable {
|
||||
class XMLLocatable extends @xmllocatable, TXMLLocatable {
|
||||
/** Gets the source location for this element. */
|
||||
Location getLocation() { xmllocations(this, result) }
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase {
|
||||
* taken when this expression is true.
|
||||
*/
|
||||
ControlFlowNode getATrueSuccessor() {
|
||||
qlCfgTrueSuccessor(this, result) and
|
||||
qlCFGTrueSuccessor(this, result) and
|
||||
result = this.getASuccessor()
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase {
|
||||
* taken when this expression is false.
|
||||
*/
|
||||
ControlFlowNode getAFalseSuccessor() {
|
||||
qlCfgFalseSuccessor(this, result) and
|
||||
qlCFGFalseSuccessor(this, result) and
|
||||
result = this.getASuccessor()
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ abstract class AdditionalControlFlowEdge extends ControlFlowNodeBase {
|
||||
* `AdditionalControlFlowEdge`. Use this relation instead of `qlCFGSuccessor`.
|
||||
*/
|
||||
predicate successors_extended(ControlFlowNodeBase source, ControlFlowNodeBase target) {
|
||||
qlCfgSuccessor(source, target)
|
||||
qlCFGSuccessor(source, target)
|
||||
or
|
||||
source.(AdditionalControlFlowEdge).getAnEdgeTarget() = target
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ class GuardCondition extends Expr {
|
||||
or
|
||||
// the IR short-circuits if(!x)
|
||||
// don't produce a guard condition for `y = !x` and other non-short-circuited cases
|
||||
not exists(Instruction inst | this.getFullyConverted() = inst.getAst()) and
|
||||
exists(IRGuardCondition ir | this.(NotExpr).getOperand() = ir.getAst())
|
||||
not exists(Instruction inst | this.getFullyConverted() = inst.getAST()) and
|
||||
exists(IRGuardCondition ir | this.(NotExpr).getOperand() = ir.getAST())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,8 +146,8 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardCondition {
|
||||
*/
|
||||
private class GuardConditionFromShortCircuitNot extends GuardCondition, NotExpr {
|
||||
GuardConditionFromShortCircuitNot() {
|
||||
not exists(Instruction inst | this.getFullyConverted() = inst.getAst()) and
|
||||
exists(IRGuardCondition ir | this.getOperand() = ir.getAst())
|
||||
not exists(Instruction inst | this.getFullyConverted() = inst.getAST()) and
|
||||
exists(IRGuardCondition ir | this.getOperand() = ir.getAST())
|
||||
}
|
||||
|
||||
override predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
||||
@@ -241,7 +241,7 @@ private class GuardConditionFromIR extends GuardCondition {
|
||||
private predicate controlsBlock(BasicBlock controlled, boolean testIsTrue) {
|
||||
exists(IRBlock irb |
|
||||
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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,13 +10,10 @@ import SSAUtils
|
||||
* The SSA logic comes in two versions: the standard SSA and range-analysis RangeSSA.
|
||||
* This class provides the standard SSA logic.
|
||||
*/
|
||||
library class StandardSsa extends SsaHelper {
|
||||
StandardSsa() { this = 0 }
|
||||
library class StandardSSA extends SSAHelper {
|
||||
StandardSSA() { this = 0 }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for StandardSsa */
|
||||
deprecated class StandardSSA = StandardSsa;
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -30,22 +27,22 @@ deprecated class StandardSSA = StandardSsa;
|
||||
* statically seen to be unreachable.
|
||||
*/
|
||||
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
|
||||
* 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
|
||||
* `(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)`. */
|
||||
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
|
||||
@@ -65,7 +62,7 @@ class SsaDefinition extends ControlFlowNodeBase {
|
||||
BasicBlock getBasicBlock() { result.contains(this.getDefinition()) }
|
||||
|
||||
/** 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. */
|
||||
Location getLocation() { result = this.(ControlFlowNode).getLocation() }
|
||||
@@ -127,7 +124,7 @@ class SsaDefinition extends ControlFlowNodeBase {
|
||||
|
||||
/** Holds if `(this, v)` reaches the end of basic block `b`. */
|
||||
predicate reachesEndOfBB(StackVariable v, BasicBlock b) {
|
||||
exists(StandardSsa x | x.ssaDefinitionReachesEndOfBB(v, this, b))
|
||||
exists(StandardSSA x | x.ssaDefinitionReachesEndOfBB(v, this, b))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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. */
|
||||
cached
|
||||
library class SsaHelper extends int {
|
||||
library class SSAHelper extends int {
|
||||
/* 0 = StandardSSA, 1 = RangeSSA */
|
||||
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
|
||||
@@ -311,6 +311,3 @@ library class SsaHelper extends int {
|
||||
ssa_use(v, result, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SsaHelper */
|
||||
deprecated class SSAHelper = SsaHelper;
|
||||
|
||||
@@ -447,6 +447,26 @@ 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
|
||||
* contiguous, and the first index is 0.
|
||||
@@ -1359,7 +1379,7 @@ private module Cached {
|
||||
* true-successors and false-successors.
|
||||
*/
|
||||
cached
|
||||
predicate qlCfgSuccessor(Node n1, Node n2) {
|
||||
predicate qlCFGSuccessor(Node n1, Node n2) {
|
||||
exists(Node memberNode, Pos memberPos |
|
||||
subEdgeIncludingDestructors(any(Pos at | at.isAt()), n1, memberNode, memberPos) and
|
||||
normalGroupMember(memberNode, memberPos, n2)
|
||||
@@ -1368,32 +1388,23 @@ private module Cached {
|
||||
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
|
||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is true.
|
||||
*/
|
||||
cached
|
||||
predicate qlCfgTrueSuccessor(Node n1, Node n2) {
|
||||
predicate qlCFGTrueSuccessor(Node n1, Node n2) {
|
||||
conditionalSuccessor(n1, true, n2) and
|
||||
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
|
||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is false.
|
||||
*/
|
||||
cached
|
||||
predicate qlCfgFalseSuccessor(Node n1, Node n2) {
|
||||
predicate qlCFGFalseSuccessor(Node n1, Node n2) {
|
||||
conditionalSuccessor(n1, false, n2) and
|
||||
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) {
|
||||
conditionAlwaysTrue(condition) and
|
||||
qlCfgFalseSuccessor(condition, succ) and
|
||||
not qlCfgTrueSuccessor(condition, succ)
|
||||
qlCFGFalseSuccessor(condition, succ) and
|
||||
not qlCFGTrueSuccessor(condition, succ)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,8 +197,8 @@ private predicate impossibleFalseEdge(Expr condition, Node succ) {
|
||||
*/
|
||||
private predicate impossibleTrueEdge(Expr condition, Node succ) {
|
||||
conditionAlwaysFalse(condition) and
|
||||
qlCfgTrueSuccessor(condition, succ) and
|
||||
not qlCfgFalseSuccessor(condition, succ)
|
||||
qlCFGTrueSuccessor(condition, succ) and
|
||||
not qlCFGFalseSuccessor(condition, succ)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -960,9 +960,9 @@ library class ConditionEvaluator extends ExprEvaluator {
|
||||
ConditionEvaluator() { this = 0 }
|
||||
|
||||
override predicate interesting(Expr e) {
|
||||
qlCfgFalseSuccessor(e, _)
|
||||
qlCFGFalseSuccessor(e, _)
|
||||
or
|
||||
qlCfgTrueSuccessor(e, _)
|
||||
qlCFGTrueSuccessor(e, _)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,4 +20,5 @@ import semmle.code.cpp.dataflow.DataFlow2
|
||||
|
||||
module TaintTracking {
|
||||
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||
private import semmle.code.cpp.dataflow.TaintTracking2
|
||||
}
|
||||
|
||||
@@ -87,30 +87,12 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
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. */
|
||||
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. */
|
||||
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
|
||||
* into account in the analysis.
|
||||
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
|
||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||
}
|
||||
|
||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierIn(n)
|
||||
@@ -332,16 +314,7 @@ private predicate fullInBarrier(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) {
|
||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierOut(n)
|
||||
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(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]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||
pragma[inline]
|
||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
not fullOutBarrier(node1, config) and
|
||||
not fullInBarrier(node2, config) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) 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(node2, s2, config)
|
||||
)
|
||||
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) 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(node2, s2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -920,8 +870,8 @@ private module Stage1 {
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
revFlow(node, true, config) and
|
||||
fwdFlow(node, true, config) and
|
||||
not fullInBarrier(node, config) and
|
||||
not fullOutBarrier(node, config)
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
}
|
||||
|
||||
/** Holds if flow may return from `callable`. */
|
||||
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
|
||||
) {
|
||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not fullOutBarrier(ret, config) and
|
||||
not fullInBarrier(out, config)
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
not fullOutBarrier(arg, config) and
|
||||
not fullInBarrier(p, config)
|
||||
not outBarrier(arg, config) and
|
||||
not inBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
Stage2::revFlow(node, state, config) and
|
||||
(
|
||||
sourceNode(node, state, config)
|
||||
or
|
||||
jumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStateStep(_, _, node, state, config)
|
||||
or
|
||||
node instanceof ParamNodeEx
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
or
|
||||
sourceNode(node, state, config) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
additionalJumpStateStep(_, _, node, state, config) or
|
||||
node instanceof ParamNodeEx or
|
||||
node.asNode() instanceof OutNodeExt or
|
||||
store(_, _, node, _, config) or
|
||||
read(_, _, node, config) or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
exists(FlowState s |
|
||||
additionalLocalStateStep(_, s, node, state, config) and
|
||||
s != state
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
additionalJumpStateStep(node, state, next, s, config)
|
||||
or
|
||||
additionalLocalStateStep(node, state, next, s, config) and
|
||||
s != state
|
||||
)
|
||||
or
|
||||
Stage2::revFlow(node, state, config) and
|
||||
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||
Configuration config, LocalCallContext cc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
state1 = state2 and
|
||||
preservesValue = true and
|
||||
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
t = node1.getDataFlowType() // irrelevant dummy value
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
||||
pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||
exists(NodeEx mid, FlowState st |
|
||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
t = node2.getDataFlowType() and
|
||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||
localFlowExit(node2, state1, config) and
|
||||
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)
|
||||
)
|
||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
||||
callContext) and
|
||||
localFlowExit(node2, state2, config)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2769,10 +2695,10 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, _, config) and
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
|
||||
@@ -87,30 +87,12 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
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. */
|
||||
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. */
|
||||
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
|
||||
* into account in the analysis.
|
||||
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
|
||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||
}
|
||||
|
||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierIn(n)
|
||||
@@ -332,16 +314,7 @@ private predicate fullInBarrier(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) {
|
||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierOut(n)
|
||||
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(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]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||
pragma[inline]
|
||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
not fullOutBarrier(node1, config) and
|
||||
not fullInBarrier(node2, config) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) 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(node2, s2, config)
|
||||
)
|
||||
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) 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(node2, s2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -920,8 +870,8 @@ private module Stage1 {
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
revFlow(node, true, config) and
|
||||
fwdFlow(node, true, config) and
|
||||
not fullInBarrier(node, config) and
|
||||
not fullOutBarrier(node, config)
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
}
|
||||
|
||||
/** Holds if flow may return from `callable`. */
|
||||
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
|
||||
) {
|
||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not fullOutBarrier(ret, config) and
|
||||
not fullInBarrier(out, config)
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
not fullOutBarrier(arg, config) and
|
||||
not fullInBarrier(p, config)
|
||||
not outBarrier(arg, config) and
|
||||
not inBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
Stage2::revFlow(node, state, config) and
|
||||
(
|
||||
sourceNode(node, state, config)
|
||||
or
|
||||
jumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStateStep(_, _, node, state, config)
|
||||
or
|
||||
node instanceof ParamNodeEx
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
or
|
||||
sourceNode(node, state, config) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
additionalJumpStateStep(_, _, node, state, config) or
|
||||
node instanceof ParamNodeEx or
|
||||
node.asNode() instanceof OutNodeExt or
|
||||
store(_, _, node, _, config) or
|
||||
read(_, _, node, config) or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
exists(FlowState s |
|
||||
additionalLocalStateStep(_, s, node, state, config) and
|
||||
s != state
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
additionalJumpStateStep(node, state, next, s, config)
|
||||
or
|
||||
additionalLocalStateStep(node, state, next, s, config) and
|
||||
s != state
|
||||
)
|
||||
or
|
||||
Stage2::revFlow(node, state, config) and
|
||||
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||
Configuration config, LocalCallContext cc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
state1 = state2 and
|
||||
preservesValue = true and
|
||||
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
t = node1.getDataFlowType() // irrelevant dummy value
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
||||
pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||
exists(NodeEx mid, FlowState st |
|
||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
t = node2.getDataFlowType() and
|
||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||
localFlowExit(node2, state1, config) and
|
||||
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)
|
||||
)
|
||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
||||
callContext) and
|
||||
localFlowExit(node2, state2, config)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2769,10 +2695,10 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, _, config) and
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
|
||||
@@ -87,30 +87,12 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
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. */
|
||||
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. */
|
||||
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
|
||||
* into account in the analysis.
|
||||
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
|
||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||
}
|
||||
|
||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierIn(n)
|
||||
@@ -332,16 +314,7 @@ private predicate fullInBarrier(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) {
|
||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierOut(n)
|
||||
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(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]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||
pragma[inline]
|
||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
not fullOutBarrier(node1, config) and
|
||||
not fullInBarrier(node2, config) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) 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(node2, s2, config)
|
||||
)
|
||||
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) 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(node2, s2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -920,8 +870,8 @@ private module Stage1 {
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
revFlow(node, true, config) and
|
||||
fwdFlow(node, true, config) and
|
||||
not fullInBarrier(node, config) and
|
||||
not fullOutBarrier(node, config)
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
}
|
||||
|
||||
/** Holds if flow may return from `callable`. */
|
||||
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
|
||||
) {
|
||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not fullOutBarrier(ret, config) and
|
||||
not fullInBarrier(out, config)
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
not fullOutBarrier(arg, config) and
|
||||
not fullInBarrier(p, config)
|
||||
not outBarrier(arg, config) and
|
||||
not inBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
Stage2::revFlow(node, state, config) and
|
||||
(
|
||||
sourceNode(node, state, config)
|
||||
or
|
||||
jumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStateStep(_, _, node, state, config)
|
||||
or
|
||||
node instanceof ParamNodeEx
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
or
|
||||
sourceNode(node, state, config) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
additionalJumpStateStep(_, _, node, state, config) or
|
||||
node instanceof ParamNodeEx or
|
||||
node.asNode() instanceof OutNodeExt or
|
||||
store(_, _, node, _, config) or
|
||||
read(_, _, node, config) or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
exists(FlowState s |
|
||||
additionalLocalStateStep(_, s, node, state, config) and
|
||||
s != state
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
additionalJumpStateStep(node, state, next, s, config)
|
||||
or
|
||||
additionalLocalStateStep(node, state, next, s, config) and
|
||||
s != state
|
||||
)
|
||||
or
|
||||
Stage2::revFlow(node, state, config) and
|
||||
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||
Configuration config, LocalCallContext cc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
state1 = state2 and
|
||||
preservesValue = true and
|
||||
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
t = node1.getDataFlowType() // irrelevant dummy value
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
||||
pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||
exists(NodeEx mid, FlowState st |
|
||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
t = node2.getDataFlowType() and
|
||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||
localFlowExit(node2, state1, config) and
|
||||
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)
|
||||
)
|
||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
||||
callContext) and
|
||||
localFlowExit(node2, state2, config)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2769,10 +2695,10 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, _, config) and
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
|
||||
@@ -87,30 +87,12 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
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. */
|
||||
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. */
|
||||
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
|
||||
* into account in the analysis.
|
||||
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
|
||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||
}
|
||||
|
||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierIn(n)
|
||||
@@ -332,16 +314,7 @@ private predicate fullInBarrier(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) {
|
||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierOut(n)
|
||||
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(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]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||
pragma[inline]
|
||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
not fullOutBarrier(node1, config) and
|
||||
not fullInBarrier(node2, config) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) 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(node2, s2, config)
|
||||
)
|
||||
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) 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(node2, s2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -920,8 +870,8 @@ private module Stage1 {
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
revFlow(node, true, config) and
|
||||
fwdFlow(node, true, config) and
|
||||
not fullInBarrier(node, config) and
|
||||
not fullOutBarrier(node, config)
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
}
|
||||
|
||||
/** Holds if flow may return from `callable`. */
|
||||
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
|
||||
) {
|
||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not fullOutBarrier(ret, config) and
|
||||
not fullInBarrier(out, config)
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
not fullOutBarrier(arg, config) and
|
||||
not fullInBarrier(p, config)
|
||||
not outBarrier(arg, config) and
|
||||
not inBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
Stage2::revFlow(node, state, config) and
|
||||
(
|
||||
sourceNode(node, state, config)
|
||||
or
|
||||
jumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStateStep(_, _, node, state, config)
|
||||
or
|
||||
node instanceof ParamNodeEx
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
or
|
||||
sourceNode(node, state, config) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
additionalJumpStateStep(_, _, node, state, config) or
|
||||
node instanceof ParamNodeEx or
|
||||
node.asNode() instanceof OutNodeExt or
|
||||
store(_, _, node, _, config) or
|
||||
read(_, _, node, config) or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
exists(FlowState s |
|
||||
additionalLocalStateStep(_, s, node, state, config) and
|
||||
s != state
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
additionalJumpStateStep(node, state, next, s, config)
|
||||
or
|
||||
additionalLocalStateStep(node, state, next, s, config) and
|
||||
s != state
|
||||
)
|
||||
or
|
||||
Stage2::revFlow(node, state, config) and
|
||||
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||
Configuration config, LocalCallContext cc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
state1 = state2 and
|
||||
preservesValue = true and
|
||||
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
t = node1.getDataFlowType() // irrelevant dummy value
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
||||
pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||
exists(NodeEx mid, FlowState st |
|
||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
t = node2.getDataFlowType() and
|
||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||
localFlowExit(node2, state1, config) and
|
||||
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)
|
||||
)
|
||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
||||
callContext) and
|
||||
localFlowExit(node2, state2, config)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2769,10 +2695,10 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, _, config) and
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
|
||||
@@ -87,30 +87,12 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
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. */
|
||||
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. */
|
||||
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
|
||||
* into account in the analysis.
|
||||
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
|
||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||
}
|
||||
|
||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierIn(n)
|
||||
@@ -332,16 +314,7 @@ private predicate fullInBarrier(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) {
|
||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierOut(n)
|
||||
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(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]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||
pragma[inline]
|
||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
not fullOutBarrier(node1, config) and
|
||||
not fullInBarrier(node2, config) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) 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(node2, s2, config)
|
||||
)
|
||||
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) 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(node2, s2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -920,8 +870,8 @@ private module Stage1 {
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
revFlow(node, true, config) and
|
||||
fwdFlow(node, true, config) and
|
||||
not fullInBarrier(node, config) and
|
||||
not fullOutBarrier(node, config)
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
}
|
||||
|
||||
/** Holds if flow may return from `callable`. */
|
||||
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
|
||||
) {
|
||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not fullOutBarrier(ret, config) and
|
||||
not fullInBarrier(out, config)
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
not fullOutBarrier(arg, config) and
|
||||
not fullInBarrier(p, config)
|
||||
not outBarrier(arg, config) and
|
||||
not inBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
Stage2::revFlow(node, state, config) and
|
||||
(
|
||||
sourceNode(node, state, config)
|
||||
or
|
||||
jumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStateStep(_, _, node, state, config)
|
||||
or
|
||||
node instanceof ParamNodeEx
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
or
|
||||
sourceNode(node, state, config) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
additionalJumpStateStep(_, _, node, state, config) or
|
||||
node instanceof ParamNodeEx or
|
||||
node.asNode() instanceof OutNodeExt or
|
||||
store(_, _, node, _, config) or
|
||||
read(_, _, node, config) or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
exists(FlowState s |
|
||||
additionalLocalStateStep(_, s, node, state, config) and
|
||||
s != state
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
additionalJumpStateStep(node, state, next, s, config)
|
||||
or
|
||||
additionalLocalStateStep(node, state, next, s, config) and
|
||||
s != state
|
||||
)
|
||||
or
|
||||
Stage2::revFlow(node, state, config) and
|
||||
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||
Configuration config, LocalCallContext cc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
state1 = state2 and
|
||||
preservesValue = true and
|
||||
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
t = node1.getDataFlowType() // irrelevant dummy value
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
||||
pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||
exists(NodeEx mid, FlowState st |
|
||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
t = node2.getDataFlowType() and
|
||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||
localFlowExit(node2, state1, config) and
|
||||
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)
|
||||
)
|
||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
||||
callContext) and
|
||||
localFlowExit(node2, state2, config)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2769,10 +2695,10 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, _, config) and
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
|
||||
@@ -64,30 +64,13 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Holds if `sink` is a relevant taint sink.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
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. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
@@ -96,29 +79,9 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
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. */
|
||||
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) }
|
||||
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
@@ -126,16 +89,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
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. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
@@ -143,16 +96,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
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`
|
||||
* must be taken into account in the analysis.
|
||||
@@ -164,25 +107,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
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) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
|
||||
@@ -64,30 +64,13 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Holds if `sink` is a relevant taint sink.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
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. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
@@ -96,29 +79,9 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
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. */
|
||||
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) }
|
||||
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
@@ -126,16 +89,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
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. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
@@ -143,16 +96,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
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`
|
||||
* must be taken into account in the analysis.
|
||||
@@ -164,25 +107,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
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) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
|
||||
@@ -129,11 +129,11 @@ private class FromGlobalVarTaintTrackingCfg extends TaintTracking2::Configuratio
|
||||
}
|
||||
|
||||
private predicate readsVariable(LoadInstruction load, Variable var) {
|
||||
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
|
||||
load.getSourceAddress().(VariableAddressInstruction).getASTVariable() = 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. */
|
||||
Element getElementFromPathNode(PathNode pathNode) {
|
||||
exists(DataFlow::Node node | node = pathNode.(WrapPathNode).inner().getNode() |
|
||||
result = node.asInstruction().getAst()
|
||||
result = node.asInstruction().getAST()
|
||||
or
|
||||
result = node.asOperand().getDef().getAst()
|
||||
result = node.asOperand().getDef().getAST()
|
||||
)
|
||||
or
|
||||
result = pathNode.(EndpointPathNode).inner()
|
||||
|
||||
@@ -17,7 +17,7 @@ private import semmle.code.cpp.ir.IR
|
||||
*/
|
||||
Function resolveCall(Call call) {
|
||||
exists(CallInstruction callInstruction |
|
||||
callInstruction.getAst() = call and
|
||||
callInstruction.getAST() = call and
|
||||
result = viableCallable(callInstruction)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -20,4 +20,5 @@ import semmle.code.cpp.ir.dataflow.DataFlow2
|
||||
|
||||
module TaintTracking {
|
||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||
private import semmle.code.cpp.ir.dataflow.TaintTracking2
|
||||
}
|
||||
|
||||
@@ -116,12 +116,12 @@ private module VirtualDispatch {
|
||||
/** Holds if `addressInstr` is an instruction that produces the address of `var`. */
|
||||
private predicate addressOfGlobal(Instruction addressInstr, GlobalOrNamespaceVariable var) {
|
||||
// Access directly to the global variable
|
||||
addressInstr.(VariableAddressInstruction).getAstVariable() = var
|
||||
addressInstr.(VariableAddressInstruction).getASTVariable() = var
|
||||
or
|
||||
// Access to a field on a global union
|
||||
exists(FieldAddressInstruction fa |
|
||||
fa = addressInstr and
|
||||
fa.getObjectAddress().(VariableAddressInstruction).getAstVariable() = var and
|
||||
fa.getObjectAddress().(VariableAddressInstruction).getASTVariable() = var and
|
||||
fa.getField().getDeclaringType() instanceof Union
|
||||
)
|
||||
}
|
||||
|
||||
@@ -87,30 +87,12 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
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. */
|
||||
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. */
|
||||
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
|
||||
* into account in the analysis.
|
||||
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
|
||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||
}
|
||||
|
||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierIn(n)
|
||||
@@ -332,16 +314,7 @@ private predicate fullInBarrier(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) {
|
||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierOut(n)
|
||||
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(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]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||
pragma[inline]
|
||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
not fullOutBarrier(node1, config) and
|
||||
not fullInBarrier(node2, config) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) 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(node2, s2, config)
|
||||
)
|
||||
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) 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(node2, s2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -920,8 +870,8 @@ private module Stage1 {
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
revFlow(node, true, config) and
|
||||
fwdFlow(node, true, config) and
|
||||
not fullInBarrier(node, config) and
|
||||
not fullOutBarrier(node, config)
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
}
|
||||
|
||||
/** Holds if flow may return from `callable`. */
|
||||
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
|
||||
) {
|
||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not fullOutBarrier(ret, config) and
|
||||
not fullInBarrier(out, config)
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
not fullOutBarrier(arg, config) and
|
||||
not fullInBarrier(p, config)
|
||||
not outBarrier(arg, config) and
|
||||
not inBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
Stage2::revFlow(node, state, config) and
|
||||
(
|
||||
sourceNode(node, state, config)
|
||||
or
|
||||
jumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStateStep(_, _, node, state, config)
|
||||
or
|
||||
node instanceof ParamNodeEx
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
or
|
||||
sourceNode(node, state, config) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
additionalJumpStateStep(_, _, node, state, config) or
|
||||
node instanceof ParamNodeEx or
|
||||
node.asNode() instanceof OutNodeExt or
|
||||
store(_, _, node, _, config) or
|
||||
read(_, _, node, config) or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
exists(FlowState s |
|
||||
additionalLocalStateStep(_, s, node, state, config) and
|
||||
s != state
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
additionalJumpStateStep(node, state, next, s, config)
|
||||
or
|
||||
additionalLocalStateStep(node, state, next, s, config) and
|
||||
s != state
|
||||
)
|
||||
or
|
||||
Stage2::revFlow(node, state, config) and
|
||||
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||
Configuration config, LocalCallContext cc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
state1 = state2 and
|
||||
preservesValue = true and
|
||||
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
t = node1.getDataFlowType() // irrelevant dummy value
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
||||
pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||
exists(NodeEx mid, FlowState st |
|
||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
t = node2.getDataFlowType() and
|
||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||
localFlowExit(node2, state1, config) and
|
||||
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)
|
||||
)
|
||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
||||
callContext) and
|
||||
localFlowExit(node2, state2, config)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2769,10 +2695,10 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, _, config) and
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
|
||||
@@ -87,30 +87,12 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
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. */
|
||||
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. */
|
||||
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
|
||||
* into account in the analysis.
|
||||
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
|
||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||
}
|
||||
|
||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierIn(n)
|
||||
@@ -332,16 +314,7 @@ private predicate fullInBarrier(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) {
|
||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierOut(n)
|
||||
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(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]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||
pragma[inline]
|
||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
not fullOutBarrier(node1, config) and
|
||||
not fullInBarrier(node2, config) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) 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(node2, s2, config)
|
||||
)
|
||||
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) 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(node2, s2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -920,8 +870,8 @@ private module Stage1 {
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
revFlow(node, true, config) and
|
||||
fwdFlow(node, true, config) and
|
||||
not fullInBarrier(node, config) and
|
||||
not fullOutBarrier(node, config)
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
}
|
||||
|
||||
/** Holds if flow may return from `callable`. */
|
||||
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
|
||||
) {
|
||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not fullOutBarrier(ret, config) and
|
||||
not fullInBarrier(out, config)
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
not fullOutBarrier(arg, config) and
|
||||
not fullInBarrier(p, config)
|
||||
not outBarrier(arg, config) and
|
||||
not inBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
Stage2::revFlow(node, state, config) and
|
||||
(
|
||||
sourceNode(node, state, config)
|
||||
or
|
||||
jumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStateStep(_, _, node, state, config)
|
||||
or
|
||||
node instanceof ParamNodeEx
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
or
|
||||
sourceNode(node, state, config) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
additionalJumpStateStep(_, _, node, state, config) or
|
||||
node instanceof ParamNodeEx or
|
||||
node.asNode() instanceof OutNodeExt or
|
||||
store(_, _, node, _, config) or
|
||||
read(_, _, node, config) or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
exists(FlowState s |
|
||||
additionalLocalStateStep(_, s, node, state, config) and
|
||||
s != state
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
additionalJumpStateStep(node, state, next, s, config)
|
||||
or
|
||||
additionalLocalStateStep(node, state, next, s, config) and
|
||||
s != state
|
||||
)
|
||||
or
|
||||
Stage2::revFlow(node, state, config) and
|
||||
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||
Configuration config, LocalCallContext cc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
state1 = state2 and
|
||||
preservesValue = true and
|
||||
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
t = node1.getDataFlowType() // irrelevant dummy value
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
||||
pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||
exists(NodeEx mid, FlowState st |
|
||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
t = node2.getDataFlowType() and
|
||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||
localFlowExit(node2, state1, config) and
|
||||
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)
|
||||
)
|
||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
||||
callContext) and
|
||||
localFlowExit(node2, state2, config)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2769,10 +2695,10 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, _, config) and
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
|
||||
@@ -87,30 +87,12 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
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. */
|
||||
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. */
|
||||
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
|
||||
* into account in the analysis.
|
||||
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
|
||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||
}
|
||||
|
||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierIn(n)
|
||||
@@ -332,16 +314,7 @@ private predicate fullInBarrier(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) {
|
||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierOut(n)
|
||||
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(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]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||
pragma[inline]
|
||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
not fullOutBarrier(node1, config) and
|
||||
not fullInBarrier(node2, config) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) 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(node2, s2, config)
|
||||
)
|
||||
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) 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(node2, s2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -920,8 +870,8 @@ private module Stage1 {
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
revFlow(node, true, config) and
|
||||
fwdFlow(node, true, config) and
|
||||
not fullInBarrier(node, config) and
|
||||
not fullOutBarrier(node, config)
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
}
|
||||
|
||||
/** Holds if flow may return from `callable`. */
|
||||
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
|
||||
) {
|
||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not fullOutBarrier(ret, config) and
|
||||
not fullInBarrier(out, config)
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
not fullOutBarrier(arg, config) and
|
||||
not fullInBarrier(p, config)
|
||||
not outBarrier(arg, config) and
|
||||
not inBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
Stage2::revFlow(node, state, config) and
|
||||
(
|
||||
sourceNode(node, state, config)
|
||||
or
|
||||
jumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStateStep(_, _, node, state, config)
|
||||
or
|
||||
node instanceof ParamNodeEx
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
or
|
||||
sourceNode(node, state, config) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
additionalJumpStateStep(_, _, node, state, config) or
|
||||
node instanceof ParamNodeEx or
|
||||
node.asNode() instanceof OutNodeExt or
|
||||
store(_, _, node, _, config) or
|
||||
read(_, _, node, config) or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
exists(FlowState s |
|
||||
additionalLocalStateStep(_, s, node, state, config) and
|
||||
s != state
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
additionalJumpStateStep(node, state, next, s, config)
|
||||
or
|
||||
additionalLocalStateStep(node, state, next, s, config) and
|
||||
s != state
|
||||
)
|
||||
or
|
||||
Stage2::revFlow(node, state, config) and
|
||||
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||
Configuration config, LocalCallContext cc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
state1 = state2 and
|
||||
preservesValue = true and
|
||||
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
t = node1.getDataFlowType() // irrelevant dummy value
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
||||
pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||
exists(NodeEx mid, FlowState st |
|
||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
t = node2.getDataFlowType() and
|
||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||
localFlowExit(node2, state1, config) and
|
||||
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)
|
||||
)
|
||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
||||
callContext) and
|
||||
localFlowExit(node2, state2, config)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2769,10 +2695,10 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, _, config) and
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
|
||||
@@ -87,30 +87,12 @@ abstract class Configuration extends string {
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
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. */
|
||||
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. */
|
||||
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
|
||||
* into account in the analysis.
|
||||
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
|
||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||
}
|
||||
|
||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
||||
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierIn(n)
|
||||
@@ -332,16 +314,7 @@ private predicate fullInBarrier(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) {
|
||||
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
config.isBarrierOut(n)
|
||||
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(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]
|
||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
|
||||
exists(Node n | node.asNode() = n |
|
||||
exists(Node n |
|
||||
node.asNode() = n and
|
||||
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()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||
pragma[inline]
|
||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||
not fullOutBarrier(node1, config) and
|
||||
not fullInBarrier(node2, config) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) 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(node2, s2, config)
|
||||
)
|
||||
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
|
||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) 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(node2, s2, config) and
|
||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
@@ -920,8 +870,8 @@ private module Stage1 {
|
||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||
revFlow(node, true, config) and
|
||||
fwdFlow(node, true, config) and
|
||||
not fullInBarrier(node, config) and
|
||||
not fullOutBarrier(node, config)
|
||||
not inBarrier(node, config) and
|
||||
not outBarrier(node, config)
|
||||
}
|
||||
|
||||
/** Holds if flow may return from `callable`. */
|
||||
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
|
||||
) {
|
||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||
Stage1::revFlow(ret, config) and
|
||||
not fullOutBarrier(ret, config) and
|
||||
not fullInBarrier(out, config)
|
||||
not outBarrier(ret, config) and
|
||||
not inBarrier(out, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
not fullOutBarrier(arg, config) and
|
||||
not fullInBarrier(p, config)
|
||||
not outBarrier(arg, config) and
|
||||
not inBarrier(p, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
|
||||
Stage2::revFlow(node, state, config) and
|
||||
(
|
||||
sourceNode(node, state, config)
|
||||
or
|
||||
jumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStep(_, node, config)
|
||||
or
|
||||
additionalJumpStateStep(_, _, node, state, config)
|
||||
or
|
||||
node instanceof ParamNodeEx
|
||||
or
|
||||
node.asNode() instanceof OutNodeExt
|
||||
or
|
||||
store(_, _, node, _, config)
|
||||
or
|
||||
read(_, _, node, config)
|
||||
or
|
||||
sourceNode(node, state, config) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
additionalJumpStateStep(_, _, node, state, config) or
|
||||
node instanceof ParamNodeEx or
|
||||
node.asNode() instanceof OutNodeExt or
|
||||
store(_, _, node, _, config) or
|
||||
read(_, _, node, config) or
|
||||
node instanceof FlowCheckNode
|
||||
or
|
||||
exists(FlowState s |
|
||||
additionalLocalStateStep(_, s, node, state, config) and
|
||||
s != state
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
|
||||
or
|
||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||
additionalJumpStateStep(node, state, next, s, config)
|
||||
or
|
||||
additionalLocalStateStep(node, state, next, s, config) and
|
||||
s != state
|
||||
)
|
||||
or
|
||||
Stage2::revFlow(node, state, config) and
|
||||
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||
Configuration config, LocalCallContext cc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
state1 = state2 and
|
||||
preservesValue = true and
|
||||
t = node1.getDataFlowType() and // irrelevant dummy value
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
t = node1.getDataFlowType() // irrelevant dummy value
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
|
||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
|
||||
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
|
||||
pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
|
||||
exists(NodeEx mid, FlowState st |
|
||||
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType()
|
||||
t = node2.getDataFlowType() and
|
||||
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
||||
localFlowExit(node2, state1, config) and
|
||||
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)
|
||||
)
|
||||
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
|
||||
callContext) and
|
||||
localFlowExit(node2, state2, config)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2769,10 +2695,10 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, _, config) and
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
|
||||
@@ -431,7 +431,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
||||
|
||||
SsaPhiNode() { this = TSsaPhiNode(phi) }
|
||||
|
||||
/** Gets the phi node associated with this node. */
|
||||
/* Get the phi node associated with this node. */
|
||||
Ssa::PhiNode getPhiNode() { result = phi }
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
@@ -287,6 +287,20 @@ 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`.
|
||||
*/
|
||||
|
||||
@@ -64,30 +64,13 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Holds if `sink` is a relevant taint sink.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
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. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
@@ -96,29 +79,9 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
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. */
|
||||
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) }
|
||||
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
@@ -126,16 +89,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
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. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
@@ -143,16 +96,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
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`
|
||||
* must be taken into account in the analysis.
|
||||
@@ -164,25 +107,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
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) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
|
||||
@@ -64,30 +64,13 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Holds if `sink` is a relevant taint sink.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
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. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
@@ -96,29 +79,9 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
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. */
|
||||
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) }
|
||||
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
@@ -126,16 +89,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
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. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
@@ -143,16 +96,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
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`
|
||||
* must be taken into account in the analysis.
|
||||
@@ -164,25 +107,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
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) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
|
||||
@@ -64,30 +64,13 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Holds if `sink` is a relevant taint sink.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
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. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
@@ -96,29 +79,9 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
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. */
|
||||
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) }
|
||||
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
@@ -126,16 +89,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
|
||||
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. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
@@ -143,16 +96,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
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`
|
||||
* must be taken into account in the analysis.
|
||||
@@ -164,25 +107,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
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) {
|
||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
|
||||
@@ -55,10 +55,7 @@ class IRVariable extends TIRVariable {
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
Language::AST getAst() { none() }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = getAst() }
|
||||
Language::AST getAST() { none() }
|
||||
|
||||
/**
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
@@ -69,7 +66,7 @@ class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* 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.
|
||||
@@ -93,10 +90,7 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
|
||||
final override string toString() { result = getVariable().toString() }
|
||||
|
||||
final override Language::AST getAst() { result = var }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Language::AST getAST() { result = getAst() }
|
||||
final override Language::AST getAST() { result = var }
|
||||
|
||||
final override string getUniqueId() {
|
||||
result = getVariable().toString() + " " + getVariable().getLocation().toString()
|
||||
@@ -163,10 +157,7 @@ class IRGeneratedVariable extends IRVariable {
|
||||
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAst() { result = ast }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Language::AST getAST() { result = getAst() }
|
||||
final override Language::AST getAST() { result = ast }
|
||||
|
||||
override string toString() { result = getBaseString() + getLocationString() }
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ class Instruction extends Construction::TStageInstruction {
|
||||
}
|
||||
|
||||
/** 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
|
||||
@@ -136,7 +136,7 @@ class Instruction extends Construction::TStageInstruction {
|
||||
string getResultId() {
|
||||
this.shouldGenerateDumpStrings() and
|
||||
result =
|
||||
this.getResultPrefix() + this.getAst().getLocation().getStartLine() + "_" + this.getLineRank()
|
||||
this.getResultPrefix() + this.getAST().getLocation().getStartLine() + "_" + this.getLineRank()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,15 +208,12 @@ class Instruction extends Construction::TStageInstruction {
|
||||
/**
|
||||
* Gets the AST that caused this instruction to be generated.
|
||||
*/
|
||||
final Language::AST getAst() { result = Construction::getInstructionAst(this) }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = this.getAst() }
|
||||
final Language::AST getAST() { result = Construction::getInstructionAST(this) }
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -462,10 +459,7 @@ class VariableInstruction extends Instruction {
|
||||
/**
|
||||
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
|
||||
*/
|
||||
final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() }
|
||||
|
||||
/** DEPRECATED: Alias for getAstVariable */
|
||||
deprecated Language::Variable getASTVariable() { result = this.getAstVariable() }
|
||||
final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,7 @@ private import internal.OperandInternal
|
||||
* of `TOperand` that are used in this stage.
|
||||
*/
|
||||
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
|
||||
@@ -38,7 +38,7 @@ class Operand extends TStageOperand {
|
||||
// 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))
|
||||
or
|
||||
exists(Instruction use | this = nonSsaMemoryOperand(use, _))
|
||||
exists(Instruction use | this = nonSSAMemoryOperand(use, _))
|
||||
or
|
||||
exists(Instruction use, Instruction def, IRBlock predecessorBlock |
|
||||
this = phiOperand(use, def, predecessorBlock, _) or
|
||||
@@ -209,7 +209,7 @@ class Operand extends TStageOperand {
|
||||
class MemoryOperand extends Operand {
|
||||
cached
|
||||
MemoryOperand() {
|
||||
this instanceof TNonSsaMemoryOperand or
|
||||
this instanceof TNonSSAMemoryOperand or
|
||||
this instanceof TPhiOperand or
|
||||
this instanceof TChiOperand
|
||||
}
|
||||
@@ -249,7 +249,7 @@ class NonPhiOperand extends Operand {
|
||||
|
||||
NonPhiOperand() {
|
||||
this = registerOperand(useInstr, tag, _) or
|
||||
this = nonSsaMemoryOperand(useInstr, tag) or
|
||||
this = nonSSAMemoryOperand(useInstr, tag) or
|
||||
this = chiOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
||||
|
||||
cached
|
||||
NonPhiMemoryOperand() {
|
||||
this = nonSsaMemoryOperand(useInstr, tag)
|
||||
this = nonSSAMemoryOperand(useInstr, tag)
|
||||
or
|
||||
this = chiOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
// count rather than strictcount to handle missing AST elements
|
||||
// separate instanceof and inline casts to avoid failed casts with a count of 0
|
||||
instr instanceof VariableAddressInstruction and
|
||||
count(instr.(VariableAddressInstruction).getIRVariable().getAst()) != 1
|
||||
count(instr.(VariableAddressInstruction).getIRVariable().getAST()) != 1
|
||||
or
|
||||
instr instanceof ConstantInstruction and
|
||||
count(instr.getResultIRType()) != 1
|
||||
@@ -121,7 +121,7 @@ private predicate variableAddressValueNumber(
|
||||
// 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
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
unique( | | instr.getIRVariable().getAst()) = ast
|
||||
unique( | | instr.getIRVariable().getAST()) = ast
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(
|
||||
@@ -131,7 +131,7 @@ private predicate initializeParameterValueNumber(
|
||||
// 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
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
instr.getIRVariable().getAst() = var
|
||||
instr.getIRVariable().getAST() = var
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
|
||||
@@ -2,12 +2,12 @@ private import AliasConfigurationInternal
|
||||
private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR
|
||||
private import cpp
|
||||
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 =
|
||||
TVariableAllocation(IRVariable var) {
|
||||
// Only model variables that were not already handled in unaliased SSA.
|
||||
not UnaliasedSsa::canReuseSsaForVariable(var)
|
||||
not UnaliasedSSA::canReuseSSAForVariable(var)
|
||||
} or
|
||||
TIndirectParameterAllocation(IRAutomaticVariable var) {
|
||||
exists(InitializeIndirectionInstruction instr | instr.getIRVariable() = var)
|
||||
|
||||
@@ -133,10 +133,7 @@ abstract class MemoryLocation extends TMemoryLocation {
|
||||
*/
|
||||
predicate isAlwaysAllocatedOnStack() { none() }
|
||||
|
||||
final predicate canReuseSsa() { none() }
|
||||
|
||||
/** DEPRECATED: Alias for canReuseSsa */
|
||||
deprecated predicate canReuseSSA() { canReuseSsa() }
|
||||
final predicate canReuseSSA() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -572,16 +569,13 @@ private Overlap getVariableMemoryLocationOverlap(
|
||||
* Holds if the def/use information for the result of `instr` can be reused from the previous
|
||||
* iteration of the IR.
|
||||
*/
|
||||
predicate canReuseSsaForOldResult(Instruction instr) { OldSSA::canReuseSsaForMemoryResult(instr) }
|
||||
|
||||
/** DEPRECATED: Alias for canReuseSsaForOldResult */
|
||||
deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1;
|
||||
predicate canReuseSSAForOldResult(Instruction instr) { OldSSA::canReuseSSAForMemoryResult(instr) }
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
MemoryLocation getResultMemoryLocation(Instruction instr) {
|
||||
not canReuseSsaForOldResult(instr) and
|
||||
not canReuseSSAForOldResult(instr) and
|
||||
exists(MemoryAccessKind kind, boolean isMayAccess |
|
||||
kind = instr.getResultMemoryAccess() and
|
||||
(if instr.hasResultMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and
|
||||
@@ -614,7 +608,7 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
|
||||
}
|
||||
|
||||
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
||||
not canReuseSsaForOldResult(operand.getAnyDef()) and
|
||||
not canReuseSSAForOldResult(operand.getAnyDef()) and
|
||||
exists(MemoryAccessKind kind, boolean isMayAccess |
|
||||
kind = operand.getMemoryAccess() and
|
||||
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
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 Alias
|
||||
private import SSAConstruction
|
||||
private import DebugSsa
|
||||
private import DebugSSA
|
||||
|
||||
bindingset[offset]
|
||||
private string getKeySuffixForOffset(int offset) {
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
private import SSAConstruction as SSA
|
||||
import SSA::SsaConsistency
|
||||
import SSA::SSAConsistency
|
||||
|
||||
@@ -112,7 +112,7 @@ private module Cached {
|
||||
exists(Alias::getResultMemoryLocation(oldInstruction))
|
||||
or
|
||||
// This result was already modeled by a previous iteration of SSA.
|
||||
Alias::canReuseSsaForOldResult(oldInstruction)
|
||||
Alias::canReuseSSAForOldResult(oldInstruction)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -182,7 +182,7 @@ private module Cached {
|
||||
* unreachable, this predicate will recurse through any degenerate `Phi` instructions to find the
|
||||
* true definition.
|
||||
*/
|
||||
private Instruction getNewDefinitionFromOldSsa(OldIR::MemoryOperand oldOperand, Overlap overlap) {
|
||||
private Instruction getNewDefinitionFromOldSSA(OldIR::MemoryOperand oldOperand, Overlap overlap) {
|
||||
exists(Overlap originalOverlap |
|
||||
originalOverlap = oldOperand.getDefinitionOverlap() and
|
||||
(
|
||||
@@ -191,7 +191,7 @@ private module Cached {
|
||||
or
|
||||
exists(OldIR::PhiInputOperand phiOperand, Overlap phiOperandOverlap |
|
||||
phiOperand = getDegeneratePhiOperand(oldOperand.getAnyDef()) and
|
||||
result = getNewDefinitionFromOldSsa(phiOperand, phiOperandOverlap) and
|
||||
result = getNewDefinitionFromOldSSA(phiOperand, phiOperandOverlap) and
|
||||
overlap =
|
||||
combineOverlap(pragma[only_bind_out](phiOperandOverlap),
|
||||
pragma[only_bind_out](originalOverlap))
|
||||
@@ -233,7 +233,7 @@ private module Cached {
|
||||
)
|
||||
or
|
||||
exists(OldIR::NonPhiMemoryOperand oldOperand |
|
||||
result = getNewDefinitionFromOldSsa(oldOperand, overlap) and
|
||||
result = getNewDefinitionFromOldSSA(oldOperand, overlap) and
|
||||
oldOperand.getUse() = instruction and
|
||||
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
|
||||
* `newPredecessorBlock`, based on that operand's definition in the old IR.
|
||||
*/
|
||||
private Instruction getNewPhiOperandDefinitionFromOldSsa(
|
||||
private Instruction getNewPhiOperandDefinitionFromOldSSA(
|
||||
Instruction instr, IRBlock newPredecessorBlock, Overlap overlap
|
||||
) {
|
||||
exists(OldIR::PhiInstruction oldPhi, OldIR::PhiInputOperand oldOperand |
|
||||
oldPhi = getOldInstruction(instr) 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)
|
||||
)
|
||||
or
|
||||
result = getNewPhiOperandDefinitionFromOldSsa(instr, newPredecessorBlock, overlap)
|
||||
result = getNewPhiOperandDefinitionFromOldSSA(instr, newPredecessorBlock, overlap)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -412,17 +412,17 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Language::AST getInstructionAst(Instruction instr) {
|
||||
result = getOldInstruction(instr).getAst()
|
||||
Language::AST getInstructionAST(Instruction instr) {
|
||||
result = getOldInstruction(instr).getAST()
|
||||
or
|
||||
exists(RawIR::Instruction blockStartInstr |
|
||||
instr = phiInstruction(blockStartInstr, _) and
|
||||
result = blockStartInstr.getAst()
|
||||
result = blockStartInstr.getAST()
|
||||
)
|
||||
or
|
||||
exists(RawIR::Instruction primaryInstr |
|
||||
instr = chiInstruction(primaryInstr) and
|
||||
result = primaryInstr.getAst()
|
||||
result = primaryInstr.getAST()
|
||||
)
|
||||
or
|
||||
exists(IRFunctionBase irFunc |
|
||||
@@ -430,12 +430,6 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for getInstructionAst */
|
||||
cached
|
||||
deprecated Language::AST getInstructionAST(Instruction instr) {
|
||||
result = getInstructionAst(instr)
|
||||
}
|
||||
|
||||
cached
|
||||
Language::LanguageType getInstructionResultType(Instruction instr) {
|
||||
result = instr.(RawIR::Instruction).getResultLanguageType()
|
||||
@@ -981,41 +975,35 @@ module DefUse {
|
||||
}
|
||||
}
|
||||
|
||||
predicate canReuseSsaForMemoryResult(Instruction instruction) {
|
||||
predicate canReuseSSAForMemoryResult(Instruction instruction) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
(
|
||||
// The previous iteration said it was reusable, so we should mark it as reusable as well.
|
||||
Alias::canReuseSsaForOldResult(oldInstruction)
|
||||
Alias::canReuseSSAForOldResult(oldInstruction)
|
||||
or
|
||||
// The current alias analysis says it is reusable.
|
||||
Alias::getResultMemoryLocation(oldInstruction).canReuseSsa()
|
||||
Alias::getResultMemoryLocation(oldInstruction).canReuseSSA()
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(Alias::MemoryLocation defLocation |
|
||||
// This is a `Phi` for a reusable location, so the result of the `Phi` is reusable as well.
|
||||
instruction = phiInstruction(_, defLocation) and
|
||||
defLocation.canReuseSsa()
|
||||
defLocation.canReuseSSA()
|
||||
)
|
||||
// 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
|
||||
* `DebugSSA` module, which is then imported by PrintSSA.
|
||||
*/
|
||||
module DebugSsa {
|
||||
module DebugSSA {
|
||||
import PhiInsertion
|
||||
import DefUse
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for DebugSsa */
|
||||
deprecated module DebugSSA = DebugSsa;
|
||||
|
||||
import CachedForDebugging
|
||||
|
||||
cached
|
||||
@@ -1050,7 +1038,7 @@ private module CachedForDebugging {
|
||||
|
||||
private OldIR::IRTempVariable getOldTempVariable(IRTempVariable var) {
|
||||
result.getEnclosingFunction() = var.getEnclosingFunction() and
|
||||
result.getAst() = var.getAst() and
|
||||
result.getAST() = var.getAST() and
|
||||
result.getTag() = var.getTag()
|
||||
}
|
||||
|
||||
@@ -1073,7 +1061,7 @@ private module CachedForDebugging {
|
||||
int maxValue() { result = 2147483647 }
|
||||
}
|
||||
|
||||
module SsaConsistency {
|
||||
module SSAConsistency {
|
||||
/**
|
||||
* Holds if a `MemoryOperand` has more than one `MemoryLocation` assigned by alias analysis.
|
||||
*/
|
||||
@@ -1126,9 +1114,6 @@ 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
|
||||
* 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.Dominance as Dominance
|
||||
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 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)
|
||||
} or
|
||||
TUnaliasedSsaPhiInstruction(
|
||||
TRawInstruction blockStartInstr, UnaliasedSsa::SSA::MemoryLocation memoryLocation
|
||||
TUnaliasedSSAPhiInstruction(
|
||||
TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation
|
||||
) {
|
||||
UnaliasedSsa::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
||||
UnaliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
||||
} or
|
||||
TUnaliasedSsaChiInstruction(TRawInstruction primaryInstruction) { none() } or
|
||||
TUnaliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
|
||||
UnaliasedSsa::SSA::hasUnreachedInstruction(irFunc)
|
||||
TUnaliasedSSAChiInstruction(TRawInstruction primaryInstruction) { none() } or
|
||||
TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) {
|
||||
UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc)
|
||||
} or
|
||||
TAliasedSsaPhiInstruction(
|
||||
TAliasedSSAPhiInstruction(
|
||||
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
|
||||
) {
|
||||
AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
||||
} or
|
||||
TAliasedSsaChiInstruction(TRawInstruction primaryInstruction) {
|
||||
TAliasedSSAChiInstruction(TRawInstruction primaryInstruction) {
|
||||
AliasedSSA::SSA::hasChiInstruction(primaryInstruction)
|
||||
} or
|
||||
TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
|
||||
TAliasedSSAUnreachedInstruction(IRFunctionBase irFunc) {
|
||||
AliasedSSA::SSA::hasUnreachedInstruction(irFunc)
|
||||
}
|
||||
|
||||
@@ -46,64 +46,58 @@ newtype TInstruction =
|
||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||
* a class alias.
|
||||
*/
|
||||
module UnaliasedSsaInstructions {
|
||||
class TPhiInstruction = TUnaliasedSsaPhiInstruction;
|
||||
module UnaliasedSSAInstructions {
|
||||
class TPhiInstruction = TUnaliasedSSAPhiInstruction;
|
||||
|
||||
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() }
|
||||
|
||||
class TChiInstruction = TUnaliasedSsaChiInstruction;
|
||||
class TChiInstruction = TUnaliasedSSAChiInstruction;
|
||||
|
||||
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
|
||||
result = TUnaliasedSsaChiInstruction(primaryInstruction)
|
||||
result = TUnaliasedSSAChiInstruction(primaryInstruction)
|
||||
}
|
||||
|
||||
class TUnreachedInstruction = TUnaliasedSsaUnreachedInstruction;
|
||||
class TUnreachedInstruction = TUnaliasedSSAUnreachedInstruction;
|
||||
|
||||
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
|
||||
* aliased SSA stage.
|
||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||
* a class alias.
|
||||
*/
|
||||
module AliasedSsaInstructions {
|
||||
class TPhiInstruction = TAliasedSsaPhiInstruction or TUnaliasedSsaPhiInstruction;
|
||||
module AliasedSSAInstructions {
|
||||
class TPhiInstruction = TAliasedSSAPhiInstruction or TUnaliasedSSAPhiInstruction;
|
||||
|
||||
TPhiInstruction phiInstruction(
|
||||
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
|
||||
) {
|
||||
result = TAliasedSsaPhiInstruction(blockStartInstr, memoryLocation)
|
||||
result = TAliasedSSAPhiInstruction(blockStartInstr, memoryLocation)
|
||||
}
|
||||
|
||||
TPhiInstruction reusedPhiInstruction(TRawInstruction blockStartInstr) {
|
||||
result = TUnaliasedSsaPhiInstruction(blockStartInstr, _)
|
||||
result = TUnaliasedSSAPhiInstruction(blockStartInstr, _)
|
||||
}
|
||||
|
||||
class TChiInstruction = TAliasedSsaChiInstruction;
|
||||
class TChiInstruction = TAliasedSSAChiInstruction;
|
||||
|
||||
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
|
||||
result = TAliasedSsaChiInstruction(primaryInstruction)
|
||||
result = TAliasedSSAChiInstruction(primaryInstruction)
|
||||
}
|
||||
|
||||
class TUnreachedInstruction = TAliasedSsaUnreachedInstruction;
|
||||
class TUnreachedInstruction = TAliasedSSAUnreachedInstruction;
|
||||
|
||||
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.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
|
||||
|
||||
@@ -31,7 +31,7 @@ private module Internal {
|
||||
TNoOperand() { none() } or
|
||||
// Can be "removed" later when there's unreachable code
|
||||
// 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
|
||||
useInstr.getOpcode().hasOperand(tag)
|
||||
} or
|
||||
@@ -49,11 +49,11 @@ private module Internal {
|
||||
// important that we use the same definition of "is variable aliased" across
|
||||
// the phases.
|
||||
TAliasedPhiOperand(
|
||||
TAliasedSsaPhiInstruction useInstr, Aliased::IRBlock predecessorBlock, Overlap overlap
|
||||
TAliasedSSAPhiInstruction useInstr, Aliased::IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
exists(AliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap))
|
||||
} or
|
||||
TAliasedChiOperand(TAliasedSsaChiInstruction useInstr, ChiOperandTag tag) { any() }
|
||||
TAliasedChiOperand(TAliasedSSAChiInstruction useInstr, ChiOperandTag tag) { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,21 +72,13 @@ private module Shared {
|
||||
result = Internal::TRegisterOperand(useInstr, tag, defInstr)
|
||||
}
|
||||
|
||||
class TNonSsaMemoryOperand = Internal::TNonSsaMemoryOperand;
|
||||
|
||||
/** DEPRECATED: Alias for TNonSsaMemoryOperand */
|
||||
deprecated class TNonSSAMemoryOperand = TNonSsaMemoryOperand;
|
||||
class TNonSSAMemoryOperand = Internal::TNonSSAMemoryOperand;
|
||||
|
||||
/**
|
||||
* Returns the non-Phi memory operand with the specified parameters.
|
||||
*/
|
||||
TNonSsaMemoryOperand nonSsaMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) {
|
||||
result = Internal::TNonSsaMemoryOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for nonSsaMemoryOperand */
|
||||
deprecated TNonSSAMemoryOperand nonSSAMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) {
|
||||
result = nonSsaMemoryOperand(useInstr, tag)
|
||||
TNonSSAMemoryOperand nonSSAMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) {
|
||||
result = Internal::TNonSSAMemoryOperand(useInstr, tag)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +95,7 @@ module RawOperands {
|
||||
|
||||
class TChiOperand = Internal::TNoOperand;
|
||||
|
||||
class TNonPhiMemoryOperand = TNonSsaMemoryOperand or TChiOperand;
|
||||
class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand;
|
||||
|
||||
/**
|
||||
* Returns the Phi operand with the specified parameters.
|
||||
@@ -134,14 +126,14 @@ module RawOperands {
|
||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||
* a class alias.
|
||||
*/
|
||||
module UnaliasedSsaOperands {
|
||||
module UnaliasedSSAOperands {
|
||||
import Shared
|
||||
|
||||
class TPhiOperand = Internal::TUnaliasedPhiOperand;
|
||||
|
||||
class TChiOperand = Internal::TNoOperand;
|
||||
|
||||
class TNonPhiMemoryOperand = TNonSsaMemoryOperand or TChiOperand;
|
||||
class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand;
|
||||
|
||||
/**
|
||||
* Returns the Phi operand with the specified parameters.
|
||||
@@ -167,23 +159,20 @@ module UnaliasedSsaOperands {
|
||||
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
|
||||
* asliased SSA stage.
|
||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||
* a class alias.
|
||||
*/
|
||||
module AliasedSsaOperands {
|
||||
module AliasedSSAOperands {
|
||||
import Shared
|
||||
|
||||
class TPhiOperand = Internal::TAliasedPhiOperand or Internal::TUnaliasedPhiOperand;
|
||||
|
||||
class TChiOperand = Internal::TAliasedChiOperand;
|
||||
|
||||
class TNonPhiMemoryOperand = TNonSsaMemoryOperand or TChiOperand;
|
||||
class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand;
|
||||
|
||||
/**
|
||||
* Returns the Phi operand with the specified parameters.
|
||||
@@ -213,10 +202,7 @@ module AliasedSsaOperands {
|
||||
/**
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for AliasedSsaOperands */
|
||||
deprecated module AliasedSSAOperands = AliasedSsaOperands;
|
||||
|
||||
@@ -55,10 +55,7 @@ class IRVariable extends TIRVariable {
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
Language::AST getAst() { none() }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = getAst() }
|
||||
Language::AST getAST() { none() }
|
||||
|
||||
/**
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
@@ -69,7 +66,7 @@ class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* 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.
|
||||
@@ -93,10 +90,7 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
|
||||
final override string toString() { result = getVariable().toString() }
|
||||
|
||||
final override Language::AST getAst() { result = var }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Language::AST getAST() { result = getAst() }
|
||||
final override Language::AST getAST() { result = var }
|
||||
|
||||
final override string getUniqueId() {
|
||||
result = getVariable().toString() + " " + getVariable().getLocation().toString()
|
||||
@@ -163,10 +157,7 @@ class IRGeneratedVariable extends IRVariable {
|
||||
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAst() { result = ast }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Language::AST getAST() { result = getAst() }
|
||||
final override Language::AST getAST() { result = ast }
|
||||
|
||||
override string toString() { result = getBaseString() + getLocationString() }
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ class Instruction extends Construction::TStageInstruction {
|
||||
}
|
||||
|
||||
/** 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
|
||||
@@ -136,7 +136,7 @@ class Instruction extends Construction::TStageInstruction {
|
||||
string getResultId() {
|
||||
this.shouldGenerateDumpStrings() and
|
||||
result =
|
||||
this.getResultPrefix() + this.getAst().getLocation().getStartLine() + "_" + this.getLineRank()
|
||||
this.getResultPrefix() + this.getAST().getLocation().getStartLine() + "_" + this.getLineRank()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,15 +208,12 @@ class Instruction extends Construction::TStageInstruction {
|
||||
/**
|
||||
* Gets the AST that caused this instruction to be generated.
|
||||
*/
|
||||
final Language::AST getAst() { result = Construction::getInstructionAst(this) }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = this.getAst() }
|
||||
final Language::AST getAST() { result = Construction::getInstructionAST(this) }
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -462,10 +459,7 @@ class VariableInstruction extends Instruction {
|
||||
/**
|
||||
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
|
||||
*/
|
||||
final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() }
|
||||
|
||||
/** DEPRECATED: Alias for getAstVariable */
|
||||
deprecated Language::Variable getASTVariable() { result = this.getAstVariable() }
|
||||
final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,7 @@ private import internal.OperandInternal
|
||||
* of `TOperand` that are used in this stage.
|
||||
*/
|
||||
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
|
||||
@@ -38,7 +38,7 @@ class Operand extends TStageOperand {
|
||||
// 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))
|
||||
or
|
||||
exists(Instruction use | this = nonSsaMemoryOperand(use, _))
|
||||
exists(Instruction use | this = nonSSAMemoryOperand(use, _))
|
||||
or
|
||||
exists(Instruction use, Instruction def, IRBlock predecessorBlock |
|
||||
this = phiOperand(use, def, predecessorBlock, _) or
|
||||
@@ -209,7 +209,7 @@ class Operand extends TStageOperand {
|
||||
class MemoryOperand extends Operand {
|
||||
cached
|
||||
MemoryOperand() {
|
||||
this instanceof TNonSsaMemoryOperand or
|
||||
this instanceof TNonSSAMemoryOperand or
|
||||
this instanceof TPhiOperand or
|
||||
this instanceof TChiOperand
|
||||
}
|
||||
@@ -249,7 +249,7 @@ class NonPhiOperand extends Operand {
|
||||
|
||||
NonPhiOperand() {
|
||||
this = registerOperand(useInstr, tag, _) or
|
||||
this = nonSsaMemoryOperand(useInstr, tag) or
|
||||
this = nonSSAMemoryOperand(useInstr, tag) or
|
||||
this = chiOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
||||
|
||||
cached
|
||||
NonPhiMemoryOperand() {
|
||||
this = nonSsaMemoryOperand(useInstr, tag)
|
||||
this = nonSSAMemoryOperand(useInstr, tag)
|
||||
or
|
||||
this = chiOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
// count rather than strictcount to handle missing AST elements
|
||||
// separate instanceof and inline casts to avoid failed casts with a count of 0
|
||||
instr instanceof VariableAddressInstruction and
|
||||
count(instr.(VariableAddressInstruction).getIRVariable().getAst()) != 1
|
||||
count(instr.(VariableAddressInstruction).getIRVariable().getAST()) != 1
|
||||
or
|
||||
instr instanceof ConstantInstruction and
|
||||
count(instr.getResultIRType()) != 1
|
||||
@@ -121,7 +121,7 @@ private predicate variableAddressValueNumber(
|
||||
// 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
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
unique( | | instr.getIRVariable().getAst()) = ast
|
||||
unique( | | instr.getIRVariable().getAST()) = ast
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(
|
||||
@@ -131,7 +131,7 @@ private predicate initializeParameterValueNumber(
|
||||
// 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
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
instr.getIRVariable().getAst() = var
|
||||
instr.getIRVariable().getAST() = var
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
|
||||
@@ -48,7 +48,7 @@ module Raw {
|
||||
cached
|
||||
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, CppType type) {
|
||||
exists(TranslatedElement element |
|
||||
element.getAst() = ast and
|
||||
element.getAST() = ast and
|
||||
func = element.getFunction() and
|
||||
element.hasTempVariable(tag, type)
|
||||
)
|
||||
@@ -75,7 +75,7 @@ module Raw {
|
||||
tag = getInstructionTag(instruction) and
|
||||
(
|
||||
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.
|
||||
exists(TranslatedElement s, GotoStmt goto |
|
||||
not isStrictlyForwardGoto(goto) and
|
||||
goto = s.getAst() and
|
||||
goto = s.getAST() and
|
||||
exists(InstructionTag tag |
|
||||
result = s.getInstructionSuccessor(tag, kind) and
|
||||
instruction = s.getInstruction(tag)
|
||||
@@ -352,13 +352,8 @@ private predicate isStrictlyForwardGoto(GotoStmt goto) {
|
||||
goto.getLocation().isBefore(goto.getTarget().getLocation())
|
||||
}
|
||||
|
||||
Locatable getInstructionAst(TStageInstruction instr) {
|
||||
result = getInstructionTranslatedElement(instr).getAst()
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for getInstructionAst */
|
||||
deprecated Locatable getInstructionAST(TStageInstruction instr) {
|
||||
result = getInstructionAst(instr)
|
||||
Locatable getInstructionAST(TStageInstruction instr) {
|
||||
result = getInstructionTranslatedElement(instr).getAST()
|
||||
}
|
||||
|
||||
CppType getInstructionResultType(TStageInstruction instr) {
|
||||
|
||||
@@ -175,10 +175,7 @@ abstract class TranslatedSideEffects extends TranslatedElement {
|
||||
/** Gets the expression whose side effects are being modeled. */
|
||||
abstract Expr getExpr();
|
||||
|
||||
final override Locatable getAst() { result = getExpr() }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
final override Locatable getAST() { result = getExpr() }
|
||||
|
||||
final override Function getFunction() { result = getExpr().getEnclosingFunction() }
|
||||
|
||||
@@ -525,10 +522,7 @@ class TranslatedArgumentExprSideEffect extends TranslatedArgumentSideEffect,
|
||||
this = TTranslatedArgumentExprSideEffect(call, arg, index, sideEffectOpcode)
|
||||
}
|
||||
|
||||
final override Locatable getAst() { result = arg }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
final override Locatable getAST() { result = arg }
|
||||
|
||||
final override Type getIndirectionType() {
|
||||
result = arg.getUnspecifiedType().(DerivedType).getBaseType()
|
||||
@@ -559,10 +553,7 @@ class TranslatedStructorQualifierSideEffect extends TranslatedArgumentSideEffect
|
||||
index = -1
|
||||
}
|
||||
|
||||
final override Locatable getAst() { result = call }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
final override Locatable getAST() { result = call }
|
||||
|
||||
final override Type getIndirectionType() { result = call.getTarget().getDeclaringType() }
|
||||
|
||||
@@ -583,10 +574,7 @@ class TranslatedCallSideEffect extends TranslatedSideEffect, TTranslatedCallSide
|
||||
|
||||
TranslatedCallSideEffect() { this = TTranslatedCallSideEffect(expr, sideEffectOpcode) }
|
||||
|
||||
override Locatable getAst() { result = expr }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
override Locatable getAST() { result = expr }
|
||||
|
||||
override Expr getPrimaryExpr() { result = expr }
|
||||
|
||||
@@ -624,10 +612,7 @@ class TranslatedAllocationSideEffect extends TranslatedSideEffect, TTranslatedAl
|
||||
|
||||
TranslatedAllocationSideEffect() { this = TTranslatedAllocationSideEffect(expr) }
|
||||
|
||||
override Locatable getAst() { result = expr }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
override Locatable getAST() { result = expr }
|
||||
|
||||
override Expr getPrimaryExpr() { result = expr }
|
||||
|
||||
|
||||
@@ -19,10 +19,7 @@ abstract class TranslatedCondition extends TranslatedElement {
|
||||
|
||||
final override string toString() { result = expr.toString() }
|
||||
|
||||
final override Locatable getAst() { result = expr }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
final override Locatable getAST() { result = expr }
|
||||
|
||||
final ConditionContext getConditionContext() { result = getParent() }
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ private import TranslatedInitialization
|
||||
* `entry`.
|
||||
*/
|
||||
TranslatedDeclarationEntry getTranslatedDeclarationEntry(DeclarationEntry entry) {
|
||||
result.getAst() = entry
|
||||
result.getAST() = entry
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,10 +37,7 @@ abstract class TranslatedDeclarationEntry extends TranslatedElement, TTranslated
|
||||
|
||||
final override string toString() { result = entry.toString() }
|
||||
|
||||
final override Locatable getAst() { result = entry }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
final override Locatable getAST() { result = entry }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -226,10 +223,7 @@ class TranslatedStaticLocalVariableInitialization extends TranslatedElement,
|
||||
|
||||
final override string toString() { result = "init: " + entry.toString() }
|
||||
|
||||
final override Locatable getAst() { result = entry }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
final override Locatable getAST() { result = entry }
|
||||
|
||||
final override LocalVariable getVariable() { result = var }
|
||||
|
||||
@@ -260,10 +254,7 @@ class TranslatedRangeBasedForVariableDeclaration extends TranslatedLocalVariable
|
||||
|
||||
override string toString() { result = var.toString() }
|
||||
|
||||
override Locatable getAst() { result = var }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
override Locatable getAST() { result = var }
|
||||
|
||||
override Function getFunction() { result = forStmt.getEnclosingFunction() }
|
||||
|
||||
@@ -271,7 +262,7 @@ class TranslatedRangeBasedForVariableDeclaration extends TranslatedLocalVariable
|
||||
}
|
||||
|
||||
TranslatedConditionDecl getTranslatedConditionDecl(ConditionDeclExpr expr) {
|
||||
result.getAst() = expr
|
||||
result.getAST() = expr
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -289,10 +280,7 @@ class TranslatedConditionDecl extends TranslatedLocalVariableDeclaration, TTrans
|
||||
|
||||
override string toString() { result = "decl: " + conditionDeclExpr.toString() }
|
||||
|
||||
override Locatable getAst() { result = conditionDeclExpr }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
override Locatable getAST() { result = conditionDeclExpr }
|
||||
|
||||
override Function getFunction() { result = conditionDeclExpr.getEnclosingFunction() }
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ IRUserVariable getIRUserVariable(Function func, Variable var) {
|
||||
}
|
||||
|
||||
IRTempVariable getIRTempVariable(Locatable ast, TempVariableTag tag) {
|
||||
result.getAst() = ast and
|
||||
result.getAST() = ast and
|
||||
result.getTag() = tag
|
||||
}
|
||||
|
||||
@@ -730,10 +730,7 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
/**
|
||||
* Gets the AST node being translated.
|
||||
*/
|
||||
abstract Locatable getAst();
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Locatable getAST() { result = getAst() }
|
||||
abstract Locatable getAST();
|
||||
|
||||
/**
|
||||
* Get the first instruction to be executed in the evaluation of this element.
|
||||
@@ -932,16 +929,16 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
*/
|
||||
final IRTempVariable getTempVariable(TempVariableTag tag) {
|
||||
exists(Locatable ast |
|
||||
result.getAst() = ast and
|
||||
result.getAST() = ast and
|
||||
result.getTag() = tag and
|
||||
hasTempVariableAndAst(tag, ast)
|
||||
hasTempVariableAndAST(tag, ast)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasTempVariableAndAst(TempVariableTag tag, Locatable ast) {
|
||||
private predicate hasTempVariableAndAST(TempVariableTag tag, Locatable ast) {
|
||||
hasTempVariable(tag, _) and
|
||||
ast = getAst()
|
||||
ast = getAST()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -74,10 +74,7 @@ abstract class TranslatedExpr extends TranslatedElement {
|
||||
expr.isGLValueCategory()
|
||||
}
|
||||
|
||||
final override Locatable getAst() { result = expr }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = this.getAst() }
|
||||
final override Locatable getAST() { result = expr }
|
||||
|
||||
final override Function getFunction() { result = expr.getEnclosingFunction() }
|
||||
|
||||
@@ -1712,7 +1709,7 @@ abstract class TranslatedAllocationSize extends TranslatedExpr, TTranslatedAlloc
|
||||
}
|
||||
|
||||
TranslatedAllocationSize getTranslatedAllocationSize(NewOrNewArrayExpr newExpr) {
|
||||
result.getAst() = newExpr
|
||||
result.getAST() = newExpr
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1878,7 +1875,7 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect
|
||||
}
|
||||
|
||||
TranslatedAllocatorCall getTranslatedAllocatorCall(NewOrNewArrayExpr newExpr) {
|
||||
result.getAst() = newExpr
|
||||
result.getAST() = newExpr
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,7 +15,7 @@ private import VarArgs
|
||||
/**
|
||||
* Gets the `TranslatedFunction` that represents function `func`.
|
||||
*/
|
||||
TranslatedFunction getTranslatedFunction(Function func) { result.getAst() = func }
|
||||
TranslatedFunction getTranslatedFunction(Function func) { result.getAST() = func }
|
||||
|
||||
/**
|
||||
* Gets the size, in bytes, of the variable used to represent the `...` parameter in a varargs
|
||||
@@ -65,10 +65,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
|
||||
|
||||
final override string toString() { result = func.toString() }
|
||||
|
||||
final override Locatable getAst() { result = func }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
final override Locatable getAST() { result = func }
|
||||
|
||||
/**
|
||||
* Gets the function being translated.
|
||||
@@ -347,7 +344,7 @@ TranslatedThisParameter getTranslatedThisParameter(Function func) { result.getFu
|
||||
/**
|
||||
* Gets the `TranslatedPositionalParameter` that represents parameter `param`.
|
||||
*/
|
||||
TranslatedPositionalParameter getTranslatedParameter(Parameter param) { result.getAst() = param }
|
||||
TranslatedPositionalParameter getTranslatedParameter(Parameter param) { result.getAST() = param }
|
||||
|
||||
/**
|
||||
* Gets the `TranslatedEllipsisParameter` for function `func`, if one exists.
|
||||
@@ -460,10 +457,7 @@ class TranslatedThisParameter extends TranslatedParameter, TTranslatedThisParame
|
||||
|
||||
final override string toString() { result = "this" }
|
||||
|
||||
final override Locatable getAst() { result = func }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
final override Locatable getAST() { result = func }
|
||||
|
||||
final override Function getFunction() { result = func }
|
||||
|
||||
@@ -495,10 +489,7 @@ class TranslatedPositionalParameter extends TranslatedParameter, TTranslatedPara
|
||||
|
||||
final override string toString() { result = param.toString() }
|
||||
|
||||
final override Locatable getAst() { result = param }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
final override Locatable getAST() { result = param }
|
||||
|
||||
final override Function getFunction() {
|
||||
result = param.getFunction() or
|
||||
@@ -535,10 +526,7 @@ class TranslatedEllipsisParameter extends TranslatedParameter, TTranslatedEllips
|
||||
|
||||
final override string toString() { result = "..." }
|
||||
|
||||
final override Locatable getAst() { result = func }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
final override Locatable getAST() { result = func }
|
||||
|
||||
final override Function getFunction() { result = func }
|
||||
|
||||
@@ -556,7 +544,7 @@ class TranslatedEllipsisParameter extends TranslatedParameter, TTranslatedEllips
|
||||
}
|
||||
|
||||
private TranslatedConstructorInitList getTranslatedConstructorInitList(Function func) {
|
||||
result.getAst() = func
|
||||
result.getAST() = func
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -573,10 +561,7 @@ class TranslatedConstructorInitList extends TranslatedElement, InitializationCon
|
||||
|
||||
override string toString() { result = "ctor init: " + func.toString() }
|
||||
|
||||
override Locatable getAst() { result = func }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
override Locatable getAST() { result = func }
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
exists(ConstructorFieldInit fieldInit |
|
||||
@@ -626,7 +611,7 @@ class TranslatedConstructorInitList extends TranslatedElement, InitializationCon
|
||||
}
|
||||
|
||||
private TranslatedDestructorDestructionList getTranslatedDestructorDestructionList(Function func) {
|
||||
result.getAst() = func
|
||||
result.getAST() = func
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -644,10 +629,7 @@ class TranslatedDestructorDestructionList extends TranslatedElement,
|
||||
|
||||
override string toString() { result = "dtor destruction: " + func.toString() }
|
||||
|
||||
override Locatable getAst() { result = func }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
override Locatable getAST() { result = func }
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
exists(DestructorFieldDestruction fieldDestruction |
|
||||
@@ -685,17 +667,14 @@ class TranslatedDestructorDestructionList extends TranslatedElement,
|
||||
}
|
||||
}
|
||||
|
||||
TranslatedReadEffects getTranslatedReadEffects(Function func) { result.getAst() = func }
|
||||
TranslatedReadEffects getTranslatedReadEffects(Function func) { result.getAST() = func }
|
||||
|
||||
class TranslatedReadEffects extends TranslatedElement, TTranslatedReadEffects {
|
||||
Function func;
|
||||
|
||||
TranslatedReadEffects() { this = TTranslatedReadEffects(func) }
|
||||
|
||||
override Locatable getAst() { result = func }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
override Locatable getAST() { result = func }
|
||||
|
||||
override Function getFunction() { result = func }
|
||||
|
||||
@@ -739,11 +718,11 @@ class TranslatedReadEffects extends TranslatedElement, TTranslatedReadEffects {
|
||||
}
|
||||
|
||||
private TranslatedThisReadEffect getTranslatedThisReadEffect(Function func) {
|
||||
result.getAst() = func
|
||||
result.getAST() = func
|
||||
}
|
||||
|
||||
private TranslatedParameterReadEffect getTranslatedParameterReadEffect(Parameter param) {
|
||||
result.getAst() = param
|
||||
result.getAST() = param
|
||||
}
|
||||
|
||||
abstract class TranslatedReadEffect extends TranslatedElement {
|
||||
@@ -779,10 +758,7 @@ class TranslatedThisReadEffect extends TranslatedReadEffect, TTranslatedThisRead
|
||||
|
||||
TranslatedThisReadEffect() { this = TTranslatedThisReadEffect(func) }
|
||||
|
||||
override Locatable getAst() { result = func }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
override Locatable getAST() { result = func }
|
||||
|
||||
override Function getFunction() { result = func }
|
||||
|
||||
@@ -805,10 +781,7 @@ class TranslatedParameterReadEffect extends TranslatedReadEffect, TTranslatedPar
|
||||
|
||||
TranslatedParameterReadEffect() { this = TTranslatedParameterReadEffect(param) }
|
||||
|
||||
override Locatable getAst() { result = param }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
override Locatable getAST() { result = param }
|
||||
|
||||
override string toString() { result = "read effect: " + param.toString() }
|
||||
|
||||
|
||||
@@ -139,10 +139,7 @@ abstract class TranslatedInitialization extends TranslatedElement, TTranslatedIn
|
||||
|
||||
final override Function getFunction() { result = expr.getEnclosingFunction() }
|
||||
|
||||
final override Locatable getAst() { result = expr }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
final override Locatable getAST() { result = expr }
|
||||
|
||||
/**
|
||||
* Gets the expression that is doing the initialization.
|
||||
@@ -464,11 +461,11 @@ class TranslatedConstructorInitialization extends TranslatedDirectInitialization
|
||||
TranslatedFieldInitialization getTranslatedFieldInitialization(
|
||||
ClassAggregateLiteral initList, Field field
|
||||
) {
|
||||
result.getAst() = initList and result.getField() = field
|
||||
result.getAST() = initList and result.getField() = field
|
||||
}
|
||||
|
||||
TranslatedFieldInitialization getTranslatedConstructorFieldInitialization(ConstructorFieldInit init) {
|
||||
result.getAst() = init
|
||||
result.getAST() = init
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -481,10 +478,7 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
|
||||
|
||||
final override string toString() { result = ast.toString() + "." + field.toString() }
|
||||
|
||||
final override Locatable getAst() { result = ast }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
final override Locatable getAST() { result = ast }
|
||||
|
||||
final override Function getFunction() { result = ast.getEnclosingFunction() }
|
||||
|
||||
@@ -628,10 +622,7 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
|
||||
result = initList.toString() + "[" + getElementIndex().toString() + "]"
|
||||
}
|
||||
|
||||
final override Locatable getAst() { result = initList }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
final override Locatable getAST() { result = initList }
|
||||
|
||||
final override Function getFunction() { result = initList.getEnclosingFunction() }
|
||||
|
||||
@@ -811,10 +802,7 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
|
||||
abstract class TranslatedStructorCallFromStructor extends TranslatedElement, StructorCallContext {
|
||||
FunctionCall call;
|
||||
|
||||
final override Locatable getAst() { result = call }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
final override Locatable getAST() { result = call }
|
||||
|
||||
final override TranslatedElement getChild(int id) {
|
||||
id = 0 and
|
||||
@@ -876,7 +864,7 @@ abstract class TranslatedConstructorCallFromConstructor extends TranslatedStruct
|
||||
}
|
||||
|
||||
TranslatedConstructorCallFromConstructor getTranslatedConstructorBaseInit(ConstructorBaseInit init) {
|
||||
result.getAst() = init
|
||||
result.getAST() = init
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -916,7 +904,7 @@ class TranslatedConstructorBaseInit extends TranslatedConstructorCallFromConstru
|
||||
TranslatedDestructorBaseDestruction getTranslatedDestructorBaseDestruction(
|
||||
DestructorBaseDestruction destruction
|
||||
) {
|
||||
result.getAst() = destruction
|
||||
result.getAST() = destruction
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -940,10 +928,7 @@ class TranslatedConstructorBareInit extends TranslatedElement, TTranslatedConstr
|
||||
|
||||
TranslatedConstructorBareInit() { this = TTranslatedConstructorBareInit(init) }
|
||||
|
||||
override Locatable getAst() { result = init }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
override Locatable getAST() { result = init }
|
||||
|
||||
final override string toString() { result = "construct base (no constructor)" }
|
||||
|
||||
@@ -963,5 +948,5 @@ class TranslatedConstructorBareInit extends TranslatedElement, TTranslatedConstr
|
||||
}
|
||||
|
||||
TranslatedConstructorBareInit getTranslatedConstructorBareInit(ConstructorInit init) {
|
||||
result.getAst() = init
|
||||
result.getAST() = init
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ private import TranslatedExpr
|
||||
private import TranslatedFunction
|
||||
private import TranslatedInitialization
|
||||
|
||||
TranslatedStmt getTranslatedStmt(Stmt stmt) { result.getAst() = stmt }
|
||||
TranslatedStmt getTranslatedStmt(Stmt stmt) { result.getAST() = stmt }
|
||||
|
||||
abstract class TranslatedStmt extends TranslatedElement, TTranslatedStmt {
|
||||
Stmt stmt;
|
||||
@@ -20,10 +20,7 @@ abstract class TranslatedStmt extends TranslatedElement, TTranslatedStmt {
|
||||
|
||||
final override string toString() { result = stmt.toString() }
|
||||
|
||||
final override Locatable getAst() { result = stmt }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
final override Locatable getAST() { result = stmt }
|
||||
|
||||
final override Function getFunction() { result = stmt.getEnclosingFunction() }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
private import ReachableBlock as Reachability
|
||||
|
||||
private module ReachabilityGraph = Reachability::Graph;
|
||||
|
||||
module Graph {
|
||||
import Reachability::Graph
|
||||
|
||||
|
||||
@@ -55,10 +55,7 @@ class IRVariable extends TIRVariable {
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
Language::AST getAst() { none() }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = getAst() }
|
||||
Language::AST getAST() { none() }
|
||||
|
||||
/**
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
@@ -69,7 +66,7 @@ class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* 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.
|
||||
@@ -93,10 +90,7 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
|
||||
final override string toString() { result = getVariable().toString() }
|
||||
|
||||
final override Language::AST getAst() { result = var }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Language::AST getAST() { result = getAst() }
|
||||
final override Language::AST getAST() { result = var }
|
||||
|
||||
final override string getUniqueId() {
|
||||
result = getVariable().toString() + " " + getVariable().getLocation().toString()
|
||||
@@ -163,10 +157,7 @@ class IRGeneratedVariable extends IRVariable {
|
||||
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAst() { result = ast }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Language::AST getAST() { result = getAst() }
|
||||
final override Language::AST getAST() { result = ast }
|
||||
|
||||
override string toString() { result = getBaseString() + getLocationString() }
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ class Instruction extends Construction::TStageInstruction {
|
||||
}
|
||||
|
||||
/** 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
|
||||
@@ -136,7 +136,7 @@ class Instruction extends Construction::TStageInstruction {
|
||||
string getResultId() {
|
||||
this.shouldGenerateDumpStrings() and
|
||||
result =
|
||||
this.getResultPrefix() + this.getAst().getLocation().getStartLine() + "_" + this.getLineRank()
|
||||
this.getResultPrefix() + this.getAST().getLocation().getStartLine() + "_" + this.getLineRank()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,15 +208,12 @@ class Instruction extends Construction::TStageInstruction {
|
||||
/**
|
||||
* Gets the AST that caused this instruction to be generated.
|
||||
*/
|
||||
final Language::AST getAst() { result = Construction::getInstructionAst(this) }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = this.getAst() }
|
||||
final Language::AST getAST() { result = Construction::getInstructionAST(this) }
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -462,10 +459,7 @@ class VariableInstruction extends Instruction {
|
||||
/**
|
||||
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
|
||||
*/
|
||||
final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() }
|
||||
|
||||
/** DEPRECATED: Alias for getAstVariable */
|
||||
deprecated Language::Variable getASTVariable() { result = this.getAstVariable() }
|
||||
final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,7 @@ private import internal.OperandInternal
|
||||
* of `TOperand` that are used in this stage.
|
||||
*/
|
||||
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
|
||||
@@ -38,7 +38,7 @@ class Operand extends TStageOperand {
|
||||
// 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))
|
||||
or
|
||||
exists(Instruction use | this = nonSsaMemoryOperand(use, _))
|
||||
exists(Instruction use | this = nonSSAMemoryOperand(use, _))
|
||||
or
|
||||
exists(Instruction use, Instruction def, IRBlock predecessorBlock |
|
||||
this = phiOperand(use, def, predecessorBlock, _) or
|
||||
@@ -209,7 +209,7 @@ class Operand extends TStageOperand {
|
||||
class MemoryOperand extends Operand {
|
||||
cached
|
||||
MemoryOperand() {
|
||||
this instanceof TNonSsaMemoryOperand or
|
||||
this instanceof TNonSSAMemoryOperand or
|
||||
this instanceof TPhiOperand or
|
||||
this instanceof TChiOperand
|
||||
}
|
||||
@@ -249,7 +249,7 @@ class NonPhiOperand extends Operand {
|
||||
|
||||
NonPhiOperand() {
|
||||
this = registerOperand(useInstr, tag, _) or
|
||||
this = nonSsaMemoryOperand(useInstr, tag) or
|
||||
this = nonSSAMemoryOperand(useInstr, tag) or
|
||||
this = chiOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
||||
|
||||
cached
|
||||
NonPhiMemoryOperand() {
|
||||
this = nonSsaMemoryOperand(useInstr, tag)
|
||||
this = nonSSAMemoryOperand(useInstr, tag)
|
||||
or
|
||||
this = chiOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
// count rather than strictcount to handle missing AST elements
|
||||
// separate instanceof and inline casts to avoid failed casts with a count of 0
|
||||
instr instanceof VariableAddressInstruction and
|
||||
count(instr.(VariableAddressInstruction).getIRVariable().getAst()) != 1
|
||||
count(instr.(VariableAddressInstruction).getIRVariable().getAST()) != 1
|
||||
or
|
||||
instr instanceof ConstantInstruction and
|
||||
count(instr.getResultIRType()) != 1
|
||||
@@ -121,7 +121,7 @@ private predicate variableAddressValueNumber(
|
||||
// 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
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
unique( | | instr.getIRVariable().getAst()) = ast
|
||||
unique( | | instr.getIRVariable().getAST()) = ast
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(
|
||||
@@ -131,7 +131,7 @@ private predicate initializeParameterValueNumber(
|
||||
// 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
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
instr.getIRVariable().getAst() = var
|
||||
instr.getIRVariable().getAST() = var
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
private import semmle.code.cpp.ir.implementation.internal.TOperand
|
||||
import UnaliasedSsaOperands
|
||||
import UnaliasedSSAOperands
|
||||
|
||||
@@ -2,7 +2,7 @@ private import SSAConstructionInternal
|
||||
private import OldIR
|
||||
private import Alias
|
||||
private import SSAConstruction
|
||||
private import DebugSsa
|
||||
private import DebugSSA
|
||||
|
||||
bindingset[offset]
|
||||
private string getKeySuffixForOffset(int offset) {
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
private import SSAConstruction as SSA
|
||||
import SSA::SsaConsistency
|
||||
import SSA::SSAConsistency
|
||||
|
||||
@@ -112,7 +112,7 @@ private module Cached {
|
||||
exists(Alias::getResultMemoryLocation(oldInstruction))
|
||||
or
|
||||
// This result was already modeled by a previous iteration of SSA.
|
||||
Alias::canReuseSsaForOldResult(oldInstruction)
|
||||
Alias::canReuseSSAForOldResult(oldInstruction)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -182,7 +182,7 @@ private module Cached {
|
||||
* unreachable, this predicate will recurse through any degenerate `Phi` instructions to find the
|
||||
* true definition.
|
||||
*/
|
||||
private Instruction getNewDefinitionFromOldSsa(OldIR::MemoryOperand oldOperand, Overlap overlap) {
|
||||
private Instruction getNewDefinitionFromOldSSA(OldIR::MemoryOperand oldOperand, Overlap overlap) {
|
||||
exists(Overlap originalOverlap |
|
||||
originalOverlap = oldOperand.getDefinitionOverlap() and
|
||||
(
|
||||
@@ -191,7 +191,7 @@ private module Cached {
|
||||
or
|
||||
exists(OldIR::PhiInputOperand phiOperand, Overlap phiOperandOverlap |
|
||||
phiOperand = getDegeneratePhiOperand(oldOperand.getAnyDef()) and
|
||||
result = getNewDefinitionFromOldSsa(phiOperand, phiOperandOverlap) and
|
||||
result = getNewDefinitionFromOldSSA(phiOperand, phiOperandOverlap) and
|
||||
overlap =
|
||||
combineOverlap(pragma[only_bind_out](phiOperandOverlap),
|
||||
pragma[only_bind_out](originalOverlap))
|
||||
@@ -233,7 +233,7 @@ private module Cached {
|
||||
)
|
||||
or
|
||||
exists(OldIR::NonPhiMemoryOperand oldOperand |
|
||||
result = getNewDefinitionFromOldSsa(oldOperand, overlap) and
|
||||
result = getNewDefinitionFromOldSSA(oldOperand, overlap) and
|
||||
oldOperand.getUse() = instruction and
|
||||
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
|
||||
* `newPredecessorBlock`, based on that operand's definition in the old IR.
|
||||
*/
|
||||
private Instruction getNewPhiOperandDefinitionFromOldSsa(
|
||||
private Instruction getNewPhiOperandDefinitionFromOldSSA(
|
||||
Instruction instr, IRBlock newPredecessorBlock, Overlap overlap
|
||||
) {
|
||||
exists(OldIR::PhiInstruction oldPhi, OldIR::PhiInputOperand oldOperand |
|
||||
oldPhi = getOldInstruction(instr) 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)
|
||||
)
|
||||
or
|
||||
result = getNewPhiOperandDefinitionFromOldSsa(instr, newPredecessorBlock, overlap)
|
||||
result = getNewPhiOperandDefinitionFromOldSSA(instr, newPredecessorBlock, overlap)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -412,17 +412,17 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Language::AST getInstructionAst(Instruction instr) {
|
||||
result = getOldInstruction(instr).getAst()
|
||||
Language::AST getInstructionAST(Instruction instr) {
|
||||
result = getOldInstruction(instr).getAST()
|
||||
or
|
||||
exists(RawIR::Instruction blockStartInstr |
|
||||
instr = phiInstruction(blockStartInstr, _) and
|
||||
result = blockStartInstr.getAst()
|
||||
result = blockStartInstr.getAST()
|
||||
)
|
||||
or
|
||||
exists(RawIR::Instruction primaryInstr |
|
||||
instr = chiInstruction(primaryInstr) and
|
||||
result = primaryInstr.getAst()
|
||||
result = primaryInstr.getAST()
|
||||
)
|
||||
or
|
||||
exists(IRFunctionBase irFunc |
|
||||
@@ -430,12 +430,6 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for getInstructionAst */
|
||||
cached
|
||||
deprecated Language::AST getInstructionAST(Instruction instr) {
|
||||
result = getInstructionAst(instr)
|
||||
}
|
||||
|
||||
cached
|
||||
Language::LanguageType getInstructionResultType(Instruction instr) {
|
||||
result = instr.(RawIR::Instruction).getResultLanguageType()
|
||||
@@ -981,41 +975,35 @@ module DefUse {
|
||||
}
|
||||
}
|
||||
|
||||
predicate canReuseSsaForMemoryResult(Instruction instruction) {
|
||||
predicate canReuseSSAForMemoryResult(Instruction instruction) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
(
|
||||
// The previous iteration said it was reusable, so we should mark it as reusable as well.
|
||||
Alias::canReuseSsaForOldResult(oldInstruction)
|
||||
Alias::canReuseSSAForOldResult(oldInstruction)
|
||||
or
|
||||
// The current alias analysis says it is reusable.
|
||||
Alias::getResultMemoryLocation(oldInstruction).canReuseSsa()
|
||||
Alias::getResultMemoryLocation(oldInstruction).canReuseSSA()
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(Alias::MemoryLocation defLocation |
|
||||
// This is a `Phi` for a reusable location, so the result of the `Phi` is reusable as well.
|
||||
instruction = phiInstruction(_, defLocation) and
|
||||
defLocation.canReuseSsa()
|
||||
defLocation.canReuseSSA()
|
||||
)
|
||||
// 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
|
||||
* `DebugSSA` module, which is then imported by PrintSSA.
|
||||
*/
|
||||
module DebugSsa {
|
||||
module DebugSSA {
|
||||
import PhiInsertion
|
||||
import DefUse
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for DebugSsa */
|
||||
deprecated module DebugSSA = DebugSsa;
|
||||
|
||||
import CachedForDebugging
|
||||
|
||||
cached
|
||||
@@ -1050,7 +1038,7 @@ private module CachedForDebugging {
|
||||
|
||||
private OldIR::IRTempVariable getOldTempVariable(IRTempVariable var) {
|
||||
result.getEnclosingFunction() = var.getEnclosingFunction() and
|
||||
result.getAst() = var.getAst() and
|
||||
result.getAST() = var.getAST() and
|
||||
result.getTag() = var.getTag()
|
||||
}
|
||||
|
||||
@@ -1073,7 +1061,7 @@ private module CachedForDebugging {
|
||||
int maxValue() { result = 2147483647 }
|
||||
}
|
||||
|
||||
module SsaConsistency {
|
||||
module SSAConsistency {
|
||||
/**
|
||||
* Holds if a `MemoryOperand` has more than one `MemoryLocation` assigned by alias analysis.
|
||||
*/
|
||||
@@ -1126,9 +1114,6 @@ 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
|
||||
* of the IR. The raw stage of the IR does not expose these predicates.
|
||||
|
||||
@@ -3,7 +3,7 @@ import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBloc
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawStage
|
||||
import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSsaInstructions as SSAInstructions
|
||||
import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import SimpleSSA as Alias
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand::UnaliasedSsaOperands as SSAOperands
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand::UnaliasedSSAOperands as SSAOperands
|
||||
|
||||
@@ -41,14 +41,11 @@ predicate isVariableModeled(Allocation var) {
|
||||
* subsequent iterations will recompute SSA for any variable that we assumed did not escape, but
|
||||
* actually would have escaped if we had used a sound escape analysis.
|
||||
*/
|
||||
predicate canReuseSsaForVariable(IRAutomaticVariable var) {
|
||||
predicate canReuseSSAForVariable(IRAutomaticVariable var) {
|
||||
isVariableModeled(var) and
|
||||
not allocationEscapes(var)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for canReuseSsaForVariable */
|
||||
deprecated predicate canReuseSSAForVariable = canReuseSsaForVariable/1;
|
||||
|
||||
private newtype TMemoryLocation = MkMemoryLocation(Allocation var) { isVariableModeled(var) }
|
||||
|
||||
private MemoryLocation getMemoryLocation(Allocation var) { result.getAllocation() = var }
|
||||
@@ -72,16 +69,10 @@ class MemoryLocation extends TMemoryLocation {
|
||||
|
||||
final string getUniqueId() { result = var.getUniqueId() }
|
||||
|
||||
final predicate canReuseSsa() { canReuseSsaForVariable(var) }
|
||||
|
||||
/** DEPRECATED: Alias for canReuseSsa */
|
||||
deprecated predicate canReuseSSA() { canReuseSsa() }
|
||||
final predicate canReuseSSA() { canReuseSSAForVariable(var) }
|
||||
}
|
||||
|
||||
predicate canReuseSsaForOldResult(Instruction instr) { none() }
|
||||
|
||||
/** DEPRECATED: Alias for canReuseSsaForOldResult */
|
||||
deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1;
|
||||
predicate canReuseSSAForOldResult(Instruction instr) { none() }
|
||||
|
||||
/**
|
||||
* Represents a set of `MemoryLocation`s that cannot overlap with
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
private import ReachableBlock as Reachability
|
||||
|
||||
private module ReachabilityGraph = Reachability::Graph;
|
||||
|
||||
module Graph {
|
||||
import Reachability::Graph
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@ private import RangeAnalysisUtils
|
||||
* The SSA logic comes in two versions: the standard SSA and range-analysis RangeSSA.
|
||||
* This class provides the range-analysis SSA logic.
|
||||
*/
|
||||
library class RangeSsa extends SsaHelper {
|
||||
RangeSsa() { this = 1 }
|
||||
library class RangeSSA extends SSAHelper {
|
||||
RangeSSA() { this = 1 }
|
||||
|
||||
/**
|
||||
* Add a phi node on the out-edge of a guard.
|
||||
@@ -40,9 +40,6 @@ library class RangeSsa extends SsaHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for RangeSsa */
|
||||
deprecated class RangeSSA = RangeSsa;
|
||||
|
||||
private predicate guard_defn(VariableAccess v, Expr guard, BasicBlock b, boolean branch) {
|
||||
guardCondition(guard, v, branch) and
|
||||
guardSuccessor(guard, branch, b)
|
||||
@@ -70,22 +67,22 @@ private predicate guardSuccessor(Expr guard, boolean branch, BasicBlock succ) {
|
||||
* nodes.
|
||||
*/
|
||||
class RangeSsaDefinition extends ControlFlowNodeBase {
|
||||
RangeSsaDefinition() { exists(RangeSsa x | x.ssa_defn(_, this, _, _)) }
|
||||
RangeSsaDefinition() { exists(RangeSSA x | x.ssa_defn(_, this, _, _)) }
|
||||
|
||||
/**
|
||||
* Gets a variable corresponding to a SSA StackVariable defined by
|
||||
* this definition.
|
||||
*/
|
||||
StackVariable getAVariable() { exists(RangeSsa x | x.ssa_defn(result, this, _, _)) }
|
||||
StackVariable getAVariable() { exists(RangeSSA x | x.ssa_defn(result, this, _, _)) }
|
||||
|
||||
/**
|
||||
* A string representation of the SSA variable represented by the pair
|
||||
* `(this, v)`.
|
||||
*/
|
||||
string toString(StackVariable v) { exists(RangeSsa x | result = x.toString(this, v)) }
|
||||
string toString(StackVariable v) { exists(RangeSSA x | result = x.toString(this, v)) }
|
||||
|
||||
/** Gets a use of the SSA variable represented by the pair `(this, v)`. */
|
||||
VariableAccess getAUse(StackVariable v) { exists(RangeSsa x | result = x.getAUse(this, v)) }
|
||||
VariableAccess getAUse(StackVariable v) { exists(RangeSSA x | result = x.getAUse(this, v)) }
|
||||
|
||||
/** Gets the control flow node for this definition. */
|
||||
ControlFlowNode getDefinition() { result = this }
|
||||
@@ -94,7 +91,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
|
||||
BasicBlock getBasicBlock() { result.contains(this.getDefinition()) }
|
||||
|
||||
/** Whether this definition is a phi node for variable `v`. */
|
||||
predicate isPhiNode(StackVariable v) { exists(RangeSsa x | x.phi_node(v, this)) }
|
||||
predicate isPhiNode(StackVariable v) { exists(RangeSSA x | x.phi_node(v, this)) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use isGuardPhi/4 instead
|
||||
@@ -175,6 +172,6 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
|
||||
* Holds if this definition of the variable `v` reached the end of the basic block `b`.
|
||||
*/
|
||||
predicate reachesEndOfBB(StackVariable v, BasicBlock b) {
|
||||
exists(RangeSsa x | x.ssaDefinitionReachesEndOfBB(v, this, b))
|
||||
exists(RangeSSA x | x.ssaDefinitionReachesEndOfBB(v, this, b))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ private ControlFlowNode getControlFlowEntry(ControlFlowNode node) {
|
||||
* graph so that we can use the dominator tree to find the most recent
|
||||
* side-effect.
|
||||
*/
|
||||
private predicate sideEffectCfg(ControlFlowNode src, ControlFlowNode dst) {
|
||||
private predicate sideEffectCFG(ControlFlowNode src, ControlFlowNode dst) {
|
||||
src.getASuccessor() = dst
|
||||
or
|
||||
// Add an edge from the entry point to any node that might have a side
|
||||
@@ -103,7 +103,7 @@ private predicate sideEffectCfg(ControlFlowNode src, ControlFlowNode dst) {
|
||||
* the side-effect CFG.
|
||||
*/
|
||||
private predicate iDomEffect(ControlFlowNode dominator, ControlFlowNode node) =
|
||||
idominance(functionEntry/1, sideEffectCfg/2)(_, dominator, node)
|
||||
idominance(functionEntry/1, sideEffectCFG/2)(_, dominator, node)
|
||||
|
||||
/**
|
||||
* Gets the most recent side effect. To be more precise, `result` is a
|
||||
|
||||
@@ -703,7 +703,7 @@ usertype_final(unique int id: @usertype ref);
|
||||
|
||||
usertype_uuid(
|
||||
unique int id: @usertype ref,
|
||||
string uuid: string ref
|
||||
unique string uuid: string ref
|
||||
);
|
||||
|
||||
mangled_name(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
description: Remove uniqueness constraint from the uuid property
|
||||
compatibility: full
|
||||
@@ -1,31 +1,3 @@
|
||||
## 0.0.12
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/overflow-destination`, `cpp/unclear-array-index-validation`, and `cpp/uncontrolled-allocation-size` queries have been modernized and converted to `path-problem` queries and provide more true positive results.
|
||||
* The `cpp/system-data-exposure` query has been increased from `medium` to `high` precision, following a number of improvements to the query logic.
|
||||
|
||||
## 0.0.11
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The deprecated queries `cpp/duplicate-block`, `cpp/duplicate-function`, `cpp/duplicate-class`, `cpp/duplicate-file`, `cpp/mostly-duplicate-function`,`cpp/similar-file`, `cpp/duplicated-lines-in-files` have been removed.
|
||||
|
||||
### Deprecated Predicates and Classes
|
||||
|
||||
* The predicates and classes in the `CodeDuplication` library have been deprecated.
|
||||
|
||||
### New Queries
|
||||
|
||||
* A new query titled "Use of expired stack-address" (`cpp/using-expired-stack-address`) has been added.
|
||||
This query finds accesses to expired stack-allocated memory that escaped via a global variable.
|
||||
* A new `cpp/insufficient-key-size` query has been added to the default query suite for C/C++. The query finds uses of certain cryptographic algorithms where the key size is too small to provide adequate encryption strength.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The "Failure to use HTTPS URLs" (`cpp/non-https-url`) has been improved reducing false positive results, and its precision has been increased to 'high'.
|
||||
* The `cpp/system-data-exposure` query has been modernized and has converted to a `path-problem` query. There are now fewer false positive results.
|
||||
|
||||
## 0.0.10
|
||||
|
||||
### Deprecated Classes
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @name Copy function using source size
|
||||
* @description Calling a copy operation with a size derived from the source
|
||||
* buffer instead of the destination buffer may result in a buffer overflow.
|
||||
* @kind path-problem
|
||||
* @kind problem
|
||||
* @id cpp/overflow-destination
|
||||
* @problem.severity warning
|
||||
* @security-severity 9.3
|
||||
@@ -14,10 +14,7 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.controlflow.IRGuards
|
||||
import semmle.code.cpp.security.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
import semmle.code.cpp.security.TaintTracking
|
||||
|
||||
/**
|
||||
* Holds if `fc` is a call to a copy operation where the size argument contains
|
||||
@@ -30,9 +27,9 @@ predicate sourceSized(FunctionCall fc, Expr src) {
|
||||
fc.getTarget().hasGlobalOrStdName(["strncpy", "strncat", "memcpy", "memmove"]) and
|
||||
exists(Expr dest, Expr size, Variable v |
|
||||
fc.getArgument(0) = dest and
|
||||
fc.getArgument(1).getFullyConverted() = src and
|
||||
fc.getArgument(1) = src and
|
||||
fc.getArgument(2) = size and
|
||||
src = v.getAnAccess().getFullyConverted() and
|
||||
src = v.getAnAccess() and
|
||||
size.getAChild+() = v.getAnAccess() and
|
||||
// exception: `dest` is also referenced in the size argument
|
||||
not exists(Variable other |
|
||||
@@ -48,49 +45,9 @@ predicate sourceSized(FunctionCall fc, Expr src) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate readsVariable(LoadInstruction load, Variable var) {
|
||||
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
|
||||
}
|
||||
|
||||
predicate hasUpperBoundsCheck(Variable var) {
|
||||
exists(RelationalOperation oper, VariableAccess access |
|
||||
oper.getAnOperand() = access and
|
||||
access.getTarget() = var and
|
||||
// Comparing to 0 is not an upper bound check
|
||||
not oper.getAnOperand().getValue() = "0"
|
||||
)
|
||||
}
|
||||
|
||||
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
|
||||
readsVariable(node.asInstruction(), checkedVar) and
|
||||
any(IRGuardCondition guard).ensuresEq(access, _, _, node.asInstruction().getBlock(), true)
|
||||
}
|
||||
|
||||
class OverflowDestinationConfig extends TaintTracking::Configuration {
|
||||
OverflowDestinationConfig() { this = "OverflowDestinationConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sourceSized(_, sink.asConvertedExpr()) }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
exists(Variable checkedVar |
|
||||
readsVariable(node.asInstruction(), checkedVar) and
|
||||
hasUpperBoundsCheck(checkedVar)
|
||||
)
|
||||
or
|
||||
exists(Variable checkedVar, Operand access |
|
||||
readsVariable(access.getDef(), checkedVar) and
|
||||
nodeIsBarrierEqualityCandidate(node, access, checkedVar)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from
|
||||
FunctionCall fc, OverflowDestinationConfig conf, DataFlow::PathNode source,
|
||||
DataFlow::PathNode sink
|
||||
from FunctionCall fc, Expr vuln, Expr taintSource
|
||||
where
|
||||
conf.hasFlowPath(source, sink) and
|
||||
sourceSized(fc, sink.getNode().asConvertedExpr())
|
||||
select fc, source, sink,
|
||||
sourceSized(fc, vuln) and
|
||||
tainted(taintSource, vuln)
|
||||
select fc,
|
||||
"To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size."
|
||||
|
||||
@@ -34,7 +34,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
||||
exists(VariableAddressInstruction var, Function func |
|
||||
var = source.asInstruction() and
|
||||
func = var.getEnclosingFunction() and
|
||||
var.getAstVariable() instanceof StackVariable and
|
||||
var.getASTVariable() instanceof StackVariable and
|
||||
// Pointer-to-member types aren't properly handled in the dbscheme.
|
||||
not var.getResultType() instanceof PointerToMemberType and
|
||||
// Rule out FPs caused by extraction errors.
|
||||
@@ -77,13 +77,12 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
||||
|
||||
from
|
||||
MustFlowPathNode source, MustFlowPathNode sink, VariableAddressInstruction var,
|
||||
ReturnStackAllocatedMemoryConfig conf, Function f
|
||||
ReturnStackAllocatedMemoryConfig conf
|
||||
where
|
||||
conf.hasFlowPath(source, sink) and
|
||||
source.getNode().asInstruction() = var and
|
||||
// Only raise an alert if we're returning from the _same_ callable as the on that
|
||||
// declared the stack variable.
|
||||
var.getEnclosingFunction() = pragma[only_bind_into](f) and
|
||||
sink.getNode().getEnclosingCallable() = pragma[only_bind_into](f)
|
||||
select sink.getNode(), source, sink, "May return stack-allocated memory from $@.", var.getAst(),
|
||||
var.getAst().toString()
|
||||
var.getEnclosingFunction() = sink.getNode().getEnclosingCallable()
|
||||
select sink.getNode(), source, sink, "May return stack-allocated memory from $@.", var.getAST(),
|
||||
var.getAST().toString()
|
||||
|
||||
@@ -19,7 +19,7 @@ import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.ir.IR
|
||||
|
||||
predicate instructionHasVariable(VariableAddressInstruction vai, StackVariable var, Function f) {
|
||||
var = vai.getAstVariable() and
|
||||
var = vai.getASTVariable() and
|
||||
f = vai.getEnclosingFunction() and
|
||||
// Pointer-to-member types aren't properly handled in the dbscheme.
|
||||
not vai.getResultType() instanceof PointerToMemberType and
|
||||
@@ -108,7 +108,7 @@ predicate inheritanceConversionTypes(
|
||||
|
||||
/** Gets the HashCons value of an address computed by `instr`, if any. */
|
||||
TGlobalAddress globalAddress(Instruction instr) {
|
||||
result = TGlobalVariable(instr.(VariableAddressInstruction).getAstVariable())
|
||||
result = TGlobalVariable(instr.(VariableAddressInstruction).getASTVariable())
|
||||
or
|
||||
not instr instanceof LoadInstruction and
|
||||
result = globalAddress(instr.(CopyInstruction).getSourceValue())
|
||||
|
||||
@@ -52,7 +52,7 @@ predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) {
|
||||
pragma[noinline]
|
||||
predicate candidateResult(LoadInstruction checked, ValueNumber value, IRBlock dominator) {
|
||||
explicitNullTestOfInstruction(checked, _) and
|
||||
not checked.getAst().isInMacroExpansion() and
|
||||
not checked.getAST().isInMacroExpansion() and
|
||||
value.getAnInstruction() = checked and
|
||||
dominator.dominates(checked.getBlock())
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
import cpp
|
||||
import ExternalAPIs
|
||||
|
||||
from ExternalApiUsedWithUntrustedData externalApi
|
||||
select externalApi, count(externalApi.getUntrustedDataNode()) as numberOfUses,
|
||||
externalApi.getNumberOfUntrustedSources() as numberOfUntrustedSources order by
|
||||
from ExternalAPIUsedWithUntrustedData externalAPI
|
||||
select externalAPI, count(externalAPI.getUntrustedDataNode()) as numberOfUses,
|
||||
externalAPI.getNumberOfUntrustedSources() as numberOfUntrustedSources order by
|
||||
numberOfUntrustedSources desc
|
||||
|
||||
@@ -9,31 +9,28 @@ private import semmle.code.cpp.models.interfaces.Taint
|
||||
import ExternalAPIsSpecific
|
||||
|
||||
/** A node representing untrusted data being passed to an external API. */
|
||||
class UntrustedExternalApiDataNode extends ExternalApiDataNode {
|
||||
UntrustedExternalApiDataNode() { any(UntrustedDataToExternalApiConfig c).hasFlow(_, this) }
|
||||
class UntrustedExternalAPIDataNode extends ExternalAPIDataNode {
|
||||
UntrustedExternalAPIDataNode() { any(UntrustedDataToExternalAPIConfig c).hasFlow(_, this) }
|
||||
|
||||
/** Gets a source of untrusted data which is passed to this external API data node. */
|
||||
DataFlow::Node getAnUntrustedSource() {
|
||||
any(UntrustedDataToExternalApiConfig c).hasFlow(result, this)
|
||||
any(UntrustedDataToExternalAPIConfig c).hasFlow(result, this)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
|
||||
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
|
||||
|
||||
private newtype TExternalApi =
|
||||
TExternalApiParameter(Function f, int index) {
|
||||
exists(UntrustedExternalApiDataNode n |
|
||||
private newtype TExternalAPI =
|
||||
TExternalAPIParameter(Function f, int index) {
|
||||
exists(UntrustedExternalAPIDataNode n |
|
||||
f = n.getExternalFunction() and
|
||||
index = n.getIndex()
|
||||
)
|
||||
}
|
||||
|
||||
/** An external API which is used with untrusted data. */
|
||||
class ExternalApiUsedWithUntrustedData extends TExternalApi {
|
||||
class ExternalAPIUsedWithUntrustedData extends TExternalAPI {
|
||||
/** Gets a possibly untrusted use of this external API. */
|
||||
UntrustedExternalApiDataNode getUntrustedDataNode() {
|
||||
this = TExternalApiParameter(result.getExternalFunction(), result.getIndex())
|
||||
UntrustedExternalAPIDataNode getUntrustedDataNode() {
|
||||
this = TExternalAPIParameter(result.getExternalFunction(), result.getIndex())
|
||||
}
|
||||
|
||||
/** Gets the number of untrusted sources used with this external API. */
|
||||
@@ -46,11 +43,8 @@ class ExternalApiUsedWithUntrustedData extends TExternalApi {
|
||||
exists(Function f, int index, string indexString |
|
||||
if index = -1 then indexString = "qualifier" else indexString = "param " + index
|
||||
|
|
||||
this = TExternalApiParameter(f, index) and
|
||||
this = TExternalAPIParameter(f, index) and
|
||||
result = f.toString() + " [" + indexString + "]"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */
|
||||
deprecated class ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData;
|
||||
|
||||
@@ -8,11 +8,11 @@ import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import SafeExternalAPIFunction
|
||||
|
||||
/** A node representing untrusted data being passed to an external API. */
|
||||
class ExternalApiDataNode extends DataFlow::Node {
|
||||
class ExternalAPIDataNode extends DataFlow::Node {
|
||||
Call call;
|
||||
int i;
|
||||
|
||||
ExternalApiDataNode() {
|
||||
ExternalAPIDataNode() {
|
||||
// Argument to call to a function
|
||||
(
|
||||
this.asExpr() = call.getArgument(i)
|
||||
@@ -27,7 +27,7 @@ class ExternalApiDataNode extends DataFlow::Node {
|
||||
not f instanceof DataFlowFunction and
|
||||
not f instanceof TaintFunction and
|
||||
// Not a call to a known safe external API
|
||||
not f instanceof SafeExternalApiFunction
|
||||
not f instanceof SafeExternalAPIFunction
|
||||
)
|
||||
}
|
||||
|
||||
@@ -41,12 +41,9 @@ class ExternalApiDataNode extends DataFlow::Node {
|
||||
string getFunctionDescription() { result = this.getExternalFunction().toString() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ExternalApiDataNode */
|
||||
deprecated class ExternalAPIDataNode = ExternalApiDataNode;
|
||||
|
||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
|
||||
class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
|
||||
UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfig" }
|
||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalAPIDataNode`s. */
|
||||
class UntrustedDataToExternalAPIConfig extends TaintTracking::Configuration {
|
||||
UntrustedDataToExternalAPIConfig() { this = "UntrustedDataToExternalAPIConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
exists(RemoteFlowSourceFunction remoteFlow |
|
||||
@@ -55,8 +52,5 @@ class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalAPIDataNode }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */
|
||||
deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
import cpp
|
||||
import ir.ExternalAPIs
|
||||
|
||||
from ExternalApiUsedWithUntrustedData externalApi
|
||||
select externalApi, count(externalApi.getUntrustedDataNode()) as numberOfUses,
|
||||
externalApi.getNumberOfUntrustedSources() as numberOfUntrustedSources order by
|
||||
from ExternalAPIUsedWithUntrustedData externalAPI
|
||||
select externalAPI, count(externalAPI.getUntrustedDataNode()) as numberOfUses,
|
||||
externalAPI.getNumberOfUntrustedSources() as numberOfUntrustedSources order by
|
||||
numberOfUntrustedSources desc
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user