Merge branch 'master' into rdmarsh/cpp/ir-flow-through-outparams

This commit is contained in:
Robert Marsh
2020-03-10 11:12:19 -07:00
477 changed files with 9258 additions and 4696 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1 @@
This directory contains [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1 @@
This directory contains tests for [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,7 @@
#define Foo static void foo()
Foo;
int main()
{
return 0;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -69,3 +69,10 @@ void test10(int x) {
} while (0);
}
}
extern const int const256;
void test11() {
short s;
for(s = 0; s < const256; ++s) {}
}

View File

@@ -0,0 +1 @@
const int const256 = 256;

View File

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

View File

@@ -0,0 +1 @@
This directory contains [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1 @@
This directory contains tests for [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.

View File

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

View File

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

View File

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

View File

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

View File

@@ -141,7 +141,7 @@ Lets 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:

View File

@@ -77,7 +77,7 @@ Lets 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:

View File

@@ -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 softwareit 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 developers 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 developers 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>`__.

View 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

View File

@@ -0,0 +1 @@
This directory contains [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -305,6 +305,7 @@ private module Unification {
arg2 = t2.getTypeArgument(pos)
}
pragma[nomagic]
predicate failsUnification(Type t1, Type t2) {
unificationTargets(t1, t2) and
(

View File

@@ -0,0 +1 @@
This directory contains tests for [experimental](../../../../docs/experimental.md) CodeQL queries and libraries.

View File

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

View File

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

View 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