mirror of
https://github.com/github/codeql.git
synced 2026-07-20 18:58:36 +02:00
Merge branch 'master' into rdmarsh/cpp/ir-flow-through-outparams
This commit is contained in:
@@ -46,6 +46,12 @@ Follow the steps below to help other users understand what your query does, and
|
||||
Query help files explain the purpose of your query to other users. Write your query help in a `.qhelp` file and save it in the same directory as your new query.
|
||||
For more information on writing query help, see the [Query help style guide](https://github.com/Semmle/ql/blob/master/docs/query-help-style-guide.md).
|
||||
|
||||
7. **Maintain backwards compatibility**
|
||||
|
||||
The standard CodeQL libraries must evolve in a backwards compatible manner. If any backwards incompatible changes need to be made, the existing API must first be marked as deprecated. This is done by adding a `deprecated` annotation along with a QLDoc reference to the replacement API. Only after at least one full release cycle has elapsed may the old API be removed.
|
||||
|
||||
In addition to contributions to our standard queries and libraries, we also welcome contributions of a more experimental nature, which do not need to fulfill all the requirements listed above. See the guidelines for [experimental queries and libraries](docs/experimental.md) for details.
|
||||
|
||||
## Using your personal data
|
||||
|
||||
If you contribute to this project, we will record your name and email
|
||||
|
||||
@@ -5,6 +5,7 @@ The following changes in version 1.24 affect Java analysis in all applications.
|
||||
## General improvements
|
||||
|
||||
* Alert suppression can now be done with single-line block comments (`/* ... */`) as well as line comments (`// ...`).
|
||||
* A `Customizations.qll` file has been added to allow customizations of the standard library that apply to all queries.
|
||||
|
||||
## New queries
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
- Calls can now be resolved to indirectly-defined class members in more cases.
|
||||
- Calls through partial invocations such as `.bind` can now be resolved in more cases.
|
||||
|
||||
* Support for flow summaries has been more clearly marked as being experimental and moved to the new `experimental` folder.
|
||||
|
||||
* Support for the following frameworks and libraries has been improved:
|
||||
- [Electron](https://electronjs.org/)
|
||||
- [Handlebars](https://www.npmjs.com/package/handlebars)
|
||||
@@ -32,6 +34,7 @@
|
||||
- [http2](https://nodejs.org/api/http2.html)
|
||||
- [lazy-cache](https://www.npmjs.com/package/lazy-cache)
|
||||
- [react](https://www.npmjs.com/package/react)
|
||||
- [request](https://www.npmjs.com/package/request)
|
||||
- [send](https://www.npmjs.com/package/send)
|
||||
- [typeahead.js](https://www.npmjs.com/package/typeahead.js)
|
||||
- [ws](https://github.com/websockets/ws)
|
||||
@@ -43,8 +46,11 @@
|
||||
| Cross-site scripting through exception (`js/xss-through-exception`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where an exception is written to the DOM. Results are not shown on LGTM by default. |
|
||||
| Regular expression always matches (`js/regex/always-matches`) | correctness, regular-expressions | Highlights regular expression checks that trivially succeed by matching an empty substring. Results are shown on LGTM by default. |
|
||||
| Missing await (`js/missing-await`) | correctness | Highlights expressions that operate directly on a promise object in a nonsensical way, instead of awaiting its result. Results are shown on LGTM by default. |
|
||||
| Prototype pollution in utility function (`js/prototype-pollution-utility`) | security, external/cwe/cwe-400, external/cwe/cwe-471 | Highlights recursive copying operations that are susceptible to prototype pollution. Results are shown on LGTM by default. |
|
||||
| Polynomial regular expression used on uncontrolled data (`js/polynomial-redos`) | security, external/cwe/cwe-730, external/cwe/cwe-400 | Highlights expensive regular expressions that may be used on malicious input. Results are shown on LGTM by default. |
|
||||
| Prototype pollution in utility function (`js/prototype-pollution-utility`) | security, external/cwe/cwe-400, external/cwe/cwe-471 | Highlights recursive assignment operations that are susceptible to prototype pollution. Results are shown on LGTM by default. |
|
||||
| Unsafe jQuery plugin (`js/unsafe-jquery-plugin`) | Highlights potential XSS vulnerabilities in unsafely designed jQuery plugins. Results are shown on LGTM by default. |
|
||||
| Unnecessary use of `cat` process (`js/unnecessary-use-of-cat`) | correctness, security, maintainability | Highlights command executions of `cat` where the fs API should be used instead. Results are shown on LGTM by default. |
|
||||
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
@@ -57,8 +63,10 @@
|
||||
| Expression has no effect (`js/useless-expression`) | Fewer false positive results | The query now recognizes block-level flow type annotations and ignores the first statement of a try block. |
|
||||
| Use of call stack introspection in strict mode (`js/strict-mode-call-stack-introspection`) | Fewer false positive results | The query no longer flags expression statements. |
|
||||
| Missing CSRF middleware (`js/missing-token-validation`) | Fewer false positive results | The query reports fewer duplicates and only flags handlers that explicitly access cookie data. |
|
||||
| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional ways dangerous paths can be constructed. |
|
||||
| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional ways dangerous paths can be constructed and used. |
|
||||
| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional ways of constructing arguments to `cmd.exe` and `/bin/sh`. |
|
||||
| Syntax error (`js/syntax-error`) | Lower severity | This results of this query are now displayed with lower severity. |
|
||||
| Use of password hash with insufficient computational effort (`js/insufficient-password-hash`) | Fewer false positive results | This query now recognizes additional cases that do not require secure hashing. |
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
|
||||
@@ -15,24 +15,33 @@ class ConstantZero extends Expr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `candidate` is an expression such that if it's unsigned then we
|
||||
* want an alert at `ge`.
|
||||
*/
|
||||
private predicate lookForUnsignedAt(GEExpr ge, Expr candidate) {
|
||||
// Base case: `candidate >= 0`
|
||||
ge.getRightOperand() instanceof ConstantZero and
|
||||
candidate = ge.getLeftOperand().getFullyConverted() and
|
||||
// left operand was a signed or unsigned IntegralType before conversions
|
||||
// (not a pointer, checking a pointer >= 0 is an entirely different mistake)
|
||||
// (not an enum, as the fully converted type of an enum is compiler dependent
|
||||
// so checking an enum >= 0 is always reasonable)
|
||||
ge.getLeftOperand().getUnderlyingType() instanceof IntegralType
|
||||
or
|
||||
// Recursive case: `...(largerType)candidate >= 0`
|
||||
exists(Conversion conversion |
|
||||
lookForUnsignedAt(ge, conversion) and
|
||||
candidate = conversion.getExpr() and
|
||||
conversion.getType().getSize() > candidate.getType().getSize()
|
||||
)
|
||||
}
|
||||
|
||||
class UnsignedGEZero extends GEExpr {
|
||||
UnsignedGEZero() {
|
||||
this.getRightOperand() instanceof ConstantZero and
|
||||
// left operand was a signed or unsigned IntegralType before conversions
|
||||
// (not a pointer, checking a pointer >= 0 is an entirely different mistake)
|
||||
// (not an enum, as the fully converted type of an enum is compiler dependent
|
||||
// so checking an enum >= 0 is always reasonable)
|
||||
getLeftOperand().getUnderlyingType() instanceof IntegralType and
|
||||
exists(Expr ue |
|
||||
// ue is some conversion of the left operand
|
||||
ue = getLeftOperand().getConversion*() and
|
||||
// ue is unsigned
|
||||
ue.getUnderlyingType().(IntegralType).isUnsigned() and
|
||||
// ue may be converted to zero or more strictly larger possibly signed types
|
||||
// before it is fully converted
|
||||
forall(Expr following | following = ue.getConversion+() |
|
||||
following.getType().getSize() > ue.getType().getSize()
|
||||
)
|
||||
lookForUnsignedAt(this, ue) and
|
||||
ue.getUnderlyingType().(IntegralType).isUnsigned()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
1
cpp/ql/src/experimental/README.md
Normal file
1
cpp/ql/src/experimental/README.md
Normal file
@@ -0,0 +1 @@
|
||||
This directory contains [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.
|
||||
@@ -19,6 +19,8 @@ import semmle.code.cpp.exprs.Access
|
||||
class Field extends MemberVariable {
|
||||
Field() { fieldoffsets(underlyingElement(this), _, _) }
|
||||
|
||||
override string getCanonicalQLClass() { result = "Field" }
|
||||
|
||||
/**
|
||||
* Gets the offset of this field in bytes from the start of its declaring
|
||||
* type (on the machine where facts were extracted).
|
||||
@@ -84,6 +86,8 @@ class Field extends MemberVariable {
|
||||
class BitField extends Field {
|
||||
BitField() { bitfield(underlyingElement(this), _, _) }
|
||||
|
||||
override string getCanonicalQLClass() { result = "BitField" }
|
||||
|
||||
/**
|
||||
* Gets the size of this bitfield in bits (on the machine where facts
|
||||
* were extracted).
|
||||
|
||||
@@ -28,6 +28,8 @@ private import semmle.code.cpp.internal.ResolveClass
|
||||
* can have multiple declarations.
|
||||
*/
|
||||
class Variable extends Declaration, @variable {
|
||||
override string getCanonicalQLClass() { result = "Variable" }
|
||||
|
||||
/** Gets the initializer of this variable, if any. */
|
||||
Initializer getInitializer() { result.getDeclaration() = this }
|
||||
|
||||
@@ -351,6 +353,8 @@ class StackVariable extends LocalScopeVariable {
|
||||
* A local variable can be declared by a `DeclStmt` or a `ConditionDeclExpr`.
|
||||
*/
|
||||
class LocalVariable extends LocalScopeVariable, @localvariable {
|
||||
override string getCanonicalQLClass() { result = "LocalVariable" }
|
||||
|
||||
override string getName() { localvariables(underlyingElement(this), _, result) }
|
||||
|
||||
override Type getType() { localvariables(underlyingElement(this), unresolveElement(result), _) }
|
||||
@@ -396,6 +400,8 @@ class NamespaceVariable extends GlobalOrNamespaceVariable {
|
||||
NamespaceVariable() {
|
||||
exists(Namespace n | namespacembrs(unresolveElement(n), underlyingElement(this)))
|
||||
}
|
||||
|
||||
override string getCanonicalQLClass() { result = "NamespaceVariable" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -415,6 +421,8 @@ class NamespaceVariable extends GlobalOrNamespaceVariable {
|
||||
*/
|
||||
class GlobalVariable extends GlobalOrNamespaceVariable {
|
||||
GlobalVariable() { not this instanceof NamespaceVariable }
|
||||
|
||||
override string getCanonicalQLClass() { result = "GlobalVariable" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -434,6 +442,8 @@ class GlobalVariable extends GlobalOrNamespaceVariable {
|
||||
class MemberVariable extends Variable, @membervariable {
|
||||
MemberVariable() { this.isMember() }
|
||||
|
||||
override string getCanonicalQLClass() { result = "MemberVariable" }
|
||||
|
||||
/** Holds if this member is private. */
|
||||
predicate isPrivate() { this.hasSpecifier("private") }
|
||||
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -442,6 +442,20 @@ class Expr extends StmtParent, @expr {
|
||||
else result = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unique non-`Conversion` expression `e` for which
|
||||
* `this = e.getConversion*()`.
|
||||
*
|
||||
* For example, if called on the expression `(int)(char)x`, this predicate
|
||||
* gets the expression `x`.
|
||||
*/
|
||||
Expr getUnconverted() {
|
||||
not this instanceof Conversion and
|
||||
result = this
|
||||
or
|
||||
result = this.(Conversion).getExpr().getUnconverted()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of this expression, after any implicit conversions and explicit casts, and after resolving typedefs.
|
||||
*
|
||||
|
||||
@@ -269,7 +269,7 @@ private predicate modelTaintToParameter(Function f, int parameterIn, int paramet
|
||||
|
||||
/**
|
||||
* Holds if `chi` is on the chain of chi-instructions for all aliased memory.
|
||||
* Taint shoud not pass through these instructions since they tend to mix up
|
||||
* Taint should not pass through these instructions since they tend to mix up
|
||||
* unrelated objects.
|
||||
*/
|
||||
private predicate isChiForAllAliasedMemory(Instruction instr) {
|
||||
@@ -277,7 +277,7 @@ private predicate isChiForAllAliasedMemory(Instruction instr) {
|
||||
or
|
||||
isChiForAllAliasedMemory(instr.(ChiInstruction).getTotal())
|
||||
or
|
||||
isChiForAllAliasedMemory(instr.(PhiInstruction).getAnInput())
|
||||
isChiForAllAliasedMemory(instr.(PhiInstruction).getAnInputOperand().getAnyDef())
|
||||
}
|
||||
|
||||
private predicate modelTaintToReturnValue(Function f, int parameterIn) {
|
||||
|
||||
@@ -135,6 +135,12 @@ private module VirtualDispatch {
|
||||
exists(FunctionInstruction fi |
|
||||
this.flowsFrom(DataFlow::instructionNode(fi), _) and
|
||||
result = fi.getFunctionSymbol()
|
||||
) and
|
||||
(
|
||||
this.getNumberOfArguments() <= result.getEffectiveNumberOfParameters() and
|
||||
this.getNumberOfArguments() >= result.getEffectiveNumberOfParameters()
|
||||
or
|
||||
result.isVarargs()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -131,10 +131,7 @@ class ExprNode extends InstructionNode {
|
||||
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
|
||||
* expression.
|
||||
*/
|
||||
Expr getExpr() {
|
||||
result.getConversion*() = instr.getConvertedResultExpression() and
|
||||
not result instanceof Conversion
|
||||
}
|
||||
Expr getExpr() { result = instr.getUnconvertedResultExpression() }
|
||||
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
|
||||
@@ -82,6 +82,7 @@ private newtype TOpcode =
|
||||
TSizedBufferReadSideEffect() or
|
||||
TSizedBufferMustWriteSideEffect() or
|
||||
TSizedBufferMayWriteSideEffect() or
|
||||
TInitializeDynamicAllocation() or
|
||||
TChi() or
|
||||
TInlineAsm() or
|
||||
TUnreached() or
|
||||
@@ -213,23 +214,28 @@ abstract class IndirectReadOpcode extends IndirectMemoryAccessOpcode {
|
||||
}
|
||||
|
||||
/**
|
||||
* An opcode that accesses a memory buffer of unknown size.
|
||||
* An opcode that accesses a memory buffer.
|
||||
*/
|
||||
abstract class BufferAccessOpcode extends Opcode {
|
||||
final override predicate hasAddressOperand() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An opcode that accesses a memory buffer of unknown size.
|
||||
*/
|
||||
abstract class UnsizedBufferAccessOpcode extends BufferAccessOpcode { }
|
||||
|
||||
/**
|
||||
* An opcode that writes to a memory buffer of unknown size.
|
||||
*/
|
||||
abstract class BufferWriteOpcode extends BufferAccessOpcode {
|
||||
abstract class UnsizedBufferWriteOpcode extends UnsizedBufferAccessOpcode {
|
||||
final override MemoryAccessKind getWriteMemoryAccess() { result instanceof BufferMemoryAccess }
|
||||
}
|
||||
|
||||
/**
|
||||
* An opcode that reads from a memory buffer of unknown size.
|
||||
*/
|
||||
abstract class BufferReadOpcode extends BufferAccessOpcode {
|
||||
abstract class UnsizedBufferReadOpcode extends UnsizedBufferAccessOpcode {
|
||||
final override MemoryAccessKind getReadMemoryAccess() { result instanceof BufferMemoryAccess }
|
||||
}
|
||||
|
||||
@@ -261,9 +267,7 @@ abstract class EntireAllocationReadOpcode extends EntireAllocationAccessOpcode {
|
||||
/**
|
||||
* An opcode that accesses a memory buffer whose size is determined by a `BufferSizeOperand`.
|
||||
*/
|
||||
abstract class SizedBufferAccessOpcode extends Opcode {
|
||||
final override predicate hasAddressOperand() { any() }
|
||||
|
||||
abstract class SizedBufferAccessOpcode extends BufferAccessOpcode {
|
||||
final override predicate hasBufferSizeOperand() { any() }
|
||||
}
|
||||
|
||||
@@ -666,17 +670,18 @@ module Opcode {
|
||||
final override string toString() { result = "IndirectMayWriteSideEffect" }
|
||||
}
|
||||
|
||||
class BufferReadSideEffect extends ReadSideEffectOpcode, BufferReadOpcode, TBufferReadSideEffect {
|
||||
class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode,
|
||||
TBufferReadSideEffect {
|
||||
final override string toString() { result = "BufferReadSideEffect" }
|
||||
}
|
||||
|
||||
class BufferMustWriteSideEffect extends WriteSideEffectOpcode, BufferWriteOpcode,
|
||||
class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode,
|
||||
TBufferMustWriteSideEffect {
|
||||
final override string toString() { result = "BufferMustWriteSideEffect" }
|
||||
}
|
||||
|
||||
class BufferMayWriteSideEffect extends WriteSideEffectOpcode, BufferWriteOpcode, MayWriteOpcode,
|
||||
TBufferMayWriteSideEffect {
|
||||
class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode,
|
||||
MayWriteOpcode, TBufferMayWriteSideEffect {
|
||||
final override string toString() { result = "BufferMayWriteSideEffect" }
|
||||
}
|
||||
|
||||
@@ -695,6 +700,11 @@ module Opcode {
|
||||
final override string toString() { result = "SizedBufferMayWriteSideEffect" }
|
||||
}
|
||||
|
||||
class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode,
|
||||
TInitializeDynamicAllocation {
|
||||
final override string toString() { result = "InitializeDynamicAllocation" }
|
||||
}
|
||||
|
||||
class Chi extends Opcode, TChi {
|
||||
final override string toString() { result = "Chi" }
|
||||
|
||||
|
||||
@@ -1,3 +1,275 @@
|
||||
private import IR
|
||||
import InstructionSanity
|
||||
import IRTypeSanity
|
||||
import InstructionSanity // module is below
|
||||
import IRTypeSanity // module is in IRType.qll
|
||||
|
||||
module InstructionSanity {
|
||||
private import internal.InstructionImports as Imports
|
||||
private import Imports::OperandTag
|
||||
private import internal.IRInternal
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
|
||||
*/
|
||||
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
|
||||
exists(OperandTag tag |
|
||||
instr.getOpcode().hasOperand(tag) and
|
||||
not exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
message =
|
||||
"Instruction '" + instr.getOpcode().toString() +
|
||||
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
|
||||
*/
|
||||
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
|
||||
exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
not instr.getOpcode().hasOperand(tag) and
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
|
||||
not (
|
||||
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
|
||||
) and
|
||||
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(
|
||||
Instruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(OperandTag tag, int operandCount |
|
||||
operandCount =
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
operandCount > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag and
|
||||
message =
|
||||
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
|
||||
" in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
|
||||
* the predecessor block `pred`.
|
||||
*/
|
||||
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
not exists(PhiInputOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getPredecessorBlock() = pred
|
||||
)
|
||||
}
|
||||
|
||||
query predicate missingOperandType(Operand operand, string message) {
|
||||
exists(Language::Function func, Instruction use |
|
||||
not exists(operand.getType()) and
|
||||
use = operand.getUse() and
|
||||
func = use.getEnclosingFunction() and
|
||||
message =
|
||||
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
|
||||
"' missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
)
|
||||
}
|
||||
|
||||
query predicate duplicateChiOperand(
|
||||
ChiInstruction chi, string message, IRFunction func, string funcText
|
||||
) {
|
||||
chi.getTotal() = chi.getPartial() and
|
||||
message =
|
||||
"Chi instruction for " + chi.getPartial().toString() +
|
||||
" has duplicate operands in function $@" and
|
||||
func = chi.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
query predicate sideEffectWithoutPrimary(
|
||||
SideEffectInstruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(instr.getPrimaryInstruction()) and
|
||||
message = "Side effect instruction missing primary instruction in function $@" and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an instruction, other than `ExitFunction`, has no successors.
|
||||
*/
|
||||
query predicate instructionWithoutSuccessor(Instruction instr) {
|
||||
not exists(instr.getASuccessor()) and
|
||||
not instr instanceof ExitFunctionInstruction and
|
||||
// Phi instructions aren't linked into the instruction-level flow graph.
|
||||
not instr instanceof PhiInstruction and
|
||||
not instr instanceof UnreachedInstruction
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
|
||||
* where `target` is among the targets of those edges.
|
||||
*/
|
||||
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
|
||||
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
|
||||
n > 1 and
|
||||
source.getSuccessor(kind) = target
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
|
||||
* contains no element that can cause loops.
|
||||
*/
|
||||
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
|
||||
exists(IRBlock block |
|
||||
instr.getBlock() = block and
|
||||
block.getEnclosingFunction() = f and
|
||||
block.getASuccessor+() = block
|
||||
) and
|
||||
not Language::hasPotentialLoop(f)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a `Phi` instruction is present in a block with fewer than two
|
||||
* predecessors.
|
||||
*/
|
||||
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
|
||||
count(instr.getBlock().getAPredecessor()) < 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if operand `operand` consumes a value that was defined in
|
||||
* a different function.
|
||||
*/
|
||||
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
|
||||
operand.getUse() = instr and
|
||||
operand.getAnyDef() = defInstr and
|
||||
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is not in exactly one block.
|
||||
*/
|
||||
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
|
||||
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||
b1.getASuccessor() = b2 and
|
||||
not b1.getBackEdgeSuccessor(_) = b2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` contains a loop in which no edge is a back edge.
|
||||
*
|
||||
* This check ensures we don't have too _few_ back edges.
|
||||
*/
|
||||
query predicate containsLoopOfForwardEdges(IRFunction f) {
|
||||
exists(IRBlock block |
|
||||
forwardEdge+(block, block) and
|
||||
block.getEnclosingIRFunction() = f
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `block` is reachable from its function entry point but would not
|
||||
* be reachable by traversing only forward edges. This check is skipped for
|
||||
* functions containing `goto` statements as the property does not generally
|
||||
* hold there.
|
||||
*
|
||||
* This check ensures we don't have too _many_ back edges.
|
||||
*/
|
||||
query predicate lostReachability(IRBlock block) {
|
||||
exists(IRFunction f, IRBlock entry |
|
||||
entry = f.getEntryBlock() and
|
||||
entry.getASuccessor+() = block and
|
||||
not forwardEdge+(entry, block) and
|
||||
not Language::hasGoto(f.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the number of back edges differs between the `Instruction` graph
|
||||
* and the `IRBlock` graph.
|
||||
*/
|
||||
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
|
||||
fromInstr =
|
||||
count(Instruction i1, Instruction i2 |
|
||||
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||
) and
|
||||
fromBlock =
|
||||
count(IRBlock b1, IRBlock b2 |
|
||||
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
|
||||
) and
|
||||
fromInstr != fromBlock
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the point in the function at which the specified operand is evaluated. For most operands,
|
||||
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
|
||||
* of evaluation is at the end of the corresponding predecessor block.
|
||||
*/
|
||||
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
|
||||
block = operand.(PhiInputOperand).getPredecessorBlock() and
|
||||
index = block.getInstructionCount()
|
||||
or
|
||||
exists(Instruction use |
|
||||
use = operand.(NonPhiOperand).getUse() and
|
||||
block.getInstruction(index) = use
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `useOperand` has a definition that does not dominate the use.
|
||||
*/
|
||||
query predicate useNotDominatedByDefinition(
|
||||
Operand useOperand, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
|
||||
not useOperand.getUse() instanceof UnmodeledUseInstruction and
|
||||
not defInstr instanceof UnmodeledDefinitionInstruction and
|
||||
pointOfEvaluation(useOperand, useBlock, useIndex) and
|
||||
defInstr = useOperand.getAnyDef() and
|
||||
(
|
||||
defInstr instanceof PhiInstruction and
|
||||
defBlock = defInstr.getBlock() and
|
||||
defIndex = -1
|
||||
or
|
||||
defBlock.getInstruction(defIndex) = defInstr
|
||||
) and
|
||||
not (
|
||||
defBlock.strictlyDominates(useBlock)
|
||||
or
|
||||
defBlock = useBlock and
|
||||
defIndex < useIndex
|
||||
) and
|
||||
message =
|
||||
"Operand '" + useOperand.toString() +
|
||||
"' is not dominated by its definition in function '$@'." and
|
||||
func = useOperand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
query predicate switchInstructionWithoutDefaultEdge(
|
||||
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(switchInstr.getDefaultSuccessor()) and
|
||||
message =
|
||||
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
|
||||
func = switchInstr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
|
||||
/**
|
||||
* A temporary variable introduced by IR construction. The most common examples are the variable
|
||||
* generated to hold the return value of afunction, or the variable generated to hold the result of
|
||||
* generated to hold the return value of a function, or the variable generated to hold the result of
|
||||
* a condition operator (`a ? b : c`).
|
||||
*/
|
||||
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
|
||||
@@ -10,274 +10,6 @@ import Imports::MemoryAccessKind
|
||||
import Imports::Opcode
|
||||
private import Imports::OperandTag
|
||||
|
||||
module InstructionSanity {
|
||||
/**
|
||||
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
|
||||
*/
|
||||
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
|
||||
exists(OperandTag tag |
|
||||
instr.getOpcode().hasOperand(tag) and
|
||||
not exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
message =
|
||||
"Instruction '" + instr.getOpcode().toString() +
|
||||
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
|
||||
*/
|
||||
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
|
||||
exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
not instr.getOpcode().hasOperand(tag) and
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
|
||||
not (
|
||||
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
|
||||
) and
|
||||
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(
|
||||
Instruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(OperandTag tag, int operandCount |
|
||||
operandCount =
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
operandCount > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag and
|
||||
message =
|
||||
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
|
||||
" in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
|
||||
* the predecessor block `pred`.
|
||||
*/
|
||||
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
not exists(PhiInputOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getPredecessorBlock() = pred
|
||||
)
|
||||
}
|
||||
|
||||
query predicate missingOperandType(Operand operand, string message) {
|
||||
exists(Language::Function func, Instruction use |
|
||||
not exists(operand.getType()) and
|
||||
use = operand.getUse() and
|
||||
func = use.getEnclosingFunction() and
|
||||
message =
|
||||
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
|
||||
"' missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
)
|
||||
}
|
||||
|
||||
query predicate duplicateChiOperand(
|
||||
ChiInstruction chi, string message, IRFunction func, string funcText
|
||||
) {
|
||||
chi.getTotal() = chi.getPartial() and
|
||||
message =
|
||||
"Chi instruction for " + chi.getPartial().toString() +
|
||||
" has duplicate operands in function $@" and
|
||||
func = chi.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
query predicate sideEffectWithoutPrimary(
|
||||
SideEffectInstruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(instr.getPrimaryInstruction()) and
|
||||
message = "Side effect instruction missing primary instruction in function $@" and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an instruction, other than `ExitFunction`, has no successors.
|
||||
*/
|
||||
query predicate instructionWithoutSuccessor(Instruction instr) {
|
||||
not exists(instr.getASuccessor()) and
|
||||
not instr instanceof ExitFunctionInstruction and
|
||||
// Phi instructions aren't linked into the instruction-level flow graph.
|
||||
not instr instanceof PhiInstruction and
|
||||
not instr instanceof UnreachedInstruction
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
|
||||
* where `target` is among the targets of those edges.
|
||||
*/
|
||||
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
|
||||
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
|
||||
n > 1 and
|
||||
source.getSuccessor(kind) = target
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
|
||||
* contains no element that can cause loops.
|
||||
*/
|
||||
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
|
||||
exists(IRBlock block |
|
||||
instr.getBlock() = block and
|
||||
block.getEnclosingFunction() = f and
|
||||
block.getASuccessor+() = block
|
||||
) and
|
||||
not Language::hasPotentialLoop(f)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a `Phi` instruction is present in a block with fewer than two
|
||||
* predecessors.
|
||||
*/
|
||||
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
|
||||
count(instr.getBlock().getAPredecessor()) < 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if operand `operand` consumes a value that was defined in
|
||||
* a different function.
|
||||
*/
|
||||
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
|
||||
operand.getUse() = instr and
|
||||
operand.getAnyDef() = defInstr and
|
||||
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is not in exactly one block.
|
||||
*/
|
||||
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
|
||||
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||
b1.getASuccessor() = b2 and
|
||||
not b1.getBackEdgeSuccessor(_) = b2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` contains a loop in which no edge is a back edge.
|
||||
*
|
||||
* This check ensures we don't have too _few_ back edges.
|
||||
*/
|
||||
query predicate containsLoopOfForwardEdges(IRFunction f) {
|
||||
exists(IRBlock block |
|
||||
forwardEdge+(block, block) and
|
||||
block.getEnclosingIRFunction() = f
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `block` is reachable from its function entry point but would not
|
||||
* be reachable by traversing only forward edges. This check is skipped for
|
||||
* functions containing `goto` statements as the property does not generally
|
||||
* hold there.
|
||||
*
|
||||
* This check ensures we don't have too _many_ back edges.
|
||||
*/
|
||||
query predicate lostReachability(IRBlock block) {
|
||||
exists(IRFunction f, IRBlock entry |
|
||||
entry = f.getEntryBlock() and
|
||||
entry.getASuccessor+() = block and
|
||||
not forwardEdge+(entry, block) and
|
||||
not Language::hasGoto(f.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the number of back edges differs between the `Instruction` graph
|
||||
* and the `IRBlock` graph.
|
||||
*/
|
||||
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
|
||||
fromInstr =
|
||||
count(Instruction i1, Instruction i2 |
|
||||
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||
) and
|
||||
fromBlock =
|
||||
count(IRBlock b1, IRBlock b2 |
|
||||
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
|
||||
) and
|
||||
fromInstr != fromBlock
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the point in the function at which the specified operand is evaluated. For most operands,
|
||||
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
|
||||
* of evaluation is at the end of the corresponding predecessor block.
|
||||
*/
|
||||
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
|
||||
block = operand.(PhiInputOperand).getPredecessorBlock() and
|
||||
index = block.getInstructionCount()
|
||||
or
|
||||
exists(Instruction use |
|
||||
use = operand.(NonPhiOperand).getUse() and
|
||||
block.getInstruction(index) = use
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `useOperand` has a definition that does not dominate the use.
|
||||
*/
|
||||
query predicate useNotDominatedByDefinition(
|
||||
Operand useOperand, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
|
||||
not useOperand.getUse() instanceof UnmodeledUseInstruction and
|
||||
not defInstr instanceof UnmodeledDefinitionInstruction and
|
||||
pointOfEvaluation(useOperand, useBlock, useIndex) and
|
||||
defInstr = useOperand.getAnyDef() and
|
||||
(
|
||||
defInstr instanceof PhiInstruction and
|
||||
defBlock = defInstr.getBlock() and
|
||||
defIndex = -1
|
||||
or
|
||||
defBlock.getInstruction(defIndex) = defInstr
|
||||
) and
|
||||
not (
|
||||
defBlock.strictlyDominates(useBlock)
|
||||
or
|
||||
defBlock = useBlock and
|
||||
defIndex < useIndex
|
||||
) and
|
||||
message =
|
||||
"Operand '" + useOperand.toString() +
|
||||
"' is not dominated by its definition in function '$@'." and
|
||||
func = useOperand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
query predicate switchInstructionWithoutDefaultEdge(
|
||||
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(switchInstr.getDefaultSuccessor()) and
|
||||
message =
|
||||
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
|
||||
func = switchInstr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified
|
||||
* `File` and line number. Used for assigning register names when printing IR.
|
||||
@@ -1204,6 +936,11 @@ class CallInstruction extends Instruction {
|
||||
final Instruction getPositionalArgument(int index) {
|
||||
result = getPositionalArgumentOperand(index).getDef()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of arguments of the call, including the `this` pointer, if any.
|
||||
*/
|
||||
final int getNumberOfArguments() { result = count(this.getAnArgumentOperand()) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1352,6 +1089,26 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
|
||||
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the initial value of newly allocated memory, e.g. the result of a
|
||||
* call to `malloc`.
|
||||
*/
|
||||
class InitializeDynamicAllocationInstruction extends SideEffectInstruction {
|
||||
InitializeDynamicAllocationInstruction() {
|
||||
getOpcode() instanceof Opcode::InitializeDynamicAllocation
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the address of the allocation this instruction is initializing.
|
||||
*/
|
||||
final AddressOperand getAllocationAddressOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the operand for the allocation this instruction is initializing.
|
||||
*/
|
||||
final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a GNU or MSVC inline assembly statement.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,9 @@ private newtype TAllocation =
|
||||
TVariableAllocation(IRVariable var) or
|
||||
TIndirectParameterAllocation(IRAutomaticUserVariable var) {
|
||||
exists(InitializeIndirectionInstruction instr | instr.getIRVariable() = var)
|
||||
} or
|
||||
TDynamicAllocation(CallInstruction call) {
|
||||
exists(InitializeDynamicAllocationInstruction instr | instr.getPrimaryInstruction() = call)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,3 +98,29 @@ class IndirectParameterAllocation extends Allocation, TIndirectParameterAllocati
|
||||
|
||||
final override predicate alwaysEscapes() { none() }
|
||||
}
|
||||
|
||||
class DynamicAllocation extends Allocation, TDynamicAllocation {
|
||||
CallInstruction call;
|
||||
|
||||
DynamicAllocation() { this = TDynamicAllocation(call) }
|
||||
|
||||
final override string toString() {
|
||||
result = call.toString() + " at " + call.getLocation() // This isn't performant, but it's only used in test/dump code right now.
|
||||
}
|
||||
|
||||
final override CallInstruction getABaseInstruction() { result = call }
|
||||
|
||||
final override IRFunction getEnclosingIRFunction() { result = call.getEnclosingIRFunction() }
|
||||
|
||||
final override Language::Location getLocation() { result = call.getLocation() }
|
||||
|
||||
final override string getUniqueId() { result = call.getUniqueId() }
|
||||
|
||||
final override IRType getIRType() { result instanceof IRUnknownType }
|
||||
|
||||
final override predicate isReadOnly() { none() }
|
||||
|
||||
final override predicate isAlwaysAllocatedOnStack() { none() }
|
||||
|
||||
final override predicate alwaysEscapes() { none() }
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ private predicate hasResultMemoryAccess(
|
||||
type = languageType.getIRType() and
|
||||
isIndirectOrBufferMemoryAccess(instr.getResultMemoryAccess()) and
|
||||
(if instr.hasResultMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and
|
||||
if type.getByteSize() > 0
|
||||
if exists(type.getByteSize())
|
||||
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
|
||||
else endBitOffset = Ints::unknown()
|
||||
)
|
||||
@@ -43,7 +43,7 @@ private predicate hasOperandMemoryAccess(
|
||||
type = languageType.getIRType() and
|
||||
isIndirectOrBufferMemoryAccess(operand.getMemoryAccess()) and
|
||||
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
|
||||
if type.getByteSize() > 0
|
||||
if exists(type.getByteSize())
|
||||
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
|
||||
else endBitOffset = Ints::unknown()
|
||||
)
|
||||
@@ -68,8 +68,12 @@ private newtype TMemoryLocation =
|
||||
) and
|
||||
languageType = type.getCanonicalLanguageType()
|
||||
} or
|
||||
TEntireAllocationMemoryLocation(IndirectParameterAllocation var, boolean isMayAccess) {
|
||||
isMayAccess = false or isMayAccess = true
|
||||
TEntireAllocationMemoryLocation(Allocation var, boolean isMayAccess) {
|
||||
(
|
||||
var instanceof IndirectParameterAllocation or
|
||||
var instanceof DynamicAllocation
|
||||
) and
|
||||
(isMayAccess = false or isMayAccess = true)
|
||||
} or
|
||||
TUnknownMemoryLocation(IRFunction irFunc, boolean isMayAccess) {
|
||||
isMayAccess = false or isMayAccess = true
|
||||
|
||||
@@ -665,17 +665,18 @@ module DefUse {
|
||||
private predicate definitionReachesRank(
|
||||
Alias::MemoryLocation useLocation, OldBlock block, int defRank, int reachesRank
|
||||
) {
|
||||
// The def always reaches the next use, even if there is also a def on the
|
||||
// use instruction.
|
||||
hasDefinitionAtRank(useLocation, _, block, defRank, _) and
|
||||
reachesRank <= exitRank(useLocation, block) and // Without this, the predicate would be infinite.
|
||||
(
|
||||
// The def always reaches the next use, even if there is also a def on the
|
||||
// use instruction.
|
||||
reachesRank = defRank + 1
|
||||
or
|
||||
// If the def reached the previous rank, it also reaches the current rank,
|
||||
// unless there was another def at the previous rank.
|
||||
definitionReachesRank(useLocation, block, defRank, reachesRank - 1) and
|
||||
not hasDefinitionAtRank(useLocation, _, block, reachesRank - 1, _)
|
||||
reachesRank = defRank + 1
|
||||
or
|
||||
// If the def reached the previous rank, it also reaches the current rank,
|
||||
// unless there was another def at the previous rank.
|
||||
exists(int prevRank |
|
||||
reachesRank = prevRank + 1 and
|
||||
definitionReachesRank(useLocation, block, defRank, prevRank) and
|
||||
not prevRank = exitRank(useLocation, block) and
|
||||
not hasDefinitionAtRank(useLocation, _, block, prevRank, _)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,275 @@
|
||||
private import IR
|
||||
import InstructionSanity
|
||||
import IRTypeSanity
|
||||
import InstructionSanity // module is below
|
||||
import IRTypeSanity // module is in IRType.qll
|
||||
|
||||
module InstructionSanity {
|
||||
private import internal.InstructionImports as Imports
|
||||
private import Imports::OperandTag
|
||||
private import internal.IRInternal
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
|
||||
*/
|
||||
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
|
||||
exists(OperandTag tag |
|
||||
instr.getOpcode().hasOperand(tag) and
|
||||
not exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
message =
|
||||
"Instruction '" + instr.getOpcode().toString() +
|
||||
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
|
||||
*/
|
||||
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
|
||||
exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
not instr.getOpcode().hasOperand(tag) and
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
|
||||
not (
|
||||
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
|
||||
) and
|
||||
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(
|
||||
Instruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(OperandTag tag, int operandCount |
|
||||
operandCount =
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
operandCount > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag and
|
||||
message =
|
||||
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
|
||||
" in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
|
||||
* the predecessor block `pred`.
|
||||
*/
|
||||
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
not exists(PhiInputOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getPredecessorBlock() = pred
|
||||
)
|
||||
}
|
||||
|
||||
query predicate missingOperandType(Operand operand, string message) {
|
||||
exists(Language::Function func, Instruction use |
|
||||
not exists(operand.getType()) and
|
||||
use = operand.getUse() and
|
||||
func = use.getEnclosingFunction() and
|
||||
message =
|
||||
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
|
||||
"' missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
)
|
||||
}
|
||||
|
||||
query predicate duplicateChiOperand(
|
||||
ChiInstruction chi, string message, IRFunction func, string funcText
|
||||
) {
|
||||
chi.getTotal() = chi.getPartial() and
|
||||
message =
|
||||
"Chi instruction for " + chi.getPartial().toString() +
|
||||
" has duplicate operands in function $@" and
|
||||
func = chi.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
query predicate sideEffectWithoutPrimary(
|
||||
SideEffectInstruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(instr.getPrimaryInstruction()) and
|
||||
message = "Side effect instruction missing primary instruction in function $@" and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an instruction, other than `ExitFunction`, has no successors.
|
||||
*/
|
||||
query predicate instructionWithoutSuccessor(Instruction instr) {
|
||||
not exists(instr.getASuccessor()) and
|
||||
not instr instanceof ExitFunctionInstruction and
|
||||
// Phi instructions aren't linked into the instruction-level flow graph.
|
||||
not instr instanceof PhiInstruction and
|
||||
not instr instanceof UnreachedInstruction
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
|
||||
* where `target` is among the targets of those edges.
|
||||
*/
|
||||
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
|
||||
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
|
||||
n > 1 and
|
||||
source.getSuccessor(kind) = target
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
|
||||
* contains no element that can cause loops.
|
||||
*/
|
||||
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
|
||||
exists(IRBlock block |
|
||||
instr.getBlock() = block and
|
||||
block.getEnclosingFunction() = f and
|
||||
block.getASuccessor+() = block
|
||||
) and
|
||||
not Language::hasPotentialLoop(f)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a `Phi` instruction is present in a block with fewer than two
|
||||
* predecessors.
|
||||
*/
|
||||
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
|
||||
count(instr.getBlock().getAPredecessor()) < 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if operand `operand` consumes a value that was defined in
|
||||
* a different function.
|
||||
*/
|
||||
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
|
||||
operand.getUse() = instr and
|
||||
operand.getAnyDef() = defInstr and
|
||||
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is not in exactly one block.
|
||||
*/
|
||||
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
|
||||
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||
b1.getASuccessor() = b2 and
|
||||
not b1.getBackEdgeSuccessor(_) = b2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` contains a loop in which no edge is a back edge.
|
||||
*
|
||||
* This check ensures we don't have too _few_ back edges.
|
||||
*/
|
||||
query predicate containsLoopOfForwardEdges(IRFunction f) {
|
||||
exists(IRBlock block |
|
||||
forwardEdge+(block, block) and
|
||||
block.getEnclosingIRFunction() = f
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `block` is reachable from its function entry point but would not
|
||||
* be reachable by traversing only forward edges. This check is skipped for
|
||||
* functions containing `goto` statements as the property does not generally
|
||||
* hold there.
|
||||
*
|
||||
* This check ensures we don't have too _many_ back edges.
|
||||
*/
|
||||
query predicate lostReachability(IRBlock block) {
|
||||
exists(IRFunction f, IRBlock entry |
|
||||
entry = f.getEntryBlock() and
|
||||
entry.getASuccessor+() = block and
|
||||
not forwardEdge+(entry, block) and
|
||||
not Language::hasGoto(f.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the number of back edges differs between the `Instruction` graph
|
||||
* and the `IRBlock` graph.
|
||||
*/
|
||||
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
|
||||
fromInstr =
|
||||
count(Instruction i1, Instruction i2 |
|
||||
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||
) and
|
||||
fromBlock =
|
||||
count(IRBlock b1, IRBlock b2 |
|
||||
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
|
||||
) and
|
||||
fromInstr != fromBlock
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the point in the function at which the specified operand is evaluated. For most operands,
|
||||
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
|
||||
* of evaluation is at the end of the corresponding predecessor block.
|
||||
*/
|
||||
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
|
||||
block = operand.(PhiInputOperand).getPredecessorBlock() and
|
||||
index = block.getInstructionCount()
|
||||
or
|
||||
exists(Instruction use |
|
||||
use = operand.(NonPhiOperand).getUse() and
|
||||
block.getInstruction(index) = use
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `useOperand` has a definition that does not dominate the use.
|
||||
*/
|
||||
query predicate useNotDominatedByDefinition(
|
||||
Operand useOperand, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
|
||||
not useOperand.getUse() instanceof UnmodeledUseInstruction and
|
||||
not defInstr instanceof UnmodeledDefinitionInstruction and
|
||||
pointOfEvaluation(useOperand, useBlock, useIndex) and
|
||||
defInstr = useOperand.getAnyDef() and
|
||||
(
|
||||
defInstr instanceof PhiInstruction and
|
||||
defBlock = defInstr.getBlock() and
|
||||
defIndex = -1
|
||||
or
|
||||
defBlock.getInstruction(defIndex) = defInstr
|
||||
) and
|
||||
not (
|
||||
defBlock.strictlyDominates(useBlock)
|
||||
or
|
||||
defBlock = useBlock and
|
||||
defIndex < useIndex
|
||||
) and
|
||||
message =
|
||||
"Operand '" + useOperand.toString() +
|
||||
"' is not dominated by its definition in function '$@'." and
|
||||
func = useOperand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
query predicate switchInstructionWithoutDefaultEdge(
|
||||
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(switchInstr.getDefaultSuccessor()) and
|
||||
message =
|
||||
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
|
||||
func = switchInstr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
|
||||
/**
|
||||
* A temporary variable introduced by IR construction. The most common examples are the variable
|
||||
* generated to hold the return value of afunction, or the variable generated to hold the result of
|
||||
* generated to hold the return value of a function, or the variable generated to hold the result of
|
||||
* a condition operator (`a ? b : c`).
|
||||
*/
|
||||
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
|
||||
@@ -10,274 +10,6 @@ import Imports::MemoryAccessKind
|
||||
import Imports::Opcode
|
||||
private import Imports::OperandTag
|
||||
|
||||
module InstructionSanity {
|
||||
/**
|
||||
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
|
||||
*/
|
||||
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
|
||||
exists(OperandTag tag |
|
||||
instr.getOpcode().hasOperand(tag) and
|
||||
not exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
message =
|
||||
"Instruction '" + instr.getOpcode().toString() +
|
||||
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
|
||||
*/
|
||||
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
|
||||
exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
not instr.getOpcode().hasOperand(tag) and
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
|
||||
not (
|
||||
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
|
||||
) and
|
||||
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(
|
||||
Instruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(OperandTag tag, int operandCount |
|
||||
operandCount =
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
operandCount > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag and
|
||||
message =
|
||||
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
|
||||
" in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
|
||||
* the predecessor block `pred`.
|
||||
*/
|
||||
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
not exists(PhiInputOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getPredecessorBlock() = pred
|
||||
)
|
||||
}
|
||||
|
||||
query predicate missingOperandType(Operand operand, string message) {
|
||||
exists(Language::Function func, Instruction use |
|
||||
not exists(operand.getType()) and
|
||||
use = operand.getUse() and
|
||||
func = use.getEnclosingFunction() and
|
||||
message =
|
||||
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
|
||||
"' missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
)
|
||||
}
|
||||
|
||||
query predicate duplicateChiOperand(
|
||||
ChiInstruction chi, string message, IRFunction func, string funcText
|
||||
) {
|
||||
chi.getTotal() = chi.getPartial() and
|
||||
message =
|
||||
"Chi instruction for " + chi.getPartial().toString() +
|
||||
" has duplicate operands in function $@" and
|
||||
func = chi.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
query predicate sideEffectWithoutPrimary(
|
||||
SideEffectInstruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(instr.getPrimaryInstruction()) and
|
||||
message = "Side effect instruction missing primary instruction in function $@" and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an instruction, other than `ExitFunction`, has no successors.
|
||||
*/
|
||||
query predicate instructionWithoutSuccessor(Instruction instr) {
|
||||
not exists(instr.getASuccessor()) and
|
||||
not instr instanceof ExitFunctionInstruction and
|
||||
// Phi instructions aren't linked into the instruction-level flow graph.
|
||||
not instr instanceof PhiInstruction and
|
||||
not instr instanceof UnreachedInstruction
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
|
||||
* where `target` is among the targets of those edges.
|
||||
*/
|
||||
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
|
||||
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
|
||||
n > 1 and
|
||||
source.getSuccessor(kind) = target
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
|
||||
* contains no element that can cause loops.
|
||||
*/
|
||||
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
|
||||
exists(IRBlock block |
|
||||
instr.getBlock() = block and
|
||||
block.getEnclosingFunction() = f and
|
||||
block.getASuccessor+() = block
|
||||
) and
|
||||
not Language::hasPotentialLoop(f)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a `Phi` instruction is present in a block with fewer than two
|
||||
* predecessors.
|
||||
*/
|
||||
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
|
||||
count(instr.getBlock().getAPredecessor()) < 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if operand `operand` consumes a value that was defined in
|
||||
* a different function.
|
||||
*/
|
||||
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
|
||||
operand.getUse() = instr and
|
||||
operand.getAnyDef() = defInstr and
|
||||
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is not in exactly one block.
|
||||
*/
|
||||
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
|
||||
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||
b1.getASuccessor() = b2 and
|
||||
not b1.getBackEdgeSuccessor(_) = b2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` contains a loop in which no edge is a back edge.
|
||||
*
|
||||
* This check ensures we don't have too _few_ back edges.
|
||||
*/
|
||||
query predicate containsLoopOfForwardEdges(IRFunction f) {
|
||||
exists(IRBlock block |
|
||||
forwardEdge+(block, block) and
|
||||
block.getEnclosingIRFunction() = f
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `block` is reachable from its function entry point but would not
|
||||
* be reachable by traversing only forward edges. This check is skipped for
|
||||
* functions containing `goto` statements as the property does not generally
|
||||
* hold there.
|
||||
*
|
||||
* This check ensures we don't have too _many_ back edges.
|
||||
*/
|
||||
query predicate lostReachability(IRBlock block) {
|
||||
exists(IRFunction f, IRBlock entry |
|
||||
entry = f.getEntryBlock() and
|
||||
entry.getASuccessor+() = block and
|
||||
not forwardEdge+(entry, block) and
|
||||
not Language::hasGoto(f.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the number of back edges differs between the `Instruction` graph
|
||||
* and the `IRBlock` graph.
|
||||
*/
|
||||
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
|
||||
fromInstr =
|
||||
count(Instruction i1, Instruction i2 |
|
||||
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||
) and
|
||||
fromBlock =
|
||||
count(IRBlock b1, IRBlock b2 |
|
||||
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
|
||||
) and
|
||||
fromInstr != fromBlock
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the point in the function at which the specified operand is evaluated. For most operands,
|
||||
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
|
||||
* of evaluation is at the end of the corresponding predecessor block.
|
||||
*/
|
||||
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
|
||||
block = operand.(PhiInputOperand).getPredecessorBlock() and
|
||||
index = block.getInstructionCount()
|
||||
or
|
||||
exists(Instruction use |
|
||||
use = operand.(NonPhiOperand).getUse() and
|
||||
block.getInstruction(index) = use
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `useOperand` has a definition that does not dominate the use.
|
||||
*/
|
||||
query predicate useNotDominatedByDefinition(
|
||||
Operand useOperand, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
|
||||
not useOperand.getUse() instanceof UnmodeledUseInstruction and
|
||||
not defInstr instanceof UnmodeledDefinitionInstruction and
|
||||
pointOfEvaluation(useOperand, useBlock, useIndex) and
|
||||
defInstr = useOperand.getAnyDef() and
|
||||
(
|
||||
defInstr instanceof PhiInstruction and
|
||||
defBlock = defInstr.getBlock() and
|
||||
defIndex = -1
|
||||
or
|
||||
defBlock.getInstruction(defIndex) = defInstr
|
||||
) and
|
||||
not (
|
||||
defBlock.strictlyDominates(useBlock)
|
||||
or
|
||||
defBlock = useBlock and
|
||||
defIndex < useIndex
|
||||
) and
|
||||
message =
|
||||
"Operand '" + useOperand.toString() +
|
||||
"' is not dominated by its definition in function '$@'." and
|
||||
func = useOperand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
query predicate switchInstructionWithoutDefaultEdge(
|
||||
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(switchInstr.getDefaultSuccessor()) and
|
||||
message =
|
||||
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
|
||||
func = switchInstr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified
|
||||
* `File` and line number. Used for assigning register names when printing IR.
|
||||
@@ -1204,6 +936,11 @@ class CallInstruction extends Instruction {
|
||||
final Instruction getPositionalArgument(int index) {
|
||||
result = getPositionalArgumentOperand(index).getDef()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of arguments of the call, including the `this` pointer, if any.
|
||||
*/
|
||||
final int getNumberOfArguments() { result = count(this.getAnArgumentOperand()) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1352,6 +1089,26 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
|
||||
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the initial value of newly allocated memory, e.g. the result of a
|
||||
* call to `malloc`.
|
||||
*/
|
||||
class InitializeDynamicAllocationInstruction extends SideEffectInstruction {
|
||||
InitializeDynamicAllocationInstruction() {
|
||||
getOpcode() instanceof Opcode::InitializeDynamicAllocation
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the address of the allocation this instruction is initializing.
|
||||
*/
|
||||
final AddressOperand getAllocationAddressOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the operand for the allocation this instruction is initializing.
|
||||
*/
|
||||
final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a GNU or MSVC inline assembly statement.
|
||||
*/
|
||||
|
||||
@@ -68,14 +68,7 @@ private module Cached {
|
||||
|
||||
cached
|
||||
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
exists(Expr converted |
|
||||
result = converted.(Conversion).getExpr+()
|
||||
or
|
||||
result = converted
|
||||
|
|
||||
not result instanceof Conversion and
|
||||
converted = getInstructionConvertedResultExpression(instruction)
|
||||
)
|
||||
result = getInstructionConvertedResultExpression(instruction).getUnconverted()
|
||||
}
|
||||
|
||||
cached
|
||||
|
||||
@@ -341,16 +341,32 @@ class TranslatedSideEffects extends TranslatedElement, TTranslatedSideEffects {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) { none() }
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) {
|
||||
expr.getTarget() instanceof AllocationFunction and
|
||||
opcode instanceof Opcode::InitializeDynamicAllocation and
|
||||
tag = OnlyInstructionTag() and
|
||||
type = getUnknownType()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() { result = getChild(0).getFirstInstruction() }
|
||||
override Instruction getFirstInstruction() {
|
||||
if expr.getTarget() instanceof AllocationFunction
|
||||
then result = getInstruction(OnlyInstructionTag())
|
||||
else result = getChild(0).getFirstInstruction()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
kind = gotoEdge() and
|
||||
expr.getTarget() instanceof AllocationFunction and
|
||||
if exists(getChild(0))
|
||||
then result = getChild(0).getFirstInstruction()
|
||||
else result = getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() }
|
||||
|
||||
override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
|
||||
none()
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
operandTag = addressOperand() and
|
||||
result = getPrimaryInstructionForSideEffect(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
|
||||
@@ -487,7 +503,7 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff
|
||||
}
|
||||
|
||||
override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
|
||||
if hasSpecificReadSideEffect(any(Opcode::BufferReadSideEffect op))
|
||||
if hasSpecificReadSideEffect(any(BufferAccessOpcode op))
|
||||
then
|
||||
result = getUnknownType() and
|
||||
tag instanceof OnlyInstructionTag and
|
||||
|
||||
@@ -411,7 +411,9 @@ newtype TTranslatedElement =
|
||||
TTranslatedConditionDecl(ConditionDeclExpr expr) { not ignoreExpr(expr) } or
|
||||
// The side effects of a `Call`
|
||||
TTranslatedSideEffects(Call expr) {
|
||||
exists(TTranslatedArgumentSideEffect(expr, _, _, _)) or expr instanceof ConstructorCall
|
||||
exists(TTranslatedArgumentSideEffect(expr, _, _, _)) or
|
||||
expr instanceof ConstructorCall or
|
||||
expr.getTarget() instanceof AllocationFunction
|
||||
} or // A precise side effect of an argument to a `Call`
|
||||
TTranslatedArgumentSideEffect(Call call, Expr expr, int n, boolean isWrite) {
|
||||
(
|
||||
|
||||
@@ -1,3 +1,275 @@
|
||||
private import IR
|
||||
import InstructionSanity
|
||||
import IRTypeSanity
|
||||
import InstructionSanity // module is below
|
||||
import IRTypeSanity // module is in IRType.qll
|
||||
|
||||
module InstructionSanity {
|
||||
private import internal.InstructionImports as Imports
|
||||
private import Imports::OperandTag
|
||||
private import internal.IRInternal
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
|
||||
*/
|
||||
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
|
||||
exists(OperandTag tag |
|
||||
instr.getOpcode().hasOperand(tag) and
|
||||
not exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
message =
|
||||
"Instruction '" + instr.getOpcode().toString() +
|
||||
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
|
||||
*/
|
||||
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
|
||||
exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
not instr.getOpcode().hasOperand(tag) and
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
|
||||
not (
|
||||
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
|
||||
) and
|
||||
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(
|
||||
Instruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(OperandTag tag, int operandCount |
|
||||
operandCount =
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
operandCount > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag and
|
||||
message =
|
||||
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
|
||||
" in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
|
||||
* the predecessor block `pred`.
|
||||
*/
|
||||
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
not exists(PhiInputOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getPredecessorBlock() = pred
|
||||
)
|
||||
}
|
||||
|
||||
query predicate missingOperandType(Operand operand, string message) {
|
||||
exists(Language::Function func, Instruction use |
|
||||
not exists(operand.getType()) and
|
||||
use = operand.getUse() and
|
||||
func = use.getEnclosingFunction() and
|
||||
message =
|
||||
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
|
||||
"' missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
)
|
||||
}
|
||||
|
||||
query predicate duplicateChiOperand(
|
||||
ChiInstruction chi, string message, IRFunction func, string funcText
|
||||
) {
|
||||
chi.getTotal() = chi.getPartial() and
|
||||
message =
|
||||
"Chi instruction for " + chi.getPartial().toString() +
|
||||
" has duplicate operands in function $@" and
|
||||
func = chi.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
query predicate sideEffectWithoutPrimary(
|
||||
SideEffectInstruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(instr.getPrimaryInstruction()) and
|
||||
message = "Side effect instruction missing primary instruction in function $@" and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an instruction, other than `ExitFunction`, has no successors.
|
||||
*/
|
||||
query predicate instructionWithoutSuccessor(Instruction instr) {
|
||||
not exists(instr.getASuccessor()) and
|
||||
not instr instanceof ExitFunctionInstruction and
|
||||
// Phi instructions aren't linked into the instruction-level flow graph.
|
||||
not instr instanceof PhiInstruction and
|
||||
not instr instanceof UnreachedInstruction
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
|
||||
* where `target` is among the targets of those edges.
|
||||
*/
|
||||
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
|
||||
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
|
||||
n > 1 and
|
||||
source.getSuccessor(kind) = target
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
|
||||
* contains no element that can cause loops.
|
||||
*/
|
||||
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
|
||||
exists(IRBlock block |
|
||||
instr.getBlock() = block and
|
||||
block.getEnclosingFunction() = f and
|
||||
block.getASuccessor+() = block
|
||||
) and
|
||||
not Language::hasPotentialLoop(f)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a `Phi` instruction is present in a block with fewer than two
|
||||
* predecessors.
|
||||
*/
|
||||
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
|
||||
count(instr.getBlock().getAPredecessor()) < 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if operand `operand` consumes a value that was defined in
|
||||
* a different function.
|
||||
*/
|
||||
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
|
||||
operand.getUse() = instr and
|
||||
operand.getAnyDef() = defInstr and
|
||||
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is not in exactly one block.
|
||||
*/
|
||||
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
|
||||
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||
b1.getASuccessor() = b2 and
|
||||
not b1.getBackEdgeSuccessor(_) = b2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` contains a loop in which no edge is a back edge.
|
||||
*
|
||||
* This check ensures we don't have too _few_ back edges.
|
||||
*/
|
||||
query predicate containsLoopOfForwardEdges(IRFunction f) {
|
||||
exists(IRBlock block |
|
||||
forwardEdge+(block, block) and
|
||||
block.getEnclosingIRFunction() = f
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `block` is reachable from its function entry point but would not
|
||||
* be reachable by traversing only forward edges. This check is skipped for
|
||||
* functions containing `goto` statements as the property does not generally
|
||||
* hold there.
|
||||
*
|
||||
* This check ensures we don't have too _many_ back edges.
|
||||
*/
|
||||
query predicate lostReachability(IRBlock block) {
|
||||
exists(IRFunction f, IRBlock entry |
|
||||
entry = f.getEntryBlock() and
|
||||
entry.getASuccessor+() = block and
|
||||
not forwardEdge+(entry, block) and
|
||||
not Language::hasGoto(f.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the number of back edges differs between the `Instruction` graph
|
||||
* and the `IRBlock` graph.
|
||||
*/
|
||||
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
|
||||
fromInstr =
|
||||
count(Instruction i1, Instruction i2 |
|
||||
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||
) and
|
||||
fromBlock =
|
||||
count(IRBlock b1, IRBlock b2 |
|
||||
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
|
||||
) and
|
||||
fromInstr != fromBlock
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the point in the function at which the specified operand is evaluated. For most operands,
|
||||
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
|
||||
* of evaluation is at the end of the corresponding predecessor block.
|
||||
*/
|
||||
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
|
||||
block = operand.(PhiInputOperand).getPredecessorBlock() and
|
||||
index = block.getInstructionCount()
|
||||
or
|
||||
exists(Instruction use |
|
||||
use = operand.(NonPhiOperand).getUse() and
|
||||
block.getInstruction(index) = use
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `useOperand` has a definition that does not dominate the use.
|
||||
*/
|
||||
query predicate useNotDominatedByDefinition(
|
||||
Operand useOperand, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
|
||||
not useOperand.getUse() instanceof UnmodeledUseInstruction and
|
||||
not defInstr instanceof UnmodeledDefinitionInstruction and
|
||||
pointOfEvaluation(useOperand, useBlock, useIndex) and
|
||||
defInstr = useOperand.getAnyDef() and
|
||||
(
|
||||
defInstr instanceof PhiInstruction and
|
||||
defBlock = defInstr.getBlock() and
|
||||
defIndex = -1
|
||||
or
|
||||
defBlock.getInstruction(defIndex) = defInstr
|
||||
) and
|
||||
not (
|
||||
defBlock.strictlyDominates(useBlock)
|
||||
or
|
||||
defBlock = useBlock and
|
||||
defIndex < useIndex
|
||||
) and
|
||||
message =
|
||||
"Operand '" + useOperand.toString() +
|
||||
"' is not dominated by its definition in function '$@'." and
|
||||
func = useOperand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
query predicate switchInstructionWithoutDefaultEdge(
|
||||
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(switchInstr.getDefaultSuccessor()) and
|
||||
message =
|
||||
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
|
||||
func = switchInstr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
|
||||
/**
|
||||
* A temporary variable introduced by IR construction. The most common examples are the variable
|
||||
* generated to hold the return value of afunction, or the variable generated to hold the result of
|
||||
* generated to hold the return value of a function, or the variable generated to hold the result of
|
||||
* a condition operator (`a ? b : c`).
|
||||
*/
|
||||
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
|
||||
@@ -10,274 +10,6 @@ import Imports::MemoryAccessKind
|
||||
import Imports::Opcode
|
||||
private import Imports::OperandTag
|
||||
|
||||
module InstructionSanity {
|
||||
/**
|
||||
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
|
||||
*/
|
||||
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
|
||||
exists(OperandTag tag |
|
||||
instr.getOpcode().hasOperand(tag) and
|
||||
not exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
message =
|
||||
"Instruction '" + instr.getOpcode().toString() +
|
||||
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
|
||||
*/
|
||||
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
|
||||
exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
not instr.getOpcode().hasOperand(tag) and
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
|
||||
not (
|
||||
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
|
||||
) and
|
||||
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(
|
||||
Instruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(OperandTag tag, int operandCount |
|
||||
operandCount =
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
operandCount > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag and
|
||||
message =
|
||||
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
|
||||
" in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
|
||||
* the predecessor block `pred`.
|
||||
*/
|
||||
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
not exists(PhiInputOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getPredecessorBlock() = pred
|
||||
)
|
||||
}
|
||||
|
||||
query predicate missingOperandType(Operand operand, string message) {
|
||||
exists(Language::Function func, Instruction use |
|
||||
not exists(operand.getType()) and
|
||||
use = operand.getUse() and
|
||||
func = use.getEnclosingFunction() and
|
||||
message =
|
||||
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
|
||||
"' missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
)
|
||||
}
|
||||
|
||||
query predicate duplicateChiOperand(
|
||||
ChiInstruction chi, string message, IRFunction func, string funcText
|
||||
) {
|
||||
chi.getTotal() = chi.getPartial() and
|
||||
message =
|
||||
"Chi instruction for " + chi.getPartial().toString() +
|
||||
" has duplicate operands in function $@" and
|
||||
func = chi.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
query predicate sideEffectWithoutPrimary(
|
||||
SideEffectInstruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(instr.getPrimaryInstruction()) and
|
||||
message = "Side effect instruction missing primary instruction in function $@" and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an instruction, other than `ExitFunction`, has no successors.
|
||||
*/
|
||||
query predicate instructionWithoutSuccessor(Instruction instr) {
|
||||
not exists(instr.getASuccessor()) and
|
||||
not instr instanceof ExitFunctionInstruction and
|
||||
// Phi instructions aren't linked into the instruction-level flow graph.
|
||||
not instr instanceof PhiInstruction and
|
||||
not instr instanceof UnreachedInstruction
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
|
||||
* where `target` is among the targets of those edges.
|
||||
*/
|
||||
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
|
||||
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
|
||||
n > 1 and
|
||||
source.getSuccessor(kind) = target
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
|
||||
* contains no element that can cause loops.
|
||||
*/
|
||||
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
|
||||
exists(IRBlock block |
|
||||
instr.getBlock() = block and
|
||||
block.getEnclosingFunction() = f and
|
||||
block.getASuccessor+() = block
|
||||
) and
|
||||
not Language::hasPotentialLoop(f)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a `Phi` instruction is present in a block with fewer than two
|
||||
* predecessors.
|
||||
*/
|
||||
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
|
||||
count(instr.getBlock().getAPredecessor()) < 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if operand `operand` consumes a value that was defined in
|
||||
* a different function.
|
||||
*/
|
||||
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
|
||||
operand.getUse() = instr and
|
||||
operand.getAnyDef() = defInstr and
|
||||
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is not in exactly one block.
|
||||
*/
|
||||
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
|
||||
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||
b1.getASuccessor() = b2 and
|
||||
not b1.getBackEdgeSuccessor(_) = b2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` contains a loop in which no edge is a back edge.
|
||||
*
|
||||
* This check ensures we don't have too _few_ back edges.
|
||||
*/
|
||||
query predicate containsLoopOfForwardEdges(IRFunction f) {
|
||||
exists(IRBlock block |
|
||||
forwardEdge+(block, block) and
|
||||
block.getEnclosingIRFunction() = f
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `block` is reachable from its function entry point but would not
|
||||
* be reachable by traversing only forward edges. This check is skipped for
|
||||
* functions containing `goto` statements as the property does not generally
|
||||
* hold there.
|
||||
*
|
||||
* This check ensures we don't have too _many_ back edges.
|
||||
*/
|
||||
query predicate lostReachability(IRBlock block) {
|
||||
exists(IRFunction f, IRBlock entry |
|
||||
entry = f.getEntryBlock() and
|
||||
entry.getASuccessor+() = block and
|
||||
not forwardEdge+(entry, block) and
|
||||
not Language::hasGoto(f.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the number of back edges differs between the `Instruction` graph
|
||||
* and the `IRBlock` graph.
|
||||
*/
|
||||
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
|
||||
fromInstr =
|
||||
count(Instruction i1, Instruction i2 |
|
||||
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||
) and
|
||||
fromBlock =
|
||||
count(IRBlock b1, IRBlock b2 |
|
||||
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
|
||||
) and
|
||||
fromInstr != fromBlock
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the point in the function at which the specified operand is evaluated. For most operands,
|
||||
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
|
||||
* of evaluation is at the end of the corresponding predecessor block.
|
||||
*/
|
||||
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
|
||||
block = operand.(PhiInputOperand).getPredecessorBlock() and
|
||||
index = block.getInstructionCount()
|
||||
or
|
||||
exists(Instruction use |
|
||||
use = operand.(NonPhiOperand).getUse() and
|
||||
block.getInstruction(index) = use
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `useOperand` has a definition that does not dominate the use.
|
||||
*/
|
||||
query predicate useNotDominatedByDefinition(
|
||||
Operand useOperand, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
|
||||
not useOperand.getUse() instanceof UnmodeledUseInstruction and
|
||||
not defInstr instanceof UnmodeledDefinitionInstruction and
|
||||
pointOfEvaluation(useOperand, useBlock, useIndex) and
|
||||
defInstr = useOperand.getAnyDef() and
|
||||
(
|
||||
defInstr instanceof PhiInstruction and
|
||||
defBlock = defInstr.getBlock() and
|
||||
defIndex = -1
|
||||
or
|
||||
defBlock.getInstruction(defIndex) = defInstr
|
||||
) and
|
||||
not (
|
||||
defBlock.strictlyDominates(useBlock)
|
||||
or
|
||||
defBlock = useBlock and
|
||||
defIndex < useIndex
|
||||
) and
|
||||
message =
|
||||
"Operand '" + useOperand.toString() +
|
||||
"' is not dominated by its definition in function '$@'." and
|
||||
func = useOperand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
query predicate switchInstructionWithoutDefaultEdge(
|
||||
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(switchInstr.getDefaultSuccessor()) and
|
||||
message =
|
||||
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
|
||||
func = switchInstr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified
|
||||
* `File` and line number. Used for assigning register names when printing IR.
|
||||
@@ -1204,6 +936,11 @@ class CallInstruction extends Instruction {
|
||||
final Instruction getPositionalArgument(int index) {
|
||||
result = getPositionalArgumentOperand(index).getDef()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of arguments of the call, including the `this` pointer, if any.
|
||||
*/
|
||||
final int getNumberOfArguments() { result = count(this.getAnArgumentOperand()) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1352,6 +1089,26 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
|
||||
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the initial value of newly allocated memory, e.g. the result of a
|
||||
* call to `malloc`.
|
||||
*/
|
||||
class InitializeDynamicAllocationInstruction extends SideEffectInstruction {
|
||||
InitializeDynamicAllocationInstruction() {
|
||||
getOpcode() instanceof Opcode::InitializeDynamicAllocation
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the address of the allocation this instruction is initializing.
|
||||
*/
|
||||
final AddressOperand getAllocationAddressOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the operand for the allocation this instruction is initializing.
|
||||
*/
|
||||
final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a GNU or MSVC inline assembly statement.
|
||||
*/
|
||||
|
||||
@@ -665,17 +665,18 @@ module DefUse {
|
||||
private predicate definitionReachesRank(
|
||||
Alias::MemoryLocation useLocation, OldBlock block, int defRank, int reachesRank
|
||||
) {
|
||||
// The def always reaches the next use, even if there is also a def on the
|
||||
// use instruction.
|
||||
hasDefinitionAtRank(useLocation, _, block, defRank, _) and
|
||||
reachesRank <= exitRank(useLocation, block) and // Without this, the predicate would be infinite.
|
||||
(
|
||||
// The def always reaches the next use, even if there is also a def on the
|
||||
// use instruction.
|
||||
reachesRank = defRank + 1
|
||||
or
|
||||
// If the def reached the previous rank, it also reaches the current rank,
|
||||
// unless there was another def at the previous rank.
|
||||
definitionReachesRank(useLocation, block, defRank, reachesRank - 1) and
|
||||
not hasDefinitionAtRank(useLocation, _, block, reachesRank - 1, _)
|
||||
reachesRank = defRank + 1
|
||||
or
|
||||
// If the def reached the previous rank, it also reaches the current rank,
|
||||
// unless there was another def at the previous rank.
|
||||
exists(int prevRank |
|
||||
reachesRank = prevRank + 1 and
|
||||
definitionReachesRank(useLocation, block, defRank, prevRank) and
|
||||
not prevRank = exitRank(useLocation, block) and
|
||||
not hasDefinitionAtRank(useLocation, _, block, prevRank, _)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ private import semmle.code.cpp.ir.IR
|
||||
* methods.
|
||||
*/
|
||||
class GVN extends TValueNumber {
|
||||
pragma[noinline]
|
||||
GVN() {
|
||||
exists(Instruction instr |
|
||||
this = tvalueNumber(instr) and exists(instr.getUnconvertedResultExpression())
|
||||
|
||||
@@ -91,13 +91,30 @@ private float wideningUpperBounds(ArithmeticType t) {
|
||||
result = 1.0 / 0.0 // +Inf
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the expression `e`, if it is a constant.
|
||||
* This predicate also handles the case of constant variables initialized in compilation units,
|
||||
* which doesn't necessarily have a getValue() result from the extractor.
|
||||
*/
|
||||
private string getValue(Expr e) {
|
||||
if exists(e.getValue())
|
||||
then result = e.getValue()
|
||||
else
|
||||
exists(VariableAccess access, Variable v |
|
||||
e = access and
|
||||
v = access.getTarget() and
|
||||
v.getUnderlyingType().isConst() and
|
||||
result = getValue(v.getAnAssignedValue())
|
||||
)
|
||||
}
|
||||
|
||||
/** Set of expressions which we know how to analyze. */
|
||||
private predicate analyzableExpr(Expr e) {
|
||||
// The type of the expression must be arithmetic. We reuse the logic in
|
||||
// `exprMinVal` to check this.
|
||||
exists(exprMinVal(e)) and
|
||||
(
|
||||
exists(e.getValue().toFloat()) or
|
||||
exists(getValue(e).toFloat()) or
|
||||
e instanceof UnaryPlusExpr or
|
||||
e instanceof UnaryMinusExpr or
|
||||
e instanceof MinExpr or
|
||||
@@ -365,8 +382,8 @@ private float getTruncatedLowerBounds(Expr expr) {
|
||||
then
|
||||
// If the expression evaluates to a constant, then there is no
|
||||
// need to call getLowerBoundsImpl.
|
||||
if exists(expr.getValue().toFloat())
|
||||
then result = expr.getValue().toFloat()
|
||||
if exists(getValue(expr).toFloat())
|
||||
then result = getValue(expr).toFloat()
|
||||
else (
|
||||
// Some of the bounds computed by getLowerBoundsImpl might
|
||||
// overflow, so we replace invalid bounds with exprMinVal.
|
||||
@@ -418,8 +435,8 @@ private float getTruncatedUpperBounds(Expr expr) {
|
||||
then
|
||||
// If the expression evaluates to a constant, then there is no
|
||||
// need to call getUpperBoundsImpl.
|
||||
if exists(expr.getValue().toFloat())
|
||||
then result = expr.getValue().toFloat()
|
||||
if exists(getValue(expr).toFloat())
|
||||
then result = getValue(expr).toFloat()
|
||||
else (
|
||||
// Some of the bounds computed by `getUpperBoundsImpl`
|
||||
// might overflow, so we replace invalid bounds with
|
||||
|
||||
@@ -13,19 +13,36 @@ predicate guardedAbs(Operation e, Expr use) {
|
||||
)
|
||||
}
|
||||
|
||||
/** This is `BasicBlock.getNode`, restricted to `Stmt` for performance. */
|
||||
pragma[noinline]
|
||||
private int getStmtIndexInBlock(BasicBlock block, Stmt stmt) { block.getNode(result) = stmt }
|
||||
|
||||
pragma[inline]
|
||||
private predicate stmtDominates(Stmt dominator, Stmt dominated) {
|
||||
// In same block
|
||||
exists(BasicBlock block, int dominatorIndex, int dominatedIndex |
|
||||
dominatorIndex = getStmtIndexInBlock(block, dominator) and
|
||||
dominatedIndex = getStmtIndexInBlock(block, dominated) and
|
||||
dominatedIndex >= dominatorIndex
|
||||
)
|
||||
or
|
||||
// In (possibly) different blocks
|
||||
bbStrictlyDominates(dominator.getBasicBlock(), dominated.getBasicBlock())
|
||||
}
|
||||
|
||||
/** is the size of this use guarded to be less than something? */
|
||||
pragma[nomagic]
|
||||
predicate guardedLesser(Operation e, Expr use) {
|
||||
exists(IfStmt c, RelationalOperation guard |
|
||||
use = guard.getLesserOperand().getAChild*() and
|
||||
guard = c.getControllingExpr().getAChild*() and
|
||||
iDominates*(c.getThen(), e.getEnclosingStmt())
|
||||
stmtDominates(c.getThen(), e.getEnclosingStmt())
|
||||
)
|
||||
or
|
||||
exists(Loop c, RelationalOperation guard |
|
||||
use = guard.getLesserOperand().getAChild*() and
|
||||
guard = c.getControllingExpr().getAChild*() and
|
||||
iDominates*(c.getStmt(), e.getEnclosingStmt())
|
||||
stmtDominates(c.getStmt(), e.getEnclosingStmt())
|
||||
)
|
||||
or
|
||||
exists(ConditionalExpr c, RelationalOperation guard |
|
||||
@@ -43,13 +60,13 @@ predicate guardedGreater(Operation e, Expr use) {
|
||||
exists(IfStmt c, RelationalOperation guard |
|
||||
use = guard.getGreaterOperand().getAChild*() and
|
||||
guard = c.getControllingExpr().getAChild*() and
|
||||
iDominates*(c.getThen(), e.getEnclosingStmt())
|
||||
stmtDominates(c.getThen(), e.getEnclosingStmt())
|
||||
)
|
||||
or
|
||||
exists(Loop c, RelationalOperation guard |
|
||||
use = guard.getGreaterOperand().getAChild*() and
|
||||
guard = c.getControllingExpr().getAChild*() and
|
||||
iDominates*(c.getStmt(), e.getEnclosingStmt())
|
||||
stmtDominates(c.getStmt(), e.getEnclosingStmt())
|
||||
)
|
||||
or
|
||||
exists(ConditionalExpr c, RelationalOperation guard |
|
||||
|
||||
@@ -1604,30 +1604,18 @@ class EnumSwitch extends SwitchStmt {
|
||||
* ```
|
||||
* there are results `GREEN` and `BLUE`.
|
||||
*/
|
||||
pragma[noopt]
|
||||
EnumConstant getAMissingCase() {
|
||||
exists(Enum et |
|
||||
exists(Expr e, Type t |
|
||||
e = this.getExpr() and
|
||||
this instanceof EnumSwitch and
|
||||
t = e.getType() and
|
||||
et = t.getUnderlyingType()
|
||||
) and
|
||||
et = this.getExpr().getUnderlyingType() and
|
||||
result = et.getAnEnumConstant() and
|
||||
not exists(string value |
|
||||
exists(SwitchCase sc, Expr e |
|
||||
sc = this.getASwitchCase() and
|
||||
e = sc.getExpr() and
|
||||
value = e.getValue()
|
||||
) and
|
||||
exists(Initializer init, Expr e |
|
||||
init = result.getInitializer() and
|
||||
e = init.getExpr() and
|
||||
e.getValue() = value
|
||||
)
|
||||
)
|
||||
not this.matchesValue(result.getInitializer().getExpr().getValue())
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate matchesValue(string value) {
|
||||
value = this.getASwitchCase().getExpr().getValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
1
cpp/ql/test/experimental/README.md
Normal file
1
cpp/ql/test/experimental/README.md
Normal file
@@ -0,0 +1 @@
|
||||
This directory contains tests for [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.
|
||||
@@ -52,3 +52,18 @@
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:15:75:18 | call to atoi | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:25 | call to getenv | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:45 | (const char *)... | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:8:24:8:25 | s1 | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:11:20:11:21 | s1 | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:11:36:11:37 | s2 | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:17:83:24 | userName | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:28:83:33 | call to getenv | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:28:83:46 | (const char *)... | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:85:8:85:11 | copy | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:2:86:7 | call to strcpy | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:9:86:12 | copy | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:15:86:22 | userName | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:6:88:27 | ! ... | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:7:88:12 | call to strcmp | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:7:88:27 | (bool)... | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | (const char *)... | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | copy | |
|
||||
|
||||
@@ -8,3 +8,6 @@
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:69:10:69:13 | copy | AST only |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:12:70:15 | copy | AST only |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:71:12:71:15 | copy | AST only |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:11:20:11:21 | s1 | AST only |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:85:8:85:11 | copy | AST only |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:9:86:12 | copy | AST only |
|
||||
|
||||
@@ -40,3 +40,15 @@
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:15:75:18 | call to atoi | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:25 | call to getenv | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:45 | (const char *)... | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:8:24:8:25 | s1 | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:11:36:11:37 | s2 | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:17:83:24 | userName | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:28:83:33 | call to getenv | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:28:83:46 | (const char *)... | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:2:86:7 | call to strcpy | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:15:86:22 | userName | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:6:88:27 | ! ... | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:7:88:12 | call to strcmp | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:7:88:27 | (bool)... | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | (const char *)... | |
|
||||
| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | copy | |
|
||||
|
||||
@@ -76,3 +76,16 @@ void guard() {
|
||||
if (len > 1000) return;
|
||||
char **node = (char **) malloc(len * sizeof(char *));
|
||||
}
|
||||
|
||||
const char *alias_global;
|
||||
|
||||
void mallocBuffer() {
|
||||
const char *userName = getenv("USER_NAME");
|
||||
char *alias = (char*)malloc(4096);
|
||||
char *copy = (char*)malloc(4096);
|
||||
strcpy(copy, userName);
|
||||
alias_global = alias; // to force a Chi node on all aliased memory
|
||||
if (!strcmp(copy, "admin")) { // copy should be tainted
|
||||
isAdmin = true;
|
||||
}
|
||||
}
|
||||
@@ -27,3 +27,5 @@
|
||||
| declarationEntry.cpp:31:4:31:19 | myMemberVariable | declarationEntry.cpp:31:4:31:19 | definition of myMemberVariable | 1 | 1 |
|
||||
| declarationEntry.cpp:34:22:34:28 | mtc_int | declarationEntry.cpp:34:22:34:28 | definition of mtc_int | 1 | 1 |
|
||||
| declarationEntry.cpp:35:24:35:32 | mtc_short | declarationEntry.cpp:35:24:35:32 | definition of mtc_short | 1 | 1 |
|
||||
| macro.c:2:1:2:3 | foo | macro.c:2:1:2:3 | declaration of foo | 1 | 1 |
|
||||
| macro.c:4:5:4:8 | main | macro.c:4:5:4:8 | definition of main | 1 | 1 |
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
| declarationEntry.c:2:6:2:20 | declaration of myFirstFunction | |
|
||||
| declarationEntry.c:4:6:4:21 | definition of mySecondFunction | |
|
||||
| declarationEntry.c:8:6:8:20 | definition of myThirdFunction | |
|
||||
| declarationEntry.c:13:2:13:2 | declaration of myFourthFunction | isImplicit |
|
||||
| declarationEntry.c:14:2:14:2 | declaration of myFifthFunction | isImplicit |
|
||||
| declarationEntry.c:17:6:17:21 | declaration of myFourthFunction | |
|
||||
| declarationEntry.cpp:9:6:9:15 | declaration of myFunction | |
|
||||
| declarationEntry.cpp:11:6:11:15 | definition of myFunction | |
|
||||
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | |
|
||||
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | |
|
||||
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | |
|
||||
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | |
|
||||
| declarationEntry.c:2:6:2:20 | declaration of myFirstFunction | | 1 | c_linkage |
|
||||
| declarationEntry.c:4:6:4:21 | definition of mySecondFunction | | 1 | c_linkage |
|
||||
| declarationEntry.c:8:6:8:20 | definition of myThirdFunction | | 1 | c_linkage |
|
||||
| declarationEntry.c:13:2:13:2 | declaration of myFourthFunction | isImplicit | 1 | c_linkage |
|
||||
| declarationEntry.c:14:2:14:2 | declaration of myFifthFunction | isImplicit | 1 | c_linkage |
|
||||
| declarationEntry.c:17:6:17:21 | declaration of myFourthFunction | | 1 | c_linkage |
|
||||
| declarationEntry.cpp:9:6:9:15 | declaration of myFunction | | 0 | |
|
||||
| declarationEntry.cpp:11:6:11:15 | definition of myFunction | | 0 | |
|
||||
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | | 0 | |
|
||||
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | | 0 | |
|
||||
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | | 0 | |
|
||||
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | | 0 | |
|
||||
| macro.c:2:1:2:3 | declaration of foo | | 2 | c_linkage, static |
|
||||
| macro.c:4:5:4:8 | definition of main | | 1 | c_linkage |
|
||||
|
||||
@@ -2,4 +2,4 @@ import cpp
|
||||
|
||||
from FunctionDeclarationEntry fde, string imp
|
||||
where if fde.isImplicit() then imp = "isImplicit" else imp = ""
|
||||
select fde, imp
|
||||
select fde, imp, count(fde.getASpecifier()), concat(fde.getASpecifier().toString(), ", ")
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#define Foo static void foo()
|
||||
Foo;
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -1238,3 +1238,47 @@ ssa.cpp:
|
||||
# 254| v254_10(void) = UnmodeledUse : mu*
|
||||
# 254| v254_11(void) = AliasedUse : ~m262_1
|
||||
# 254| v254_12(void) = ExitFunction :
|
||||
|
||||
# 268| void* MallocAliasing(void*, int)
|
||||
# 268| Block 0
|
||||
# 268| v268_1(void) = EnterFunction :
|
||||
# 268| m268_2(unknown) = AliasedDefinition :
|
||||
# 268| m268_3(unknown) = InitializeNonLocal :
|
||||
# 268| m268_4(unknown) = Chi : total:m268_2, partial:m268_3
|
||||
# 268| mu268_5(unknown) = UnmodeledDefinition :
|
||||
# 268| r268_6(glval<void *>) = VariableAddress[s] :
|
||||
# 268| m268_7(void *) = InitializeParameter[s] : &:r268_6
|
||||
# 268| r268_8(void *) = Load : &:r268_6, m268_7
|
||||
# 268| m268_9(unknown) = InitializeIndirection[s] : &:r268_8
|
||||
# 268| r268_10(glval<int>) = VariableAddress[size] :
|
||||
# 268| m268_11(int) = InitializeParameter[size] : &:r268_10
|
||||
# 269| r269_1(glval<void *>) = VariableAddress[buf] :
|
||||
# 269| r269_2(glval<unknown>) = FunctionAddress[malloc] :
|
||||
# 269| r269_3(glval<int>) = VariableAddress[size] :
|
||||
# 269| r269_4(int) = Load : &:r269_3, m268_11
|
||||
# 269| r269_5(void *) = Call : func:r269_2, 0:r269_4
|
||||
# 269| m269_6(unknown) = ^CallSideEffect : ~m268_9
|
||||
# 269| m269_7(unknown) = Chi : total:m268_9, partial:m269_6
|
||||
# 269| m269_8(unknown) = ^InitializeDynamicAllocation : &:r269_5
|
||||
# 269| m269_9(void *) = Store : &:r269_1, r269_5
|
||||
# 270| r270_1(glval<unknown>) = FunctionAddress[memcpy] :
|
||||
# 270| r270_2(glval<void *>) = VariableAddress[buf] :
|
||||
# 270| r270_3(void *) = Load : &:r270_2, m269_9
|
||||
# 270| r270_4(glval<void *>) = VariableAddress[s] :
|
||||
# 270| r270_5(void *) = Load : &:r270_4, m268_7
|
||||
# 270| r270_6(glval<int>) = VariableAddress[size] :
|
||||
# 270| r270_7(int) = Load : &:r270_6, m268_11
|
||||
# 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7
|
||||
# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m269_8
|
||||
# 270| m270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7
|
||||
# 270| m270_11(unknown) = Chi : total:m269_8, partial:m270_10
|
||||
# 271| r271_1(glval<void *>) = VariableAddress[#return] :
|
||||
# 271| r271_2(glval<void *>) = VariableAddress[buf] :
|
||||
# 271| r271_3(void *) = Load : &:r271_2, m269_9
|
||||
# 271| m271_4(void *) = Store : &:r271_1, r271_3
|
||||
# 268| v268_12(void) = ReturnIndirection : &:r268_8, ~m270_11
|
||||
# 268| r268_13(glval<void *>) = VariableAddress[#return] :
|
||||
# 268| v268_14(void) = ReturnValue : &:r268_13, m271_4
|
||||
# 268| v268_15(void) = UnmodeledUse : mu*
|
||||
# 268| v268_16(void) = AliasedUse : ~m270_11
|
||||
# 268| v268_17(void) = ExitFunction :
|
||||
|
||||
@@ -1233,3 +1233,47 @@ ssa.cpp:
|
||||
# 254| v254_10(void) = UnmodeledUse : mu*
|
||||
# 254| v254_11(void) = AliasedUse : ~m262_1
|
||||
# 254| v254_12(void) = ExitFunction :
|
||||
|
||||
# 268| void* MallocAliasing(void*, int)
|
||||
# 268| Block 0
|
||||
# 268| v268_1(void) = EnterFunction :
|
||||
# 268| m268_2(unknown) = AliasedDefinition :
|
||||
# 268| m268_3(unknown) = InitializeNonLocal :
|
||||
# 268| m268_4(unknown) = Chi : total:m268_2, partial:m268_3
|
||||
# 268| mu268_5(unknown) = UnmodeledDefinition :
|
||||
# 268| r268_6(glval<void *>) = VariableAddress[s] :
|
||||
# 268| m268_7(void *) = InitializeParameter[s] : &:r268_6
|
||||
# 268| r268_8(void *) = Load : &:r268_6, m268_7
|
||||
# 268| m268_9(unknown) = InitializeIndirection[s] : &:r268_8
|
||||
# 268| r268_10(glval<int>) = VariableAddress[size] :
|
||||
# 268| m268_11(int) = InitializeParameter[size] : &:r268_10
|
||||
# 269| r269_1(glval<void *>) = VariableAddress[buf] :
|
||||
# 269| r269_2(glval<unknown>) = FunctionAddress[malloc] :
|
||||
# 269| r269_3(glval<int>) = VariableAddress[size] :
|
||||
# 269| r269_4(int) = Load : &:r269_3, m268_11
|
||||
# 269| r269_5(void *) = Call : func:r269_2, 0:r269_4
|
||||
# 269| m269_6(unknown) = ^CallSideEffect : ~m268_4
|
||||
# 269| m269_7(unknown) = Chi : total:m268_4, partial:m269_6
|
||||
# 269| m269_8(unknown) = ^InitializeDynamicAllocation : &:r269_5
|
||||
# 269| m269_9(void *) = Store : &:r269_1, r269_5
|
||||
# 270| r270_1(glval<unknown>) = FunctionAddress[memcpy] :
|
||||
# 270| r270_2(glval<void *>) = VariableAddress[buf] :
|
||||
# 270| r270_3(void *) = Load : &:r270_2, m269_9
|
||||
# 270| r270_4(glval<void *>) = VariableAddress[s] :
|
||||
# 270| r270_5(void *) = Load : &:r270_4, m268_7
|
||||
# 270| r270_6(glval<int>) = VariableAddress[size] :
|
||||
# 270| r270_7(int) = Load : &:r270_6, m268_11
|
||||
# 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7
|
||||
# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m268_9
|
||||
# 270| m270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7
|
||||
# 270| m270_11(unknown) = Chi : total:m269_8, partial:m270_10
|
||||
# 271| r271_1(glval<void *>) = VariableAddress[#return] :
|
||||
# 271| r271_2(glval<void *>) = VariableAddress[buf] :
|
||||
# 271| r271_3(void *) = Load : &:r271_2, m269_9
|
||||
# 271| m271_4(void *) = Store : &:r271_1, r271_3
|
||||
# 268| v268_12(void) = ReturnIndirection : &:r268_8, m268_9
|
||||
# 268| r268_13(glval<void *>) = VariableAddress[#return] :
|
||||
# 268| v268_14(void) = ReturnValue : &:r268_13, m271_4
|
||||
# 268| v268_15(void) = UnmodeledUse : mu*
|
||||
# 268| v268_16(void) = AliasedUse : ~m269_7
|
||||
# 268| v268_17(void) = ExitFunction :
|
||||
|
||||
@@ -262,3 +262,11 @@ char StringLiteralAliasing2(bool b) {
|
||||
const char* s = "Literal";
|
||||
return s[2];
|
||||
}
|
||||
|
||||
void *malloc(int size);
|
||||
|
||||
void *MallocAliasing(void *s, int size) {
|
||||
void *buf = malloc(size);
|
||||
memcpy(buf, s, size);
|
||||
return buf;
|
||||
}
|
||||
@@ -1147,3 +1147,44 @@ ssa.cpp:
|
||||
# 254| v254_9(void) = UnmodeledUse : mu*
|
||||
# 254| v254_10(void) = AliasedUse : ~mu254_4
|
||||
# 254| v254_11(void) = ExitFunction :
|
||||
|
||||
# 268| void* MallocAliasing(void*, int)
|
||||
# 268| Block 0
|
||||
# 268| v268_1(void) = EnterFunction :
|
||||
# 268| mu268_2(unknown) = AliasedDefinition :
|
||||
# 268| mu268_3(unknown) = InitializeNonLocal :
|
||||
# 268| mu268_4(unknown) = UnmodeledDefinition :
|
||||
# 268| r268_5(glval<void *>) = VariableAddress[s] :
|
||||
# 268| m268_6(void *) = InitializeParameter[s] : &:r268_5
|
||||
# 268| r268_7(void *) = Load : &:r268_5, m268_6
|
||||
# 268| mu268_8(unknown) = InitializeIndirection[s] : &:r268_7
|
||||
# 268| r268_9(glval<int>) = VariableAddress[size] :
|
||||
# 268| m268_10(int) = InitializeParameter[size] : &:r268_9
|
||||
# 269| r269_1(glval<void *>) = VariableAddress[buf] :
|
||||
# 269| r269_2(glval<unknown>) = FunctionAddress[malloc] :
|
||||
# 269| r269_3(glval<int>) = VariableAddress[size] :
|
||||
# 269| r269_4(int) = Load : &:r269_3, m268_10
|
||||
# 269| r269_5(void *) = Call : func:r269_2, 0:r269_4
|
||||
# 269| mu269_6(unknown) = ^CallSideEffect : ~mu268_4
|
||||
# 269| mu269_7(unknown) = ^InitializeDynamicAllocation : &:r269_5
|
||||
# 269| m269_8(void *) = Store : &:r269_1, r269_5
|
||||
# 270| r270_1(glval<unknown>) = FunctionAddress[memcpy] :
|
||||
# 270| r270_2(glval<void *>) = VariableAddress[buf] :
|
||||
# 270| r270_3(void *) = Load : &:r270_2, m269_8
|
||||
# 270| r270_4(glval<void *>) = VariableAddress[s] :
|
||||
# 270| r270_5(void *) = Load : &:r270_4, m268_6
|
||||
# 270| r270_6(glval<int>) = VariableAddress[size] :
|
||||
# 270| r270_7(int) = Load : &:r270_6, m268_10
|
||||
# 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7
|
||||
# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~mu268_4
|
||||
# 270| mu270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7
|
||||
# 271| r271_1(glval<void *>) = VariableAddress[#return] :
|
||||
# 271| r271_2(glval<void *>) = VariableAddress[buf] :
|
||||
# 271| r271_3(void *) = Load : &:r271_2, m269_8
|
||||
# 271| m271_4(void *) = Store : &:r271_1, r271_3
|
||||
# 268| v268_11(void) = ReturnIndirection : &:r268_7, ~mu268_4
|
||||
# 268| r268_12(glval<void *>) = VariableAddress[#return] :
|
||||
# 268| v268_13(void) = ReturnValue : &:r268_12, m271_4
|
||||
# 268| v268_14(void) = UnmodeledUse : mu*
|
||||
# 268| v268_15(void) = AliasedUse : ~mu268_4
|
||||
# 268| v268_16(void) = ExitFunction :
|
||||
|
||||
@@ -1147,3 +1147,44 @@ ssa.cpp:
|
||||
# 254| v254_9(void) = UnmodeledUse : mu*
|
||||
# 254| v254_10(void) = AliasedUse : ~mu254_4
|
||||
# 254| v254_11(void) = ExitFunction :
|
||||
|
||||
# 268| void* MallocAliasing(void*, int)
|
||||
# 268| Block 0
|
||||
# 268| v268_1(void) = EnterFunction :
|
||||
# 268| mu268_2(unknown) = AliasedDefinition :
|
||||
# 268| mu268_3(unknown) = InitializeNonLocal :
|
||||
# 268| mu268_4(unknown) = UnmodeledDefinition :
|
||||
# 268| r268_5(glval<void *>) = VariableAddress[s] :
|
||||
# 268| m268_6(void *) = InitializeParameter[s] : &:r268_5
|
||||
# 268| r268_7(void *) = Load : &:r268_5, m268_6
|
||||
# 268| mu268_8(unknown) = InitializeIndirection[s] : &:r268_7
|
||||
# 268| r268_9(glval<int>) = VariableAddress[size] :
|
||||
# 268| m268_10(int) = InitializeParameter[size] : &:r268_9
|
||||
# 269| r269_1(glval<void *>) = VariableAddress[buf] :
|
||||
# 269| r269_2(glval<unknown>) = FunctionAddress[malloc] :
|
||||
# 269| r269_3(glval<int>) = VariableAddress[size] :
|
||||
# 269| r269_4(int) = Load : &:r269_3, m268_10
|
||||
# 269| r269_5(void *) = Call : func:r269_2, 0:r269_4
|
||||
# 269| mu269_6(unknown) = ^CallSideEffect : ~mu268_4
|
||||
# 269| mu269_7(unknown) = ^InitializeDynamicAllocation : &:r269_5
|
||||
# 269| m269_8(void *) = Store : &:r269_1, r269_5
|
||||
# 270| r270_1(glval<unknown>) = FunctionAddress[memcpy] :
|
||||
# 270| r270_2(glval<void *>) = VariableAddress[buf] :
|
||||
# 270| r270_3(void *) = Load : &:r270_2, m269_8
|
||||
# 270| r270_4(glval<void *>) = VariableAddress[s] :
|
||||
# 270| r270_5(void *) = Load : &:r270_4, m268_6
|
||||
# 270| r270_6(glval<int>) = VariableAddress[size] :
|
||||
# 270| r270_7(int) = Load : &:r270_6, m268_10
|
||||
# 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7
|
||||
# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~mu268_4
|
||||
# 270| mu270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7
|
||||
# 271| r271_1(glval<void *>) = VariableAddress[#return] :
|
||||
# 271| r271_2(glval<void *>) = VariableAddress[buf] :
|
||||
# 271| r271_3(void *) = Load : &:r271_2, m269_8
|
||||
# 271| m271_4(void *) = Store : &:r271_1, r271_3
|
||||
# 268| v268_11(void) = ReturnIndirection : &:r268_7, ~mu268_4
|
||||
# 268| r268_12(glval<void *>) = VariableAddress[#return] :
|
||||
# 268| v268_13(void) = ReturnValue : &:r268_12, m271_4
|
||||
# 268| v268_14(void) = UnmodeledUse : mu*
|
||||
# 268| v268_15(void) = AliasedUse : ~mu268_4
|
||||
# 268| v268_16(void) = ExitFunction :
|
||||
|
||||
@@ -213,11 +213,9 @@
|
||||
| file://:0:0:0:0 | const lambda [] type at line 3, col. 5 |
|
||||
| file://:0:0:0:0 | const lambda [] type at line 3, col. 5 & |
|
||||
| file://:0:0:0:0 | const lambda [] type at line 3, col. 5 * |
|
||||
| file://:0:0:0:0 | const lambda [] type at line 3, col. 5 *const |
|
||||
| file://:0:0:0:0 | const lambda [] type at line 9, col. 5 |
|
||||
| file://:0:0:0:0 | const lambda [] type at line 9, col. 5 & |
|
||||
| file://:0:0:0:0 | const lambda [] type at line 9, col. 5 * |
|
||||
| file://:0:0:0:0 | const lambda [] type at line 9, col. 5 *const |
|
||||
| file://:0:0:0:0 | const lambda [] type at line 9, col. 15 |
|
||||
| file://:0:0:0:0 | const lambda [] type at line 9, col. 15 & |
|
||||
| file://:0:0:0:0 | const lambda [] type at line 15, col. 5 |
|
||||
@@ -225,7 +223,6 @@
|
||||
| file://:0:0:0:0 | const lambda [] type at line 22, col. 19 |
|
||||
| file://:0:0:0:0 | const lambda [] type at line 22, col. 19 & |
|
||||
| file://:0:0:0:0 | const lambda [] type at line 22, col. 19 * |
|
||||
| file://:0:0:0:0 | const lambda [] type at line 22, col. 19 *const |
|
||||
| file://:0:0:0:0 | declaration of 1st parameter |
|
||||
| file://:0:0:0:0 | declaration of 1st parameter |
|
||||
| file://:0:0:0:0 | declaration of 1st parameter |
|
||||
|
||||
@@ -39,17 +39,13 @@
|
||||
| file://:0:0:0:0 | __va_list_tag && |
|
||||
| file://:0:0:0:0 | abstract |
|
||||
| file://:0:0:0:0 | action<ActionT> * |
|
||||
| file://:0:0:0:0 | action<ActionT> *const |
|
||||
| file://:0:0:0:0 | action<actor1<composite<int>>> & |
|
||||
| file://:0:0:0:0 | action<actor1<composite<int>>> && |
|
||||
| file://:0:0:0:0 | action<actor1<composite<int>>> * |
|
||||
| file://:0:0:0:0 | action<actor1<composite<int>>> *const |
|
||||
| file://:0:0:0:0 | actor1<BaseT> * |
|
||||
| file://:0:0:0:0 | actor1<BaseT> *const |
|
||||
| file://:0:0:0:0 | actor1<composite<int>> & |
|
||||
| file://:0:0:0:0 | actor1<composite<int>> && |
|
||||
| file://:0:0:0:0 | actor1<composite<int>> * |
|
||||
| file://:0:0:0:0 | actor1<composite<int>> *const |
|
||||
| file://:0:0:0:0 | atomic |
|
||||
| file://:0:0:0:0 | auto |
|
||||
| file://:0:0:0:0 | auto |
|
||||
|
||||
@@ -6,3 +6,4 @@
|
||||
| test.cpp:49:17:49:30 | new[] | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:52:21:52:27 | call to realloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:52:35:52:60 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:127:17:127:22 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:123:25:123:30 | call to getenv | user input (getenv) |
|
||||
|
||||
@@ -105,3 +105,24 @@ void processFile()
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
char *getenv(const char *name);
|
||||
|
||||
#define MAX_SIZE 500
|
||||
|
||||
int bounded(int x, int limit) {
|
||||
int result = x;
|
||||
if (x <= 0)
|
||||
result = 1;
|
||||
else if (x > limit)
|
||||
result = limit;
|
||||
return result;
|
||||
}
|
||||
|
||||
void open_file_bounded () {
|
||||
int size = size = atoi(getenv("USER"));
|
||||
int bounded_size = bounded(size, MAX_SIZE);
|
||||
|
||||
int* a = (int*)malloc(bounded_size); // GOOD
|
||||
int* b = (int*)malloc(size); // BAD
|
||||
}
|
||||
@@ -69,3 +69,10 @@ void test10(int x) {
|
||||
} while (0);
|
||||
}
|
||||
}
|
||||
|
||||
extern const int const256;
|
||||
|
||||
void test11() {
|
||||
short s;
|
||||
for(s = 0; s < const256; ++s) {}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
const int const256 = 256;
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
@@ -13,16 +14,12 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteSubId(ContainingType);
|
||||
trapFile.Write(".");
|
||||
trapFile.WriteSubId(Location);
|
||||
if (symbol.IsGenericMethod && !IsSourceDeclaration)
|
||||
{
|
||||
trapFile.Write('<');
|
||||
trapFile.BuildList(",", symbol.TypeArguments, (ta, tb0) => AddSignatureTypeToId(Context, tb0, symbol, ta));
|
||||
trapFile.Write('>');
|
||||
}
|
||||
trapFile.Write(";localfunction");
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public override void WriteQuotedId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write('*');
|
||||
}
|
||||
|
||||
public static new LocalFunction Create(Context cx, IMethodSymbol field) => LocalFunctionFactory.Instance.CreateEntity(cx, field);
|
||||
|
||||
1
csharp/ql/src/experimental/README.md
Normal file
1
csharp/ql/src/experimental/README.md
Normal file
@@ -0,0 +1 @@
|
||||
This directory contains [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -50,7 +50,7 @@ module JsonNET {
|
||||
) {
|
||||
// ToString methods
|
||||
c = getAToStringMethod() and
|
||||
preservesValue = true and
|
||||
preservesValue = false and
|
||||
source = any(CallableFlowSourceArg arg | arg.getArgumentIndex() = 0) and
|
||||
sink instanceof CallableFlowSinkReturn
|
||||
or
|
||||
|
||||
@@ -82,6 +82,7 @@ private newtype TOpcode =
|
||||
TSizedBufferReadSideEffect() or
|
||||
TSizedBufferMustWriteSideEffect() or
|
||||
TSizedBufferMayWriteSideEffect() or
|
||||
TInitializeDynamicAllocation() or
|
||||
TChi() or
|
||||
TInlineAsm() or
|
||||
TUnreached() or
|
||||
@@ -213,23 +214,28 @@ abstract class IndirectReadOpcode extends IndirectMemoryAccessOpcode {
|
||||
}
|
||||
|
||||
/**
|
||||
* An opcode that accesses a memory buffer of unknown size.
|
||||
* An opcode that accesses a memory buffer.
|
||||
*/
|
||||
abstract class BufferAccessOpcode extends Opcode {
|
||||
final override predicate hasAddressOperand() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An opcode that accesses a memory buffer of unknown size.
|
||||
*/
|
||||
abstract class UnsizedBufferAccessOpcode extends BufferAccessOpcode { }
|
||||
|
||||
/**
|
||||
* An opcode that writes to a memory buffer of unknown size.
|
||||
*/
|
||||
abstract class BufferWriteOpcode extends BufferAccessOpcode {
|
||||
abstract class UnsizedBufferWriteOpcode extends UnsizedBufferAccessOpcode {
|
||||
final override MemoryAccessKind getWriteMemoryAccess() { result instanceof BufferMemoryAccess }
|
||||
}
|
||||
|
||||
/**
|
||||
* An opcode that reads from a memory buffer of unknown size.
|
||||
*/
|
||||
abstract class BufferReadOpcode extends BufferAccessOpcode {
|
||||
abstract class UnsizedBufferReadOpcode extends UnsizedBufferAccessOpcode {
|
||||
final override MemoryAccessKind getReadMemoryAccess() { result instanceof BufferMemoryAccess }
|
||||
}
|
||||
|
||||
@@ -261,9 +267,7 @@ abstract class EntireAllocationReadOpcode extends EntireAllocationAccessOpcode {
|
||||
/**
|
||||
* An opcode that accesses a memory buffer whose size is determined by a `BufferSizeOperand`.
|
||||
*/
|
||||
abstract class SizedBufferAccessOpcode extends Opcode {
|
||||
final override predicate hasAddressOperand() { any() }
|
||||
|
||||
abstract class SizedBufferAccessOpcode extends BufferAccessOpcode {
|
||||
final override predicate hasBufferSizeOperand() { any() }
|
||||
}
|
||||
|
||||
@@ -666,17 +670,18 @@ module Opcode {
|
||||
final override string toString() { result = "IndirectMayWriteSideEffect" }
|
||||
}
|
||||
|
||||
class BufferReadSideEffect extends ReadSideEffectOpcode, BufferReadOpcode, TBufferReadSideEffect {
|
||||
class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode,
|
||||
TBufferReadSideEffect {
|
||||
final override string toString() { result = "BufferReadSideEffect" }
|
||||
}
|
||||
|
||||
class BufferMustWriteSideEffect extends WriteSideEffectOpcode, BufferWriteOpcode,
|
||||
class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode,
|
||||
TBufferMustWriteSideEffect {
|
||||
final override string toString() { result = "BufferMustWriteSideEffect" }
|
||||
}
|
||||
|
||||
class BufferMayWriteSideEffect extends WriteSideEffectOpcode, BufferWriteOpcode, MayWriteOpcode,
|
||||
TBufferMayWriteSideEffect {
|
||||
class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode,
|
||||
MayWriteOpcode, TBufferMayWriteSideEffect {
|
||||
final override string toString() { result = "BufferMayWriteSideEffect" }
|
||||
}
|
||||
|
||||
@@ -695,6 +700,11 @@ module Opcode {
|
||||
final override string toString() { result = "SizedBufferMayWriteSideEffect" }
|
||||
}
|
||||
|
||||
class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode,
|
||||
TInitializeDynamicAllocation {
|
||||
final override string toString() { result = "InitializeDynamicAllocation" }
|
||||
}
|
||||
|
||||
class Chi extends Opcode, TChi {
|
||||
final override string toString() { result = "Chi" }
|
||||
|
||||
|
||||
@@ -1,3 +1,275 @@
|
||||
private import IR
|
||||
import InstructionSanity
|
||||
import IRTypeSanity
|
||||
import InstructionSanity // module is below
|
||||
import IRTypeSanity // module is in IRType.qll
|
||||
|
||||
module InstructionSanity {
|
||||
private import internal.InstructionImports as Imports
|
||||
private import Imports::OperandTag
|
||||
private import internal.IRInternal
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
|
||||
*/
|
||||
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
|
||||
exists(OperandTag tag |
|
||||
instr.getOpcode().hasOperand(tag) and
|
||||
not exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
message =
|
||||
"Instruction '" + instr.getOpcode().toString() +
|
||||
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
|
||||
*/
|
||||
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
|
||||
exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
not instr.getOpcode().hasOperand(tag) and
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
|
||||
not (
|
||||
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
|
||||
) and
|
||||
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(
|
||||
Instruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(OperandTag tag, int operandCount |
|
||||
operandCount =
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
operandCount > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag and
|
||||
message =
|
||||
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
|
||||
" in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
|
||||
* the predecessor block `pred`.
|
||||
*/
|
||||
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
not exists(PhiInputOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getPredecessorBlock() = pred
|
||||
)
|
||||
}
|
||||
|
||||
query predicate missingOperandType(Operand operand, string message) {
|
||||
exists(Language::Function func, Instruction use |
|
||||
not exists(operand.getType()) and
|
||||
use = operand.getUse() and
|
||||
func = use.getEnclosingFunction() and
|
||||
message =
|
||||
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
|
||||
"' missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
)
|
||||
}
|
||||
|
||||
query predicate duplicateChiOperand(
|
||||
ChiInstruction chi, string message, IRFunction func, string funcText
|
||||
) {
|
||||
chi.getTotal() = chi.getPartial() and
|
||||
message =
|
||||
"Chi instruction for " + chi.getPartial().toString() +
|
||||
" has duplicate operands in function $@" and
|
||||
func = chi.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
query predicate sideEffectWithoutPrimary(
|
||||
SideEffectInstruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(instr.getPrimaryInstruction()) and
|
||||
message = "Side effect instruction missing primary instruction in function $@" and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an instruction, other than `ExitFunction`, has no successors.
|
||||
*/
|
||||
query predicate instructionWithoutSuccessor(Instruction instr) {
|
||||
not exists(instr.getASuccessor()) and
|
||||
not instr instanceof ExitFunctionInstruction and
|
||||
// Phi instructions aren't linked into the instruction-level flow graph.
|
||||
not instr instanceof PhiInstruction and
|
||||
not instr instanceof UnreachedInstruction
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
|
||||
* where `target` is among the targets of those edges.
|
||||
*/
|
||||
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
|
||||
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
|
||||
n > 1 and
|
||||
source.getSuccessor(kind) = target
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
|
||||
* contains no element that can cause loops.
|
||||
*/
|
||||
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
|
||||
exists(IRBlock block |
|
||||
instr.getBlock() = block and
|
||||
block.getEnclosingFunction() = f and
|
||||
block.getASuccessor+() = block
|
||||
) and
|
||||
not Language::hasPotentialLoop(f)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a `Phi` instruction is present in a block with fewer than two
|
||||
* predecessors.
|
||||
*/
|
||||
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
|
||||
count(instr.getBlock().getAPredecessor()) < 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if operand `operand` consumes a value that was defined in
|
||||
* a different function.
|
||||
*/
|
||||
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
|
||||
operand.getUse() = instr and
|
||||
operand.getAnyDef() = defInstr and
|
||||
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is not in exactly one block.
|
||||
*/
|
||||
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
|
||||
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||
b1.getASuccessor() = b2 and
|
||||
not b1.getBackEdgeSuccessor(_) = b2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` contains a loop in which no edge is a back edge.
|
||||
*
|
||||
* This check ensures we don't have too _few_ back edges.
|
||||
*/
|
||||
query predicate containsLoopOfForwardEdges(IRFunction f) {
|
||||
exists(IRBlock block |
|
||||
forwardEdge+(block, block) and
|
||||
block.getEnclosingIRFunction() = f
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `block` is reachable from its function entry point but would not
|
||||
* be reachable by traversing only forward edges. This check is skipped for
|
||||
* functions containing `goto` statements as the property does not generally
|
||||
* hold there.
|
||||
*
|
||||
* This check ensures we don't have too _many_ back edges.
|
||||
*/
|
||||
query predicate lostReachability(IRBlock block) {
|
||||
exists(IRFunction f, IRBlock entry |
|
||||
entry = f.getEntryBlock() and
|
||||
entry.getASuccessor+() = block and
|
||||
not forwardEdge+(entry, block) and
|
||||
not Language::hasGoto(f.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the number of back edges differs between the `Instruction` graph
|
||||
* and the `IRBlock` graph.
|
||||
*/
|
||||
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
|
||||
fromInstr =
|
||||
count(Instruction i1, Instruction i2 |
|
||||
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||
) and
|
||||
fromBlock =
|
||||
count(IRBlock b1, IRBlock b2 |
|
||||
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
|
||||
) and
|
||||
fromInstr != fromBlock
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the point in the function at which the specified operand is evaluated. For most operands,
|
||||
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
|
||||
* of evaluation is at the end of the corresponding predecessor block.
|
||||
*/
|
||||
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
|
||||
block = operand.(PhiInputOperand).getPredecessorBlock() and
|
||||
index = block.getInstructionCount()
|
||||
or
|
||||
exists(Instruction use |
|
||||
use = operand.(NonPhiOperand).getUse() and
|
||||
block.getInstruction(index) = use
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `useOperand` has a definition that does not dominate the use.
|
||||
*/
|
||||
query predicate useNotDominatedByDefinition(
|
||||
Operand useOperand, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
|
||||
not useOperand.getUse() instanceof UnmodeledUseInstruction and
|
||||
not defInstr instanceof UnmodeledDefinitionInstruction and
|
||||
pointOfEvaluation(useOperand, useBlock, useIndex) and
|
||||
defInstr = useOperand.getAnyDef() and
|
||||
(
|
||||
defInstr instanceof PhiInstruction and
|
||||
defBlock = defInstr.getBlock() and
|
||||
defIndex = -1
|
||||
or
|
||||
defBlock.getInstruction(defIndex) = defInstr
|
||||
) and
|
||||
not (
|
||||
defBlock.strictlyDominates(useBlock)
|
||||
or
|
||||
defBlock = useBlock and
|
||||
defIndex < useIndex
|
||||
) and
|
||||
message =
|
||||
"Operand '" + useOperand.toString() +
|
||||
"' is not dominated by its definition in function '$@'." and
|
||||
func = useOperand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
query predicate switchInstructionWithoutDefaultEdge(
|
||||
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(switchInstr.getDefaultSuccessor()) and
|
||||
message =
|
||||
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
|
||||
func = switchInstr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
|
||||
/**
|
||||
* A temporary variable introduced by IR construction. The most common examples are the variable
|
||||
* generated to hold the return value of afunction, or the variable generated to hold the result of
|
||||
* generated to hold the return value of a function, or the variable generated to hold the result of
|
||||
* a condition operator (`a ? b : c`).
|
||||
*/
|
||||
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
|
||||
@@ -10,274 +10,6 @@ import Imports::MemoryAccessKind
|
||||
import Imports::Opcode
|
||||
private import Imports::OperandTag
|
||||
|
||||
module InstructionSanity {
|
||||
/**
|
||||
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
|
||||
*/
|
||||
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
|
||||
exists(OperandTag tag |
|
||||
instr.getOpcode().hasOperand(tag) and
|
||||
not exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
message =
|
||||
"Instruction '" + instr.getOpcode().toString() +
|
||||
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
|
||||
*/
|
||||
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
|
||||
exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
not instr.getOpcode().hasOperand(tag) and
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
|
||||
not (
|
||||
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
|
||||
) and
|
||||
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(
|
||||
Instruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(OperandTag tag, int operandCount |
|
||||
operandCount =
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
operandCount > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag and
|
||||
message =
|
||||
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
|
||||
" in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
|
||||
* the predecessor block `pred`.
|
||||
*/
|
||||
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
not exists(PhiInputOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getPredecessorBlock() = pred
|
||||
)
|
||||
}
|
||||
|
||||
query predicate missingOperandType(Operand operand, string message) {
|
||||
exists(Language::Function func, Instruction use |
|
||||
not exists(operand.getType()) and
|
||||
use = operand.getUse() and
|
||||
func = use.getEnclosingFunction() and
|
||||
message =
|
||||
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
|
||||
"' missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
)
|
||||
}
|
||||
|
||||
query predicate duplicateChiOperand(
|
||||
ChiInstruction chi, string message, IRFunction func, string funcText
|
||||
) {
|
||||
chi.getTotal() = chi.getPartial() and
|
||||
message =
|
||||
"Chi instruction for " + chi.getPartial().toString() +
|
||||
" has duplicate operands in function $@" and
|
||||
func = chi.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
query predicate sideEffectWithoutPrimary(
|
||||
SideEffectInstruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(instr.getPrimaryInstruction()) and
|
||||
message = "Side effect instruction missing primary instruction in function $@" and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an instruction, other than `ExitFunction`, has no successors.
|
||||
*/
|
||||
query predicate instructionWithoutSuccessor(Instruction instr) {
|
||||
not exists(instr.getASuccessor()) and
|
||||
not instr instanceof ExitFunctionInstruction and
|
||||
// Phi instructions aren't linked into the instruction-level flow graph.
|
||||
not instr instanceof PhiInstruction and
|
||||
not instr instanceof UnreachedInstruction
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
|
||||
* where `target` is among the targets of those edges.
|
||||
*/
|
||||
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
|
||||
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
|
||||
n > 1 and
|
||||
source.getSuccessor(kind) = target
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
|
||||
* contains no element that can cause loops.
|
||||
*/
|
||||
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
|
||||
exists(IRBlock block |
|
||||
instr.getBlock() = block and
|
||||
block.getEnclosingFunction() = f and
|
||||
block.getASuccessor+() = block
|
||||
) and
|
||||
not Language::hasPotentialLoop(f)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a `Phi` instruction is present in a block with fewer than two
|
||||
* predecessors.
|
||||
*/
|
||||
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
|
||||
count(instr.getBlock().getAPredecessor()) < 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if operand `operand` consumes a value that was defined in
|
||||
* a different function.
|
||||
*/
|
||||
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
|
||||
operand.getUse() = instr and
|
||||
operand.getAnyDef() = defInstr and
|
||||
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is not in exactly one block.
|
||||
*/
|
||||
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
|
||||
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||
b1.getASuccessor() = b2 and
|
||||
not b1.getBackEdgeSuccessor(_) = b2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` contains a loop in which no edge is a back edge.
|
||||
*
|
||||
* This check ensures we don't have too _few_ back edges.
|
||||
*/
|
||||
query predicate containsLoopOfForwardEdges(IRFunction f) {
|
||||
exists(IRBlock block |
|
||||
forwardEdge+(block, block) and
|
||||
block.getEnclosingIRFunction() = f
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `block` is reachable from its function entry point but would not
|
||||
* be reachable by traversing only forward edges. This check is skipped for
|
||||
* functions containing `goto` statements as the property does not generally
|
||||
* hold there.
|
||||
*
|
||||
* This check ensures we don't have too _many_ back edges.
|
||||
*/
|
||||
query predicate lostReachability(IRBlock block) {
|
||||
exists(IRFunction f, IRBlock entry |
|
||||
entry = f.getEntryBlock() and
|
||||
entry.getASuccessor+() = block and
|
||||
not forwardEdge+(entry, block) and
|
||||
not Language::hasGoto(f.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the number of back edges differs between the `Instruction` graph
|
||||
* and the `IRBlock` graph.
|
||||
*/
|
||||
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
|
||||
fromInstr =
|
||||
count(Instruction i1, Instruction i2 |
|
||||
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||
) and
|
||||
fromBlock =
|
||||
count(IRBlock b1, IRBlock b2 |
|
||||
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
|
||||
) and
|
||||
fromInstr != fromBlock
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the point in the function at which the specified operand is evaluated. For most operands,
|
||||
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
|
||||
* of evaluation is at the end of the corresponding predecessor block.
|
||||
*/
|
||||
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
|
||||
block = operand.(PhiInputOperand).getPredecessorBlock() and
|
||||
index = block.getInstructionCount()
|
||||
or
|
||||
exists(Instruction use |
|
||||
use = operand.(NonPhiOperand).getUse() and
|
||||
block.getInstruction(index) = use
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `useOperand` has a definition that does not dominate the use.
|
||||
*/
|
||||
query predicate useNotDominatedByDefinition(
|
||||
Operand useOperand, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
|
||||
not useOperand.getUse() instanceof UnmodeledUseInstruction and
|
||||
not defInstr instanceof UnmodeledDefinitionInstruction and
|
||||
pointOfEvaluation(useOperand, useBlock, useIndex) and
|
||||
defInstr = useOperand.getAnyDef() and
|
||||
(
|
||||
defInstr instanceof PhiInstruction and
|
||||
defBlock = defInstr.getBlock() and
|
||||
defIndex = -1
|
||||
or
|
||||
defBlock.getInstruction(defIndex) = defInstr
|
||||
) and
|
||||
not (
|
||||
defBlock.strictlyDominates(useBlock)
|
||||
or
|
||||
defBlock = useBlock and
|
||||
defIndex < useIndex
|
||||
) and
|
||||
message =
|
||||
"Operand '" + useOperand.toString() +
|
||||
"' is not dominated by its definition in function '$@'." and
|
||||
func = useOperand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
query predicate switchInstructionWithoutDefaultEdge(
|
||||
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(switchInstr.getDefaultSuccessor()) and
|
||||
message =
|
||||
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
|
||||
func = switchInstr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified
|
||||
* `File` and line number. Used for assigning register names when printing IR.
|
||||
@@ -1204,6 +936,11 @@ class CallInstruction extends Instruction {
|
||||
final Instruction getPositionalArgument(int index) {
|
||||
result = getPositionalArgumentOperand(index).getDef()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of arguments of the call, including the `this` pointer, if any.
|
||||
*/
|
||||
final int getNumberOfArguments() { result = count(this.getAnArgumentOperand()) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1352,6 +1089,26 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
|
||||
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the initial value of newly allocated memory, e.g. the result of a
|
||||
* call to `malloc`.
|
||||
*/
|
||||
class InitializeDynamicAllocationInstruction extends SideEffectInstruction {
|
||||
InitializeDynamicAllocationInstruction() {
|
||||
getOpcode() instanceof Opcode::InitializeDynamicAllocation
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the address of the allocation this instruction is initializing.
|
||||
*/
|
||||
final AddressOperand getAllocationAddressOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the operand for the allocation this instruction is initializing.
|
||||
*/
|
||||
final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a GNU or MSVC inline assembly statement.
|
||||
*/
|
||||
|
||||
@@ -1,3 +1,275 @@
|
||||
private import IR
|
||||
import InstructionSanity
|
||||
import IRTypeSanity
|
||||
import InstructionSanity // module is below
|
||||
import IRTypeSanity // module is in IRType.qll
|
||||
|
||||
module InstructionSanity {
|
||||
private import internal.InstructionImports as Imports
|
||||
private import Imports::OperandTag
|
||||
private import internal.IRInternal
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
|
||||
*/
|
||||
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
|
||||
exists(OperandTag tag |
|
||||
instr.getOpcode().hasOperand(tag) and
|
||||
not exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
message =
|
||||
"Instruction '" + instr.getOpcode().toString() +
|
||||
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
|
||||
*/
|
||||
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
|
||||
exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
not instr.getOpcode().hasOperand(tag) and
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
|
||||
not (
|
||||
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
|
||||
) and
|
||||
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(
|
||||
Instruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(OperandTag tag, int operandCount |
|
||||
operandCount =
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
operandCount > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag and
|
||||
message =
|
||||
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
|
||||
" in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
|
||||
* the predecessor block `pred`.
|
||||
*/
|
||||
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
not exists(PhiInputOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getPredecessorBlock() = pred
|
||||
)
|
||||
}
|
||||
|
||||
query predicate missingOperandType(Operand operand, string message) {
|
||||
exists(Language::Function func, Instruction use |
|
||||
not exists(operand.getType()) and
|
||||
use = operand.getUse() and
|
||||
func = use.getEnclosingFunction() and
|
||||
message =
|
||||
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
|
||||
"' missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
)
|
||||
}
|
||||
|
||||
query predicate duplicateChiOperand(
|
||||
ChiInstruction chi, string message, IRFunction func, string funcText
|
||||
) {
|
||||
chi.getTotal() = chi.getPartial() and
|
||||
message =
|
||||
"Chi instruction for " + chi.getPartial().toString() +
|
||||
" has duplicate operands in function $@" and
|
||||
func = chi.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
query predicate sideEffectWithoutPrimary(
|
||||
SideEffectInstruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(instr.getPrimaryInstruction()) and
|
||||
message = "Side effect instruction missing primary instruction in function $@" and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an instruction, other than `ExitFunction`, has no successors.
|
||||
*/
|
||||
query predicate instructionWithoutSuccessor(Instruction instr) {
|
||||
not exists(instr.getASuccessor()) and
|
||||
not instr instanceof ExitFunctionInstruction and
|
||||
// Phi instructions aren't linked into the instruction-level flow graph.
|
||||
not instr instanceof PhiInstruction and
|
||||
not instr instanceof UnreachedInstruction
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
|
||||
* where `target` is among the targets of those edges.
|
||||
*/
|
||||
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
|
||||
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
|
||||
n > 1 and
|
||||
source.getSuccessor(kind) = target
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
|
||||
* contains no element that can cause loops.
|
||||
*/
|
||||
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
|
||||
exists(IRBlock block |
|
||||
instr.getBlock() = block and
|
||||
block.getEnclosingFunction() = f and
|
||||
block.getASuccessor+() = block
|
||||
) and
|
||||
not Language::hasPotentialLoop(f)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a `Phi` instruction is present in a block with fewer than two
|
||||
* predecessors.
|
||||
*/
|
||||
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
|
||||
count(instr.getBlock().getAPredecessor()) < 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if operand `operand` consumes a value that was defined in
|
||||
* a different function.
|
||||
*/
|
||||
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
|
||||
operand.getUse() = instr and
|
||||
operand.getAnyDef() = defInstr and
|
||||
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is not in exactly one block.
|
||||
*/
|
||||
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
|
||||
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||
b1.getASuccessor() = b2 and
|
||||
not b1.getBackEdgeSuccessor(_) = b2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` contains a loop in which no edge is a back edge.
|
||||
*
|
||||
* This check ensures we don't have too _few_ back edges.
|
||||
*/
|
||||
query predicate containsLoopOfForwardEdges(IRFunction f) {
|
||||
exists(IRBlock block |
|
||||
forwardEdge+(block, block) and
|
||||
block.getEnclosingIRFunction() = f
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `block` is reachable from its function entry point but would not
|
||||
* be reachable by traversing only forward edges. This check is skipped for
|
||||
* functions containing `goto` statements as the property does not generally
|
||||
* hold there.
|
||||
*
|
||||
* This check ensures we don't have too _many_ back edges.
|
||||
*/
|
||||
query predicate lostReachability(IRBlock block) {
|
||||
exists(IRFunction f, IRBlock entry |
|
||||
entry = f.getEntryBlock() and
|
||||
entry.getASuccessor+() = block and
|
||||
not forwardEdge+(entry, block) and
|
||||
not Language::hasGoto(f.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the number of back edges differs between the `Instruction` graph
|
||||
* and the `IRBlock` graph.
|
||||
*/
|
||||
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
|
||||
fromInstr =
|
||||
count(Instruction i1, Instruction i2 |
|
||||
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||
) and
|
||||
fromBlock =
|
||||
count(IRBlock b1, IRBlock b2 |
|
||||
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
|
||||
) and
|
||||
fromInstr != fromBlock
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the point in the function at which the specified operand is evaluated. For most operands,
|
||||
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
|
||||
* of evaluation is at the end of the corresponding predecessor block.
|
||||
*/
|
||||
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
|
||||
block = operand.(PhiInputOperand).getPredecessorBlock() and
|
||||
index = block.getInstructionCount()
|
||||
or
|
||||
exists(Instruction use |
|
||||
use = operand.(NonPhiOperand).getUse() and
|
||||
block.getInstruction(index) = use
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `useOperand` has a definition that does not dominate the use.
|
||||
*/
|
||||
query predicate useNotDominatedByDefinition(
|
||||
Operand useOperand, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
|
||||
not useOperand.getUse() instanceof UnmodeledUseInstruction and
|
||||
not defInstr instanceof UnmodeledDefinitionInstruction and
|
||||
pointOfEvaluation(useOperand, useBlock, useIndex) and
|
||||
defInstr = useOperand.getAnyDef() and
|
||||
(
|
||||
defInstr instanceof PhiInstruction and
|
||||
defBlock = defInstr.getBlock() and
|
||||
defIndex = -1
|
||||
or
|
||||
defBlock.getInstruction(defIndex) = defInstr
|
||||
) and
|
||||
not (
|
||||
defBlock.strictlyDominates(useBlock)
|
||||
or
|
||||
defBlock = useBlock and
|
||||
defIndex < useIndex
|
||||
) and
|
||||
message =
|
||||
"Operand '" + useOperand.toString() +
|
||||
"' is not dominated by its definition in function '$@'." and
|
||||
func = useOperand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
query predicate switchInstructionWithoutDefaultEdge(
|
||||
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(switchInstr.getDefaultSuccessor()) and
|
||||
message =
|
||||
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
|
||||
func = switchInstr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
|
||||
/**
|
||||
* A temporary variable introduced by IR construction. The most common examples are the variable
|
||||
* generated to hold the return value of afunction, or the variable generated to hold the result of
|
||||
* generated to hold the return value of a function, or the variable generated to hold the result of
|
||||
* a condition operator (`a ? b : c`).
|
||||
*/
|
||||
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
|
||||
@@ -10,274 +10,6 @@ import Imports::MemoryAccessKind
|
||||
import Imports::Opcode
|
||||
private import Imports::OperandTag
|
||||
|
||||
module InstructionSanity {
|
||||
/**
|
||||
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
|
||||
*/
|
||||
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
|
||||
exists(OperandTag tag |
|
||||
instr.getOpcode().hasOperand(tag) and
|
||||
not exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
message =
|
||||
"Instruction '" + instr.getOpcode().toString() +
|
||||
"' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
|
||||
*/
|
||||
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
|
||||
exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
not instr.getOpcode().hasOperand(tag) and
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
|
||||
not (
|
||||
instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
|
||||
) and
|
||||
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(
|
||||
Instruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(OperandTag tag, int operandCount |
|
||||
operandCount =
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) and
|
||||
operandCount > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag and
|
||||
message =
|
||||
"Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" +
|
||||
" in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
|
||||
* the predecessor block `pred`.
|
||||
*/
|
||||
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
not exists(PhiInputOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getPredecessorBlock() = pred
|
||||
)
|
||||
}
|
||||
|
||||
query predicate missingOperandType(Operand operand, string message) {
|
||||
exists(Language::Function func, Instruction use |
|
||||
not exists(operand.getType()) and
|
||||
use = operand.getUse() and
|
||||
func = use.getEnclosingFunction() and
|
||||
message =
|
||||
"Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() +
|
||||
"' missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
)
|
||||
}
|
||||
|
||||
query predicate duplicateChiOperand(
|
||||
ChiInstruction chi, string message, IRFunction func, string funcText
|
||||
) {
|
||||
chi.getTotal() = chi.getPartial() and
|
||||
message =
|
||||
"Chi instruction for " + chi.getPartial().toString() +
|
||||
" has duplicate operands in function $@" and
|
||||
func = chi.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
query predicate sideEffectWithoutPrimary(
|
||||
SideEffectInstruction instr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(instr.getPrimaryInstruction()) and
|
||||
message = "Side effect instruction missing primary instruction in function $@" and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an instruction, other than `ExitFunction`, has no successors.
|
||||
*/
|
||||
query predicate instructionWithoutSuccessor(Instruction instr) {
|
||||
not exists(instr.getASuccessor()) and
|
||||
not instr instanceof ExitFunctionInstruction and
|
||||
// Phi instructions aren't linked into the instruction-level flow graph.
|
||||
not instr instanceof PhiInstruction and
|
||||
not instr instanceof UnreachedInstruction
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there are multiple (`n`) edges of kind `kind` from `source`,
|
||||
* where `target` is among the targets of those edges.
|
||||
*/
|
||||
query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) {
|
||||
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
|
||||
n > 1 and
|
||||
source.getSuccessor(kind) = target
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
|
||||
* contains no element that can cause loops.
|
||||
*/
|
||||
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
|
||||
exists(IRBlock block |
|
||||
instr.getBlock() = block and
|
||||
block.getEnclosingFunction() = f and
|
||||
block.getASuccessor+() = block
|
||||
) and
|
||||
not Language::hasPotentialLoop(f)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a `Phi` instruction is present in a block with fewer than two
|
||||
* predecessors.
|
||||
*/
|
||||
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
|
||||
count(instr.getBlock().getAPredecessor()) < 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if operand `operand` consumes a value that was defined in
|
||||
* a different function.
|
||||
*/
|
||||
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
|
||||
operand.getUse() = instr and
|
||||
operand.getAnyDef() = defInstr and
|
||||
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is not in exactly one block.
|
||||
*/
|
||||
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
|
||||
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||
b1.getASuccessor() = b2 and
|
||||
not b1.getBackEdgeSuccessor(_) = b2
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` contains a loop in which no edge is a back edge.
|
||||
*
|
||||
* This check ensures we don't have too _few_ back edges.
|
||||
*/
|
||||
query predicate containsLoopOfForwardEdges(IRFunction f) {
|
||||
exists(IRBlock block |
|
||||
forwardEdge+(block, block) and
|
||||
block.getEnclosingIRFunction() = f
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `block` is reachable from its function entry point but would not
|
||||
* be reachable by traversing only forward edges. This check is skipped for
|
||||
* functions containing `goto` statements as the property does not generally
|
||||
* hold there.
|
||||
*
|
||||
* This check ensures we don't have too _many_ back edges.
|
||||
*/
|
||||
query predicate lostReachability(IRBlock block) {
|
||||
exists(IRFunction f, IRBlock entry |
|
||||
entry = f.getEntryBlock() and
|
||||
entry.getASuccessor+() = block and
|
||||
not forwardEdge+(entry, block) and
|
||||
not Language::hasGoto(f.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the number of back edges differs between the `Instruction` graph
|
||||
* and the `IRBlock` graph.
|
||||
*/
|
||||
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
|
||||
fromInstr =
|
||||
count(Instruction i1, Instruction i2 |
|
||||
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||
) and
|
||||
fromBlock =
|
||||
count(IRBlock b1, IRBlock b2 |
|
||||
b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2
|
||||
) and
|
||||
fromInstr != fromBlock
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the point in the function at which the specified operand is evaluated. For most operands,
|
||||
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
|
||||
* of evaluation is at the end of the corresponding predecessor block.
|
||||
*/
|
||||
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
|
||||
block = operand.(PhiInputOperand).getPredecessorBlock() and
|
||||
index = block.getInstructionCount()
|
||||
or
|
||||
exists(Instruction use |
|
||||
use = operand.(NonPhiOperand).getUse() and
|
||||
block.getInstruction(index) = use
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `useOperand` has a definition that does not dominate the use.
|
||||
*/
|
||||
query predicate useNotDominatedByDefinition(
|
||||
Operand useOperand, string message, IRFunction func, string funcText
|
||||
) {
|
||||
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
|
||||
not useOperand.getUse() instanceof UnmodeledUseInstruction and
|
||||
not defInstr instanceof UnmodeledDefinitionInstruction and
|
||||
pointOfEvaluation(useOperand, useBlock, useIndex) and
|
||||
defInstr = useOperand.getAnyDef() and
|
||||
(
|
||||
defInstr instanceof PhiInstruction and
|
||||
defBlock = defInstr.getBlock() and
|
||||
defIndex = -1
|
||||
or
|
||||
defBlock.getInstruction(defIndex) = defInstr
|
||||
) and
|
||||
not (
|
||||
defBlock.strictlyDominates(useBlock)
|
||||
or
|
||||
defBlock = useBlock and
|
||||
defIndex < useIndex
|
||||
) and
|
||||
message =
|
||||
"Operand '" + useOperand.toString() +
|
||||
"' is not dominated by its definition in function '$@'." and
|
||||
func = useOperand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
query predicate switchInstructionWithoutDefaultEdge(
|
||||
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
|
||||
) {
|
||||
not exists(switchInstr.getDefaultSuccessor()) and
|
||||
message =
|
||||
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
|
||||
func = switchInstr.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified
|
||||
* `File` and line number. Used for assigning register names when printing IR.
|
||||
@@ -1204,6 +936,11 @@ class CallInstruction extends Instruction {
|
||||
final Instruction getPositionalArgument(int index) {
|
||||
result = getPositionalArgumentOperand(index).getDef()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of arguments of the call, including the `this` pointer, if any.
|
||||
*/
|
||||
final int getNumberOfArguments() { result = count(this.getAnArgumentOperand()) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1352,6 +1089,26 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
|
||||
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the initial value of newly allocated memory, e.g. the result of a
|
||||
* call to `malloc`.
|
||||
*/
|
||||
class InitializeDynamicAllocationInstruction extends SideEffectInstruction {
|
||||
InitializeDynamicAllocationInstruction() {
|
||||
getOpcode() instanceof Opcode::InitializeDynamicAllocation
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the address of the allocation this instruction is initializing.
|
||||
*/
|
||||
final AddressOperand getAllocationAddressOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the operand for the allocation this instruction is initializing.
|
||||
*/
|
||||
final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a GNU or MSVC inline assembly statement.
|
||||
*/
|
||||
|
||||
@@ -665,17 +665,18 @@ module DefUse {
|
||||
private predicate definitionReachesRank(
|
||||
Alias::MemoryLocation useLocation, OldBlock block, int defRank, int reachesRank
|
||||
) {
|
||||
// The def always reaches the next use, even if there is also a def on the
|
||||
// use instruction.
|
||||
hasDefinitionAtRank(useLocation, _, block, defRank, _) and
|
||||
reachesRank <= exitRank(useLocation, block) and // Without this, the predicate would be infinite.
|
||||
(
|
||||
// The def always reaches the next use, even if there is also a def on the
|
||||
// use instruction.
|
||||
reachesRank = defRank + 1
|
||||
or
|
||||
// If the def reached the previous rank, it also reaches the current rank,
|
||||
// unless there was another def at the previous rank.
|
||||
definitionReachesRank(useLocation, block, defRank, reachesRank - 1) and
|
||||
not hasDefinitionAtRank(useLocation, _, block, reachesRank - 1, _)
|
||||
reachesRank = defRank + 1
|
||||
or
|
||||
// If the def reached the previous rank, it also reaches the current rank,
|
||||
// unless there was another def at the previous rank.
|
||||
exists(int prevRank |
|
||||
reachesRank = prevRank + 1 and
|
||||
definitionReachesRank(useLocation, block, defRank, prevRank) and
|
||||
not prevRank = exitRank(useLocation, block) and
|
||||
not hasDefinitionAtRank(useLocation, _, block, prevRank, _)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
1
csharp/ql/test/experimental/README.md
Normal file
1
csharp/ql/test/experimental/README.md
Normal file
@@ -0,0 +1 @@
|
||||
This directory contains tests for [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.
|
||||
@@ -1381,7 +1381,7 @@
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 |
|
||||
@@ -1391,7 +1391,7 @@
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 |
|
||||
@@ -1401,7 +1401,7 @@
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 |
|
||||
@@ -1413,7 +1413,7 @@
|
||||
| GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | GlobalDataFlow.cs:287:50:287:50 | z |
|
||||
| GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | GlobalDataFlow.cs:287:50:287:50 | z : String |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 |
|
||||
@@ -1421,7 +1421,7 @@
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 |
|
||||
@@ -1429,7 +1429,7 @@
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 |
|
||||
@@ -1439,7 +1439,7 @@
|
||||
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<String> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 |
|
||||
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<String> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<String> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<String> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<String> | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 |
|
||||
@@ -1449,7 +1449,7 @@
|
||||
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<T> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 |
|
||||
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<T> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<T> |
|
||||
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<T> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<T> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable<T> | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 |
|
||||
@@ -1461,7 +1461,7 @@
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<String> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<String> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<String> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<String> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<String> | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 |
|
||||
@@ -1473,7 +1473,7 @@
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<T> |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 |
|
||||
@@ -1491,19 +1491,19 @@
|
||||
| GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
|
||||
| GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 |
|
||||
@@ -1521,7 +1521,7 @@
|
||||
| GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call |
|
||||
| GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call : String |
|
||||
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 |
|
||||
@@ -1529,7 +1529,7 @@
|
||||
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:59:82:72 | call to method First |
|
||||
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:59:82:72 | call to method First : String |
|
||||
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 |
|
||||
@@ -1539,7 +1539,7 @@
|
||||
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 |
|
||||
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 |
|
||||
@@ -1553,7 +1553,7 @@
|
||||
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First |
|
||||
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
|
||||
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
|
||||
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable<String> | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 |
|
||||
@@ -1569,7 +1569,7 @@
|
||||
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 |
|
||||
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 |
|
||||
@@ -1583,7 +1583,7 @@
|
||||
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First |
|
||||
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
|
||||
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
|
||||
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable<String> | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 |
|
||||
@@ -1605,19 +1605,19 @@
|
||||
| GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:59:82:72 | call to method First |
|
||||
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<String> | GlobalDataFlow.cs:82:59:82:72 | call to method First : String |
|
||||
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:59:82:72 | call to method First |
|
||||
| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable<T> | GlobalDataFlow.cs:82:59:82:72 | call to method First : String |
|
||||
| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:23:82:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) |
|
||||
@@ -1627,7 +1627,7 @@
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 |
|
||||
@@ -1641,7 +1641,7 @@
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:90:75:90:88 | call to method First |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 |
|
||||
@@ -1659,7 +1659,7 @@
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:84:23:84:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 |
|
||||
@@ -1673,7 +1673,7 @@
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:90:75:90:88 | call to method First |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 |
|
||||
@@ -1685,7 +1685,7 @@
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 |
|
||||
@@ -1699,7 +1699,7 @@
|
||||
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First |
|
||||
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
|
||||
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
|
||||
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 |
|
||||
@@ -1713,7 +1713,7 @@
|
||||
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 |
|
||||
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... |
|
||||
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 |
|
||||
@@ -1721,7 +1721,7 @@
|
||||
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:119 | call to method First |
|
||||
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:119 | call to method First : String |
|
||||
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... |
|
||||
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable<String> | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 |
|
||||
@@ -1733,7 +1733,7 @@
|
||||
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 |
|
||||
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... |
|
||||
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 |
|
||||
@@ -1741,7 +1741,7 @@
|
||||
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:119 | call to method First |
|
||||
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:119 | call to method First : String |
|
||||
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... |
|
||||
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable<String> | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 |
|
||||
@@ -1759,7 +1759,7 @@
|
||||
| GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:23:84:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:84:59:84:72 | call to method First |
|
||||
@@ -1771,7 +1771,7 @@
|
||||
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First |
|
||||
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
|
||||
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
|
||||
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 |
|
||||
@@ -1783,13 +1783,13 @@
|
||||
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 |
|
||||
| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... |
|
||||
| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:82:84:121 | (...) ... |
|
||||
| GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:82:84:121 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:82:84:121 | (...) ... |
|
||||
| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:82:84:121 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:82:84:121 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) |
|
||||
@@ -1799,7 +1799,7 @@
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 |
|
||||
@@ -1807,7 +1807,7 @@
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:106:86:119 | call to method First |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:106:86:119 | call to method First : String |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 |
|
||||
@@ -1835,7 +1835,7 @@
|
||||
| GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... |
|
||||
| GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String |
|
||||
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... |
|
||||
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 |
|
||||
@@ -1843,7 +1843,7 @@
|
||||
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:119 | call to method First |
|
||||
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:119 | call to method First : String |
|
||||
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... |
|
||||
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 |
|
||||
@@ -1859,7 +1859,7 @@
|
||||
| GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:23:86:62 | (...) ... |
|
||||
| GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:23:86:62 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:23:86:62 | (...) ... |
|
||||
| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:23:86:62 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:23:86:62 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... |
|
||||
@@ -1873,13 +1873,13 @@
|
||||
| GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:70:86:121 | (...) ... |
|
||||
| GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... |
|
||||
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:119 | call to method First |
|
||||
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:86:106:86:119 | call to method First : String |
|
||||
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... |
|
||||
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 |
|
||||
@@ -1887,7 +1887,7 @@
|
||||
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:104:118:117 | call to method First |
|
||||
| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:104:118:117 | call to method First : String |
|
||||
| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... |
|
||||
| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) |
|
||||
@@ -1927,7 +1927,7 @@
|
||||
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First |
|
||||
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
|
||||
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
|
||||
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 |
|
||||
@@ -2069,13 +2069,13 @@
|
||||
| GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:90:23:90:62 | (...) ... |
|
||||
| GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:23:90:62 | (...) ... |
|
||||
| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:23:90:62 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First |
|
||||
| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
|
||||
| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
|
||||
| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 |
|
||||
@@ -2365,13 +2365,13 @@
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
|
||||
@@ -2383,13 +2383,13 @@
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
|
||||
@@ -2407,13 +2407,13 @@
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
|
||||
@@ -2423,13 +2423,13 @@
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
|
||||
@@ -2461,13 +2461,13 @@
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
|
||||
@@ -2477,13 +2477,13 @@
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
|
||||
@@ -2491,25 +2491,25 @@
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z |
|
||||
| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z : T |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
|
||||
@@ -2537,21 +2537,21 @@
|
||||
| GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
|
||||
| GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 |
|
||||
@@ -2585,11 +2585,11 @@
|
||||
| GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
|
||||
| GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
|
||||
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... |
|
||||
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:114:76:114:76 | x : IEnumerable<String> | GlobalDataFlow.cs:114:76:114:76 | x |
|
||||
@@ -2627,7 +2627,7 @@
|
||||
| GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
|
||||
| GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
|
||||
| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:116:57:116:70 | call to method First |
|
||||
@@ -2637,7 +2637,7 @@
|
||||
| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 |
|
||||
| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... |
|
||||
| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:116:80:116:119 | (...) ... : IEnumerable<String> | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... |
|
||||
@@ -2651,7 +2651,7 @@
|
||||
| GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:80:116:119 | (...) ... |
|
||||
| GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:80:116:119 | (...) ... |
|
||||
| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:80:116:119 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) |
|
||||
@@ -2701,19 +2701,19 @@
|
||||
| GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:21:118:60 | (...) ... |
|
||||
| GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:21:118:60 | (...) ... |
|
||||
| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:21:118:60 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:68:118:119 | (...) ... |
|
||||
| GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... |
|
||||
| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:104:118:117 | call to method First |
|
||||
| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable<String> | GlobalDataFlow.cs:118:104:118:117 | call to method First : String |
|
||||
| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... |
|
||||
| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] |
|
||||
| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] |
|
||||
| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) |
|
||||
@@ -3833,17 +3833,17 @@
|
||||
| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable<String> | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink |
|
||||
| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable<String> | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable<String> |
|
||||
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) |
|
||||
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable<String> |
|
||||
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:19:222:39 | call to method Select |
|
||||
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable<String> |
|
||||
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink |
|
||||
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable<String> |
|
||||
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) |
|
||||
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable<String> |
|
||||
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:19:222:39 | call to method Select |
|
||||
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable<String> |
|
||||
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink |
|
||||
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable<String> |
|
||||
| GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable<String> | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink |
|
||||
| GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable<String> | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable<String> | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam |
|
||||
@@ -3879,17 +3879,17 @@
|
||||
| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable<String> | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink |
|
||||
| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable<String> | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable<String> |
|
||||
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) |
|
||||
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable<String> |
|
||||
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:19:226:39 | call to method Select |
|
||||
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable<String> |
|
||||
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink |
|
||||
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable<String> |
|
||||
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) |
|
||||
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable<String> |
|
||||
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:19:226:39 | call to method Select |
|
||||
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable<String> |
|
||||
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink |
|
||||
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable<String> |
|
||||
| GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable<String> | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink |
|
||||
| GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable<String> | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable<String> | GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func<String,String> |
|
||||
|
||||
@@ -137,21 +137,21 @@ edges
|
||||
| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String |
|
||||
| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> |
|
||||
| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T |
|
||||
| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> |
|
||||
| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T |
|
||||
| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | GlobalDataFlow.cs:90:75:90:88 | call to method First : String |
|
||||
| GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String |
|
||||
| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String |
|
||||
| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 |
|
||||
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String |
|
||||
| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String |
|
||||
@@ -199,7 +199,7 @@ edges
|
||||
| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 |
|
||||
| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 |
|
||||
| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 |
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable<String> | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 |
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 |
|
||||
| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 |
|
||||
| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable<String> | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 |
|
||||
| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String |
|
||||
@@ -331,15 +331,15 @@ nodes
|
||||
| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | semmle.label | SSA def(sink3) : String |
|
||||
| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | semmle.label | access to local variable sink3 |
|
||||
| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | semmle.label | call to method SelectEven : IEnumerable<T> |
|
||||
| GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable<String> | semmle.label | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | semmle.label | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | semmle.label | access to local variable sink13 |
|
||||
| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable<String> | semmle.label | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | semmle.label | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> : T | semmle.label | [output] delegate creation of type Func<String,String> : T |
|
||||
| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | semmle.label | access to local variable sink14 |
|
||||
| GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable<String> | semmle.label | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | semmle.label | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String |
|
||||
| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | semmle.label | access to local variable sink15 |
|
||||
| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable<String> | semmle.label | (...) ... : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | semmle.label | (...) ... : String[] |
|
||||
| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String |
|
||||
| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | semmle.label | access to local variable sink16 |
|
||||
| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable<String> | semmle.label | access to local variable sink14 : IEnumerable<String> |
|
||||
@@ -404,7 +404,7 @@ nodes
|
||||
| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 |
|
||||
| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | semmle.label | sinkParam7 : String |
|
||||
| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 |
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable<String> | semmle.label | sinkParam8 : IEnumerable<String> |
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | semmle.label | sinkParam8 : String[] |
|
||||
| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 |
|
||||
| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | semmle.label | sinkParam9 : String |
|
||||
| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 |
|
||||
|
||||
41
docs/experimental.md
Normal file
41
docs/experimental.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Experimental CodeQL queries and libraries
|
||||
|
||||
In addition to our standard CodeQL queries and libraries, this repository may also contain queries and libraries of a more experimental nature. Experimental queries and libraries can be improved incrementally and may eventually reach a sufficient maturity to be included in our standard libraries and queries.
|
||||
|
||||
Experimental queries and libraries may not be actively maintained as the standard libraries evolve. They may also be changed in backwards-incompatible ways or may be removed entirely in the future without deprecation warnings.
|
||||
|
||||
## Requirements
|
||||
|
||||
1. **Directory structure**
|
||||
|
||||
- Experimental queries and libraries are stored in the `experimental` subdirectory within each language-specific directory in the [CodeQL repository](https://github.com/Semmle/ql). For example, experimental Java queries and libraries are stored in `ql/java/ql/src/experimental` and any corresponding tests in `ql/java/ql/test/experimental`.
|
||||
- The structure of an `experimental` subdirectory mirrors the structure of standard queries and libraries (or tests) in the parent directory.
|
||||
|
||||
2. **Query metadata**
|
||||
|
||||
- The query `@id` must not clash with any other queries in the repository.
|
||||
- The query must have a `@name` and `@description` to explain its purpose.
|
||||
- The query must have a `@kind` and `@problem.severity` as required by CodeQL tools.
|
||||
|
||||
For details, see the [guide on query metadata](https://github.com/Semmle/ql/blob/master/docs/query-metadata-style-guide.md).
|
||||
|
||||
3. **Formatting**
|
||||
|
||||
- The queries and libraries must be [autoformatted](https://help.semmle.com/codeql/codeql-for-vscode/reference/editor.html#autoformatting).
|
||||
|
||||
4. **Compilation**
|
||||
|
||||
- Compilation of the query and any associated libraries and tests must be resilient to future development of the standard libraries. This means that the functionality cannot use internal APIs, cannot depend on the output of `getAQlClass`, and cannot make use of regexp matching on `toString`.
|
||||
- The query and any associated libraries and tests must not cause any compiler warnings to be emitted (such as use of deprecated functionality or missing `override` annotations).
|
||||
|
||||
5. **Results**
|
||||
|
||||
- The query must have at least one true positive result on some revision of a real project.
|
||||
|
||||
6. **Contributor License Agreement**
|
||||
|
||||
- The contributor can satisfy the [CLA](CONTRIBUTING.md#contributor-license-agreement).
|
||||
|
||||
## Non-requirements
|
||||
|
||||
Other criteria typically required for our standard queries and libraries are not required for experimental queries and libraries. In particular, fully disciplined query [metadata](docs/query-metadata-style-guide.md), query [help](docs/query-help-style-guide.md), tests, a low false positive rate and performance tuning are not required (but nonetheless recommended).
|
||||
@@ -1,7 +1,7 @@
|
||||
Learning CodeQL
|
||||
###############
|
||||
|
||||
CodeQL is the code analysis platform used by security researchers to automate `variant analysis <https://semmle.com/variant-analysis>`__.
|
||||
CodeQL is the code analysis platform used by security researchers to automate variant analysis.
|
||||
You can use CodeQL queries to explore code and quickly find variants of security vulnerabilities and bugs.
|
||||
These queries are easy to write and share–visit the topics below and `our open source repository on GitHub <https://github.com/Semmle/ql>`__ to learn more.
|
||||
You can also try out CodeQL in the `query console <https://lgtm.com/query>`__ on `LGTM.com <https://lgtm.com>`__.
|
||||
|
||||
@@ -4,9 +4,9 @@ CodeQL training and variant analysis examples
|
||||
CodeQL and variant analysis
|
||||
---------------------------
|
||||
|
||||
`Variant analysis <https://semmle.com/variant-analysis>`__ is the process of using a known vulnerability as a seed to find similar problems in your code. Security engineers typically perform variant analysis to identify possible vulnerabilities and to ensure that these threats are properly fixed across multiple code bases.
|
||||
Variant analysis is the process of using a known vulnerability as a seed to find similar problems in your code. Security engineers typically perform variant analysis to identify possible vulnerabilities and to ensure that these threats are properly fixed across multiple code bases.
|
||||
|
||||
`CodeQL <https://semmle.com/ql>`__ is the code analysis engine that underpins LGTM, Semmle's community driven security analysis platform. Together, CodeQL and LGTM provide continuous monitoring and scalable variant analysis for your projects, even if you don’t have your own team of dedicated security engineers. You can read more about using CodeQL and LGTM in variant analysis on the `Security Lab research page <https://securitylab.github.com/research>`__.
|
||||
CodeQL is the code analysis engine that underpins LGTM, the community driven security analysis platform. Together, CodeQL and LGTM provide continuous monitoring and scalable variant analysis for your projects, even if you don’t have your own team of dedicated security engineers. You can read more about using CodeQL and LGTM in variant analysis on the `Security Lab research page <https://securitylab.github.com/research>`__.
|
||||
|
||||
CodeQL is easy to learn, and exploring code using CodeQL is the most efficient way to perform variant analysis.
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ Let’s look for overflow guards of the form ``v + b < v``, using the classes
|
||||
|
||||
.. note::
|
||||
|
||||
- When performing `variant analysis <https://semmle.com/variant-analysis>`__, it is usually helpful to write a simple query that finds the simple syntactic pattern, before trying to go on to describe the cases where it goes wrong.
|
||||
- When performing variant analysis, it is usually helpful to write a simple query that finds the simple syntactic pattern, before trying to go on to describe the cases where it goes wrong.
|
||||
- In this case, we start by looking for all the *overflow* checks, before trying to refine the query to find all *bad overflow* checks.
|
||||
- The ``select`` clause defines what this query is looking for:
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ Let’s start by looking for calls to methods with names of the form ``sparql*Qu
|
||||
|
||||
.. note::
|
||||
|
||||
- When performing `variant analysis <https://semmle.com/variant-analysis>`__, it is usually helpful to write a simple query that finds the simple syntactic pattern, before trying to go on to describe the cases where it goes wrong.
|
||||
- When performing variant analysis, it is usually helpful to write a simple query that finds the simple syntactic pattern, before trying to go on to describe the cases where it goes wrong.
|
||||
- In this case, we start by looking for all the method calls that appear to run, before trying to refine the query to find cases which are vulnerable to query injection.
|
||||
- The ``select`` clause defines what this query is looking for:
|
||||
|
||||
|
||||
@@ -81,8 +81,6 @@ Find all instances!
|
||||
|
||||
- All were fixed with a mid-flight patch.
|
||||
|
||||
- For more detail on the collaboration between Semmle and NASA, see our case study: `Semmle at NASA: Landing Curiosity safely on Mars <https://semmle.com/case-studies/semmle-nasa-landing-curiosity-safely-mars>`__.
|
||||
|
||||
.. note::
|
||||
|
||||
The JPL team ran the query across the full Curiosity control software–it identified the original problem, and more than 30 other variants, of which three were in the critical Entry, Descent, and Landing module.
|
||||
@@ -107,7 +105,7 @@ Analysis overview
|
||||
|
||||
Once the extraction finishes, all this information is collected into a single `CodeQL database <https://help.semmle.com/QL/learn-ql/database.html>`__, which is then ready to query, possibly on a different machine. A copy of the source files, made at the time the database was created, is also included in the CodeQL database so analysis results can be displayed at the correct location in the code. The database schema is (source) language specific.
|
||||
|
||||
Queries are written in `QL <https://semmle.com/ql>`__ and usually depend on one or more of the `standard CodeQL libraries <https://github.com/semmle/ql>`__ (and of course you can write your own custom libraries). They are compiled into an efficiently executable format by the QL compiler and then run on a CodeQL database by the QL evaluator, either on a remote worker machine or locally on a developer’s machine.
|
||||
Queries are written in QL and usually depend on one or more of the `standard CodeQL libraries <https://github.com/semmle/ql>`__ (and of course you can write your own custom libraries). They are compiled into an efficiently executable format by the QL compiler and then run on a CodeQL database by the QL evaluator, either on a remote worker machine or locally on a developer’s machine.
|
||||
|
||||
Query results can be interpreted and presented in a variety of ways, including displaying them in an `IDE extension <https://lgtm.com/help/lgtm/running-queries-ide>`__ such as CodeQL for Visual Studio Code, or in a web dashboard as on `LGTM <https://lgtm.com/help/lgtm/about-lgtm>`__.
|
||||
|
||||
|
||||
12
java/ql/src/Customizations.qll
Normal file
12
java/ql/src/Customizations.qll
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Contains customizations to the standard library.
|
||||
*
|
||||
* This module is imported by `java.qll`, so any customizations defined here automatically
|
||||
* apply to all queries.
|
||||
*
|
||||
* Typical examples of customizations include adding new subclasses of abstract classes such as
|
||||
* the `RemoteFlowSource` and `AdditionalTaintStep` classes associated with the security queries
|
||||
* to model frameworks that are not covered by the standard library.
|
||||
*/
|
||||
|
||||
import java
|
||||
1
java/ql/src/experimental/README.md
Normal file
1
java/ql/src/experimental/README.md
Normal file
@@ -0,0 +1 @@
|
||||
This directory contains [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.
|
||||
@@ -1,5 +1,6 @@
|
||||
/** Provides all default Java QL imports. */
|
||||
|
||||
import Customizations
|
||||
import semmle.code.FileSystem
|
||||
import semmle.code.Location
|
||||
import semmle.code.java.Annotation
|
||||
|
||||
@@ -364,13 +364,45 @@ private predicate typeFlow(TypeFlowNode n, RefType t) {
|
||||
typeFlowJoin(lastRank(n), n, t)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate erasedTypeBound(RefType t) {
|
||||
exists(RefType t0 | typeFlow(_, t0) and t = t0.getErasure())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate typeBound(RefType t) { typeFlow(_, t) }
|
||||
|
||||
/**
|
||||
* Holds if we have a bound for `n` that is better than `t`, taking only erased
|
||||
* types into account.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate irrelevantErasedBound(TypeFlowNode n, RefType t) {
|
||||
exists(RefType bound |
|
||||
typeFlow(n, bound)
|
||||
or
|
||||
n.getType() = bound and typeFlow(n, _)
|
||||
|
|
||||
t = bound.getErasure().(RefType).getASourceSupertype+() and
|
||||
erasedTypeBound(t)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if we have a bound for `n` that is better than `t`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate irrelevantBound(TypeFlowNode n, RefType t) {
|
||||
exists(RefType bound | typeFlow(n, bound) or n.getType() = bound |
|
||||
t = bound.getErasure().(RefType).getASourceSupertype+()
|
||||
exists(RefType bound |
|
||||
typeFlow(n, bound) and
|
||||
t = bound.getASupertype+() and
|
||||
typeBound(t) and
|
||||
typeFlow(n, t) and
|
||||
not t.getASupertype*() = bound
|
||||
or
|
||||
n.getType() = bound and
|
||||
typeFlow(n, t) and
|
||||
t = bound.getASupertype*()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -380,7 +412,8 @@ private predicate irrelevantBound(TypeFlowNode n, RefType t) {
|
||||
*/
|
||||
private predicate bestTypeFlow(TypeFlowNode n, RefType t) {
|
||||
typeFlow(n, t) and
|
||||
not irrelevantBound(n, t.getErasure())
|
||||
not irrelevantErasedBound(n, t.getErasure()) and
|
||||
not irrelevantBound(n, t)
|
||||
}
|
||||
|
||||
cached
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -1307,15 +1307,20 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowStep(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
additionalLocalFlowStep(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1323,17 +1328,18 @@ private predicate localFlowStepPlus(
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand(TNormalNode(node2), unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1345,17 +1351,18 @@ private predicate localFlowStepPlus(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStepExt(
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, Configuration config
|
||||
NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config
|
||||
) {
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, config, _)
|
||||
localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _)
|
||||
}
|
||||
|
||||
private newtype TAccessPathFront =
|
||||
@@ -1395,46 +1402,24 @@ private predicate flowCandFwd(
|
||||
else any()
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathFrontNilNode extends NormalNodeExt {
|
||||
AccessPathFrontNilNode() {
|
||||
nodeCand(this, _) and
|
||||
(
|
||||
any(Configuration c).isSource(this.getNode())
|
||||
or
|
||||
localFlowBigStepExt(_, this, false, _)
|
||||
or
|
||||
additionalJumpStepExt(_, this, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `nil` path front for this node. */
|
||||
AccessPathFrontNil getApf() { result = TFrontNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
private predicate flowCandFwd0(
|
||||
NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config
|
||||
) {
|
||||
nodeCand2(node, _, false, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
or
|
||||
nodeCand(node, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
localFlowBigStepExt(mid, node, false, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
@@ -1447,7 +1432,7 @@ private predicate flowCandFwd0(
|
||||
flowCandFwd(mid, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
apf = TFrontNil(node.getErasedNodeTypeBound())
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, boolean allowsFieldFlow |
|
||||
@@ -1589,13 +1574,13 @@ private predicate flowCand0(
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1810,18 +1795,6 @@ private predicate popWithFront(AccessPath ap0, Content f, AccessPathFront apf, A
|
||||
/** Gets the access path obtained by pushing `f` onto `ap`. */
|
||||
private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) }
|
||||
|
||||
/**
|
||||
* A node that requires an empty access path and should have its tracked type
|
||||
* (re-)computed. This is either a source or a node reached through an
|
||||
* additional step.
|
||||
*/
|
||||
private class AccessPathNilNode extends NormalNodeExt {
|
||||
AccessPathNilNode() { flowCand(this.(AccessPathFrontNilNode), _, _, _) }
|
||||
|
||||
/** Gets the `nil` path for this node. */
|
||||
AccessPathNil getAp() { result = TNil(this.getErasedNodeTypeBound()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from a source to `node` with the given `ap`.
|
||||
*/
|
||||
@@ -1838,20 +1811,19 @@ private predicate flowFwd0(
|
||||
flowCand(node, _, _, config) and
|
||||
config.isSource(node.getNode()) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, unbind(config)) and
|
||||
(
|
||||
exists(NodeExt mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStepExt(mid, node, true, config)
|
||||
localFlowBigStepExt(mid, node, true, _, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStepExt(mid, node, false, config) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
localFlowBigStepExt(mid, node, false, apf, config) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1865,7 +1837,7 @@ private predicate flowFwd0(
|
||||
flowFwd(mid, _, _, nil, config) and
|
||||
additionalJumpStepExt(mid, node, config) and
|
||||
fromArg = false and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
ap = TNil(node.getErasedNodeTypeBound()) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
@@ -1982,13 +1954,13 @@ private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configura
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(NodeExt mid |
|
||||
localFlowBigStepExt(node, mid, true, config) and
|
||||
localFlowBigStepExt(node, mid, true, _, config) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(NodeExt mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStepExt(node, mid, false, config) and
|
||||
localFlowBigStepExt(node, mid, false, _, config) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -2164,7 +2136,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2357,12 +2329,11 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and
|
||||
localCC = getLocalCallContext(cc, enclosing)
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and
|
||||
ap0 instanceof AccessPathNil
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
@@ -2374,7 +2345,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = any(AccessPathNilNode nil | nil.getNode() = node).getAp()
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Content f, AccessPath ap0 | pathReadStep(mid, node, ap0, f, cc) and ap = pop(f, ap0)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2397,7 +2368,7 @@ private predicate pathIntoLocalStep(
|
||||
midnode = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
conf = mid.getConfiguration() and
|
||||
localFlowBigStep(midnode, _, _, conf, _) and
|
||||
localFlowBigStep(midnode, _, _, _, conf, _) and
|
||||
enclosing = midnode.getEnclosingCallable() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
ap0 = mid.getAp()
|
||||
@@ -2949,7 +2920,7 @@ private module FlowExploration {
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate partialPathOutOfCallable1(
|
||||
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
|
||||
@@ -305,6 +305,7 @@ private module Unification {
|
||||
arg2 = t2.getTypeArgument(pos)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate failsUnification(Type t1, Type t2) {
|
||||
unificationTargets(t1, t2) and
|
||||
(
|
||||
|
||||
1
java/ql/test/experimental/README.md
Normal file
1
java/ql/test/experimental/README.md
Normal file
@@ -0,0 +1 @@
|
||||
This directory contains tests for [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.
|
||||
@@ -34,4 +34,38 @@ public class A {
|
||||
Box b4 = Box.mk(taint());
|
||||
sink(b4.getS1());
|
||||
}
|
||||
|
||||
static class Box2 {
|
||||
String s;
|
||||
String getS() { return s; }
|
||||
void setS(String s) { this.s = s; }
|
||||
|
||||
Box2(String s) {
|
||||
setS(s + "1");
|
||||
}
|
||||
String getS1() { return getS() + "2"; }
|
||||
String getS2() { return step(getS() + "_") + "2"; }
|
||||
void setS1(String s) { setS("3" + s); }
|
||||
void setS2(String s) { setS("3" + step("_" + s)); }
|
||||
static Box2 mk(String s) {
|
||||
Box2 b = new Box2("");
|
||||
b.setS(step(s));
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
void foo2(Box2 b1, Box2 b2) {
|
||||
b1.setS1(taint());
|
||||
sink(b1.getS1());
|
||||
|
||||
b2.setS2(taint());
|
||||
sink(b2.getS2());
|
||||
|
||||
String t3 = taint();
|
||||
Box2 b3 = new Box2(step(t3));
|
||||
sink(b3.s);
|
||||
|
||||
Box2 b4 = Box2.mk(taint());
|
||||
sink(b4.getS1());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,3 +2,7 @@
|
||||
| A.java:27:14:27:20 | taint(...) | A.java:28:10:28:19 | getS2(...) |
|
||||
| A.java:30:17:30:23 | taint(...) | A.java:32:10:32:13 | b3.s |
|
||||
| A.java:34:21:34:27 | taint(...) | A.java:35:10:35:19 | getS1(...) |
|
||||
| A.java:58:14:58:20 | taint(...) | A.java:59:10:59:19 | getS1(...) |
|
||||
| A.java:61:14:61:20 | taint(...) | A.java:62:10:62:19 | getS2(...) |
|
||||
| A.java:64:17:64:23 | taint(...) | A.java:66:10:66:13 | b3.s |
|
||||
| A.java:68:23:68:29 | taint(...) | A.java:69:10:69:19 | getS1(...) |
|
||||
|
||||
18
java/ql/test/library-tests/dataflow/typepruning/A.java
Normal file
18
java/ql/test/library-tests/dataflow/typepruning/A.java
Normal file
@@ -0,0 +1,18 @@
|
||||
public class A {
|
||||
Object customStep(Object o) { return null; }
|
||||
|
||||
Object source() { return null; }
|
||||
|
||||
void sink(Object o) { }
|
||||
|
||||
Object through1(Object o) {
|
||||
Object o2 = customStep(o);
|
||||
String s = (String)o2;
|
||||
return s;
|
||||
}
|
||||
|
||||
void foo() {
|
||||
Object x = through1(source());
|
||||
sink(x);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user