Compare commits

..

2 Commits

Author SHA1 Message Date
Esben Sparre Andreasen
e94e1bb65b re-optimize without being unsound 2022-03-17 10:55:55 +01:00
Esben Sparre Andreasen
e16470a2ae undo unsound performance optimizations
For an ordinary path-problem query, it is a requirement that at least one sink exists, otherwise there is nothing to alert on.
Thus the optimization with checking `isSink(_, this, _)` pruning in `Configuration::hasFlow` is sound.

For programs without any relevant sinks (which is likely to be the case when ATM is used), the `Configuration::hasFlow` calls will not hold due to the above pruning step.
The optimizations removed in this commit are thus unsound for programs without any relevant sinks.
2022-03-16 21:49:52 +01:00
317 changed files with 4109 additions and 21483 deletions

View File

@@ -36,7 +36,7 @@ If you have an idea for a query that you would like to share with other CodeQL u
For details, see the [guide on query metadata](docs/query-metadata-style-guide.md).
Make sure the `select` statement is compatible with the query `@kind`. See [About CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/about-codeql-queries/#select-clause) on codeql.github.com.
Make sure the `select` statement is compatible with the query `@kind`. See [About CodeQL queries](https://help.semmle.com/QL/learn-ql/writing-queries/introduction-to-queries.html#select-clause) on help.semmle.com.
3. **Formatting**

View File

@@ -1,51 +0,0 @@
# benjamin-buttons.md
This file describes the changes that have been applied to
the library to make it behave as if it was younger.
## TaintedPath.ql
Sinks added between 2020-01-01 and 2020-10-06 have been removed. Found by looking at:
- the commit titles of https://github.com/github/codeql/commits/main/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sink
Sinks added between 2018-08-02 and 2020-01-01 have been removed. Found by looking at:
- the commit titles of https://github.com/github/codeql/commits/main/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sink
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+pathinjection
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+tainted-path
Sinks from the "graceful-fs" and "fs-extra" (added before the open-sourcing squash).
## Xss.ql
Sinks added between 2020-01-01 and 2020-10-06 have been removed. Found by looking at:
- the commit titles of https://github.com/github/codeql/commits/main/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sink
- recursive type tracking for `jQuery::dollar`, `DOM::domValueRef`.
## SqlInjection.ql
Sinks added between 2020-01-01 and 2020-10-06 have been removed. Found by looking at:
- the commit titles of https://github.com/github/codeql/commits/main/javascript/ql/test/query-tests/Security/CWE-089
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sink
Sinks added between 2018-08-02 and 2020-01-01 have been removed. Found by looking at:
- the commit titles of https://github.com/github/codeql/commits/main/javascript/ql/test/query-tests/Security/CWE-089
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sink
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sql
TypeTracking in SQL.qll (added before the open-sourcing squash)
The model of `mssql` and `sequelize` (added before the open-sourcing squash)
## PseudoProperties
Pseudo-properties (`$name$`) used in type-tracking and global dataflow configurations have been disabled.
Found by searching for `"\$.*\$"`.

View File

@@ -27,8 +27,7 @@
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll"
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll"
],
"DataFlow Java/C++/C#/Python Common": [
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
@@ -55,8 +54,7 @@
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking2/TaintTrackingImpl.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking4/TaintTrackingImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforlibraries/TaintTrackingImpl.qll"
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
],
"DataFlow Java/C++/C#/Python Consistency checks": [
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll",
@@ -482,12 +480,11 @@
"python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll",
"ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll"
],
"ReDoS Exponential Python/JS/Ruby": [
"ReDoS Exponential Python/JS": [
"javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll",
"python/ql/lib/semmle/python/security/performance/ExponentialBackTracking.qll",
"ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll"
"python/ql/lib/semmle/python/security/performance/ExponentialBackTracking.qll"
],
"ReDoS Polynomial Python/JS/Ruby": [
"ReDoS Polynomial Python/JS": [
"javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll",
"ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll"
@@ -518,30 +515,5 @@
"java/ql/lib/semmle/code/java/dataflow/internal/AccessPathSyntax.qll",
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/AccessPathSyntax.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/AccessPathSyntax.qll"
],
"Hostname Regexp queries": [
"javascript/ql/src/Security/CWE-020/HostnameRegexpShared.qll",
"python/ql/src/Security/CWE-020/HostnameRegexpShared.qll",
"ruby/ql/src/queries/security/cwe-020/HostnameRegexpShared.qll"
],
"ApiGraphModels": [
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll",
"ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll"
],
"TaintedFormatStringQuery Ruby/JS": [
"javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatStringQuery.qll",
"ruby/ql/lib/codeql/ruby/security/TaintedFormatStringQuery.qll"
],
"TaintedFormatStringCustomizations Ruby/JS": [
"javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatStringCustomizations.qll",
"ruby/ql/lib/codeql/ruby/security/TaintedFormatStringCustomizations.qll"
],
"HttpToFileAccessQuery JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessQuery.qll",
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessQuery.qll"
],
"HttpToFileAccessCustomizations JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessCustomizations.qll",
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessCustomizations.qll"
]
}

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* The data flow and taint tracking libraries have been extended with versions of `isBarrierIn`, `isBarrierOut`, and `isBarrierGuard`, respectively `isSanitizerIn`, `isSanitizerOut`, and `isSanitizerGuard`, that support flow states.

View File

@@ -94,7 +94,6 @@ class Type extends Locatable, @type {
* The result of this predicate will be the type itself, except in the case of a TypedefType or a Decltype,
* in which case the result will be type which results from (possibly recursively) resolving typedefs.
*/
pragma[nomagic]
Type getUnderlyingType() { result = this }
/**

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -143,16 +123,6 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -143,16 +123,6 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -143,16 +123,6 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -143,16 +123,6 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -143,16 +123,6 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -12820,221 +12820,6 @@ ir.cpp:
# 1668| Type = [IntType] int
# 1668| ValueCategory = prvalue(load)
# 1670| getStmt(3): [ReturnStmt] return ...
# 1672| [TopLevelFunction] void array_structured_binding_non_ref_init()
# 1672| <params>:
# 1672| getEntryPoint(): [BlockStmt] { ... }
# 1673| getStmt(0): [DeclStmt] declaration
# 1673| getDeclarationEntry(0): [VariableDeclarationEntry] definition of xs
# 1673| Type = [ArrayType] int[2]
# 1673| getVariable().getInitializer(): [Initializer] initializer for xs
# 1673| getExpr(): [ArrayAggregateLiteral] {...}
# 1673| Type = [ArrayType] int[2]
# 1673| ValueCategory = prvalue
# 1673| getElementExpr(0): [Literal] 1
# 1673| Type = [IntType] int
# 1673| Value = [Literal] 1
# 1673| ValueCategory = prvalue
# 1673| getElementExpr(1): [Literal] 2
# 1673| Type = [IntType] int
# 1673| Value = [Literal] 2
# 1673| ValueCategory = prvalue
# 1674| getStmt(1): [DeclStmt] declaration
# 1674| getDeclarationEntry(0): (no string representation)
# 1674| Type = [ArrayType] int[2]
# 1674| getVariable().getInitializer(): [Initializer] initializer for (unnamed local variable)
# 1674| getExpr(): [VariableAccess] xs
# 1674| Type = [ArrayType] int[2]
# 1674| ValueCategory = prvalue(load)
# 1674| getDeclarationEntry(1): [VariableDeclarationEntry] definition of x0
# 1674| Type = [IntType] int
#-----| getVariable().getInitializer(): [Initializer] initializer for x0
#-----| getExpr(): [ArrayExpr] access to array
#-----| Type = [IntType] int
#-----| ValueCategory = lvalue
#-----| getArrayBase(): [VariableAccess] (unnamed local variable)
#-----| Type = [ArrayType] int[2]
#-----| ValueCategory = lvalue
#-----| getArrayOffset(): [Literal] 0
#-----| Type = [LongType] unsigned long
#-----| Value = [Literal] 0
#-----| ValueCategory = prvalue
#-----| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
#-----| Type = [IntPointerType] int *
#-----| ValueCategory = prvalue
# 1674| getDeclarationEntry(2): [VariableDeclarationEntry] definition of x1
# 1674| Type = [IntType] int
#-----| getVariable().getInitializer(): [Initializer] initializer for x1
#-----| getExpr(): [ArrayExpr] access to array
#-----| Type = [IntType] int
#-----| ValueCategory = lvalue
#-----| getArrayBase(): [VariableAccess] (unnamed local variable)
#-----| Type = [ArrayType] int[2]
#-----| ValueCategory = lvalue
#-----| getArrayOffset(): [Literal] 1
#-----| Type = [LongType] unsigned long
#-----| Value = [Literal] 1
#-----| ValueCategory = prvalue
#-----| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
#-----| Type = [IntPointerType] int *
#-----| ValueCategory = prvalue
# 1675| getStmt(2): [ReturnStmt] return ...
# 1677| [CopyAssignmentOperator] CapturedLambdaMyObj& CapturedLambdaMyObj::operator=(CapturedLambdaMyObj const&)
# 1677| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const CapturedLambdaMyObj &
# 1677| [MoveAssignmentOperator] CapturedLambdaMyObj& CapturedLambdaMyObj::operator=(CapturedLambdaMyObj&&)
# 1677| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] CapturedLambdaMyObj &&
# 1677| [CopyConstructor] void CapturedLambdaMyObj::CapturedLambdaMyObj(CapturedLambdaMyObj const&)
# 1677| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const CapturedLambdaMyObj &
# 1677| [MoveConstructor] void CapturedLambdaMyObj::CapturedLambdaMyObj(CapturedLambdaMyObj&&)
# 1677| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] CapturedLambdaMyObj &&
# 1680| [Constructor] void CapturedLambdaMyObj::CapturedLambdaMyObj()
# 1680| <params>:
# 1680| <initializations>:
# 1680| getEntryPoint(): [BlockStmt] { ... }
# 1680| getStmt(0): [ReturnStmt] return ...
# 1683| [TopLevelFunction] void captured_lambda(int, int&, int&&)
# 1683| <params>:
# 1683| getParameter(0): [Parameter] x
# 1683| Type = [IntType] int
# 1683| getParameter(1): [Parameter] y
# 1683| Type = [LValueReferenceType] int &
# 1683| getParameter(2): [Parameter] z
# 1683| Type = [RValueReferenceType] int &&
# 1684| getEntryPoint(): [BlockStmt] { ... }
# 1685| getStmt(0): [DeclStmt] declaration
# 1685| getDeclarationEntry(0): [VariableDeclarationEntry] definition of obj1
# 1685| Type = [LValueReferenceType] const CapturedLambdaMyObj &
# 1685| getVariable().getInitializer(): [Initializer] initializer for obj1
# 1685| getExpr(): [ConstructorCall] call to CapturedLambdaMyObj
# 1685| Type = [VoidType] void
# 1685| ValueCategory = prvalue
# 1685| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
# 1685| Type = [LValueReferenceType] const CapturedLambdaMyObj &
# 1685| ValueCategory = prvalue
# 1685| getExpr(): [CStyleCast] (const CapturedLambdaMyObj)...
# 1685| Conversion = [GlvalueConversion] glvalue conversion
# 1685| Type = [SpecifiedType] const CapturedLambdaMyObj
# 1685| ValueCategory = lvalue
# 1685| getExpr(): [TemporaryObjectExpr] temporary object
# 1685| Type = [Class] CapturedLambdaMyObj
# 1685| ValueCategory = lvalue
# 1686| getStmt(1): [DeclStmt] declaration
# 1686| getDeclarationEntry(0): [VariableDeclarationEntry] definition of obj2
# 1686| Type = [Class] CapturedLambdaMyObj
# 1686| getVariable().getInitializer(): [Initializer] initializer for obj2
# 1686| getExpr(): [ConstructorCall] call to CapturedLambdaMyObj
# 1686| Type = [VoidType] void
# 1686| ValueCategory = prvalue
# 1688| getStmt(2): [DeclStmt] declaration
# 1688| getDeclarationEntry(0): [VariableDeclarationEntry] definition of lambda_outer
# 1688| Type = [Closure,LocalClass] decltype([...](...){...})
# 1688| getVariable().getInitializer(): [Initializer] initializer for lambda_outer
# 1688| getExpr(): [LambdaExpression] [...](...){...}
# 1688| Type = [Closure,LocalClass] decltype([...](...){...})
# 1688| ValueCategory = prvalue
# 1688| getInitializer(): [ClassAggregateLiteral] {...}
# 1688| Type = [Closure,LocalClass] decltype([...](...){...})
# 1688| ValueCategory = prvalue
# 1688| getFieldExpr(obj1): [Literal] Unknown literal
# 1688| Type = [SpecifiedType] const CapturedLambdaMyObj
# 1688| ValueCategory = prvalue
# 1688| getFieldExpr(obj2): [Literal] Unknown literal
# 1688| Type = [Class] CapturedLambdaMyObj
# 1688| ValueCategory = prvalue
# 1688| getFieldExpr(x): [VariableAccess] x
# 1688| Type = [IntType] int
# 1688| ValueCategory = prvalue(load)
# 1688| getFieldExpr(y): [VariableAccess] y
# 1688| Type = [LValueReferenceType] int &
# 1688| ValueCategory = prvalue(load)
# 1688| getFieldExpr(z): [VariableAccess] z
# 1688| Type = [RValueReferenceType] int &&
# 1688| ValueCategory = prvalue(load)
# 1690| getFieldExpr(y).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1690| Type = [IntType] int
# 1690| ValueCategory = prvalue(load)
# 1690| getFieldExpr(z).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1690| Type = [IntType] int
# 1690| ValueCategory = prvalue(load)
# 1691| getStmt(3): [ReturnStmt] return ...
# 1688| [CopyAssignmentOperator] (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)& (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator=((void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25) const&)
# 1688| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const lambda [] type at line 1688, col. 25 &
# 1688| [CopyConstructor] void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::(unnamed constructor)((void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25) const&)
# 1688| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const lambda [] type at line 1688, col. 25 &
# 1688| [MoveConstructor] void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::(unnamed constructor)((void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)&&)
# 1688| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] lambda [] type at line 1688, col. 25 &&
# 1688| [Constructor] void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::(unnamed constructor)()
# 1688| <params>:
# 1688| [ConstMemberFunction] void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const
# 1688| <params>:
# 1688| getEntryPoint(): [BlockStmt] { ... }
# 1689| getStmt(0): [DeclStmt] declaration
# 1689| getDeclarationEntry(0): [VariableDeclarationEntry] definition of lambda_inner
# 1689| Type = [Closure,LocalClass] decltype([...](...){...})
# 1689| getVariable().getInitializer(): [Initializer] initializer for lambda_inner
# 1689| getExpr(): [LambdaExpression] [...](...){...}
# 1689| Type = [Closure,LocalClass] decltype([...](...){...})
# 1689| ValueCategory = prvalue
# 1689| getInitializer(): [ClassAggregateLiteral] {...}
# 1689| Type = [Closure,LocalClass] decltype([...](...){...})
# 1689| ValueCategory = prvalue
# 1689| getFieldExpr(obj1): [Literal] Unknown literal
# 1689| Type = [SpecifiedType] const CapturedLambdaMyObj
# 1689| ValueCategory = prvalue
# 1689| getFieldExpr(obj2): [Literal] Unknown literal
# 1689| Type = [Class] CapturedLambdaMyObj
# 1689| ValueCategory = prvalue
# 1689| getFieldExpr(x): [PointerFieldAccess] x
# 1689| Type = [IntType] int
# 1689| ValueCategory = prvalue(load)
# 1689| getQualifier(): [ThisExpr] this
# 1689| Type = [PointerType] const lambda [] type at line 1688, col. 25 *
# 1689| ValueCategory = prvalue(load)
# 1689| getFieldExpr(y): [PointerFieldAccess] y
# 1689| Type = [IntType] int
# 1689| ValueCategory = prvalue(load)
# 1689| getQualifier(): [ThisExpr] this
# 1689| Type = [PointerType] const lambda [] type at line 1688, col. 25 *
# 1689| ValueCategory = prvalue(load)
# 1689| getFieldExpr(z): [PointerFieldAccess] z
# 1689| Type = [IntType] int
# 1689| ValueCategory = prvalue(load)
# 1689| getQualifier(): [ThisExpr] this
# 1689| Type = [PointerType] const lambda [] type at line 1688, col. 25 *
# 1689| ValueCategory = prvalue(load)
# 1690| getStmt(1): [ReturnStmt] return ...
# 1689| [CopyAssignmentOperator] (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)& (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::operator=((void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29) const&)
# 1689| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const lambda [] type at line 1689, col. 29 &
# 1689| [CopyConstructor] void (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::(unnamed constructor)((void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29) const&)
# 1689| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const lambda [] type at line 1689, col. 29 &
# 1689| [MoveConstructor] void (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::(unnamed constructor)((void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)&&)
# 1689| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] lambda [] type at line 1689, col. 29 &&
# 1689| [Constructor] void (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::(unnamed constructor)()
# 1689| <params>:
# 1689| [ConstMemberFunction] void (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::operator()() const
# 1689| <params>:
# 1689| getEntryPoint(): [BlockStmt] { ... }
# 1689| getStmt(0): [EmptyStmt] ;
# 1689| getStmt(1): [ReturnStmt] return ...
perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| <params>:

View File

@@ -6,8 +6,6 @@ missingOperandType
duplicateChiOperand
sideEffectWithoutPrimary
instructionWithoutSuccessor
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction

View File

@@ -6,8 +6,6 @@ missingOperandType
duplicateChiOperand
sideEffectWithoutPrimary
instructionWithoutSuccessor
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction

View File

@@ -1669,25 +1669,4 @@ void tuple_structured_binding_no_ref_get() {
}
}
void array_structured_binding_non_ref_init() {
int xs[2] = {1, 2};
auto [x0, x1] = xs;
}
class CapturedLambdaMyObj
{
public:
CapturedLambdaMyObj() {}
};
void captured_lambda(int x, int &y, int &&z)
{
const auto &obj1 = CapturedLambdaMyObj();
auto obj2 = CapturedLambdaMyObj();
auto lambda_outer = [obj1, obj2, x, y, z](){
auto lambda_inner = [obj1, obj2, x, y, z](){;};
};
}
// semmle-extractor-options: -std=c++17 --clang

View File

@@ -684,9 +684,7 @@
| file://:0:0:0:0 | ChiTotal | total:m763_8 |
| file://:0:0:0:0 | ChiTotal | total:m1043_10 |
| file://:0:0:0:0 | ChiTotal | total:m1240_4 |
| file://:0:0:0:0 | Left | r0_2 |
| file://:0:0:0:0 | Left | r0_4 |
| file://:0:0:0:0 | Left | r0_7 |
| file://:0:0:0:0 | Left | r0_11 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
@@ -698,9 +696,7 @@
| file://:0:0:0:0 | Load | m1466_4 |
| file://:0:0:0:0 | Load | m1466_4 |
| file://:0:0:0:0 | Load | ~m1444_6 |
| file://:0:0:0:0 | Right | r0_3 |
| file://:0:0:0:0 | Right | r0_5 |
| file://:0:0:0:0 | Right | r0_8 |
| file://:0:0:0:0 | Right | r0_12 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_4 |
@@ -730,15 +726,12 @@
| file://:0:0:0:0 | StoreValue | r0_1 |
| file://:0:0:0:0 | StoreValue | r0_1 |
| file://:0:0:0:0 | StoreValue | r0_3 |
| file://:0:0:0:0 | StoreValue | r0_4 |
| file://:0:0:0:0 | StoreValue | r0_6 |
| file://:0:0:0:0 | StoreValue | r0_9 |
| file://:0:0:0:0 | StoreValue | r0_13 |
| file://:0:0:0:0 | StoreValue | r0_13 |
| file://:0:0:0:0 | StoreValue | r0_22 |
| file://:0:0:0:0 | StoreValue | r0_22 |
| file://:0:0:0:0 | Unary | r0_1 |
| file://:0:0:0:0 | Unary | r0_1 |
| file://:0:0:0:0 | Unary | r0_2 |
| file://:0:0:0:0 | Unary | r0_3 |
| file://:0:0:0:0 | Unary | r0_5 |
@@ -746,7 +739,6 @@
| file://:0:0:0:0 | Unary | r0_6 |
| file://:0:0:0:0 | Unary | r0_6 |
| file://:0:0:0:0 | Unary | r0_6 |
| file://:0:0:0:0 | Unary | r0_6 |
| file://:0:0:0:0 | Unary | r0_7 |
| file://:0:0:0:0 | Unary | r0_7 |
| file://:0:0:0:0 | Unary | r0_7 |
@@ -7444,89 +7436,6 @@
| ir.cpp:1668:17:1668:17 | Load | m1661_14 |
| ir.cpp:1668:17:1668:17 | Load | ~m1666_6 |
| ir.cpp:1668:17:1668:17 | StoreValue | r1668_4 |
| ir.cpp:1672:6:1672:42 | ChiPartial | partial:m1672_3 |
| ir.cpp:1672:6:1672:42 | ChiTotal | total:m1672_2 |
| ir.cpp:1672:6:1672:42 | SideEffect | m1672_3 |
| ir.cpp:1673:9:1673:10 | Address | &:r1673_1 |
| ir.cpp:1673:9:1673:10 | Left | r1673_1 |
| ir.cpp:1673:9:1673:10 | Left | r1673_1 |
| ir.cpp:1673:16:1673:22 | Address | &:r1673_4 |
| ir.cpp:1673:16:1673:22 | Address | &:r1673_9 |
| ir.cpp:1673:16:1673:22 | Right | r1673_3 |
| ir.cpp:1673:16:1673:22 | Right | r1673_8 |
| ir.cpp:1673:18:1673:18 | ChiPartial | partial:m1673_6 |
| ir.cpp:1673:18:1673:18 | ChiTotal | total:m1673_2 |
| ir.cpp:1673:18:1673:18 | StoreValue | r1673_5 |
| ir.cpp:1673:21:1673:21 | ChiPartial | partial:m1673_11 |
| ir.cpp:1673:21:1673:21 | ChiTotal | total:m1673_7 |
| ir.cpp:1673:21:1673:21 | StoreValue | r1673_10 |
| ir.cpp:1674:10:1674:10 | Address | &:r1674_1 |
| ir.cpp:1674:11:1674:11 | Address | &:r1674_5 |
| ir.cpp:1674:15:1674:15 | Address | &:r1674_6 |
| ir.cpp:1674:21:1674:22 | Address | &:r1674_2 |
| ir.cpp:1674:21:1674:22 | Load | m1673_12 |
| ir.cpp:1674:21:1674:22 | StoreValue | r1674_3 |
| ir.cpp:1680:5:1680:23 | Address | &:r1680_5 |
| ir.cpp:1680:5:1680:23 | Address | &:r1680_5 |
| ir.cpp:1680:5:1680:23 | Address | &:r1680_7 |
| ir.cpp:1680:5:1680:23 | Address | &:r1680_7 |
| ir.cpp:1680:5:1680:23 | ChiPartial | partial:m1680_3 |
| ir.cpp:1680:5:1680:23 | ChiTotal | total:m1680_2 |
| ir.cpp:1680:5:1680:23 | Load | m1680_6 |
| ir.cpp:1680:5:1680:23 | SideEffect | m1680_3 |
| ir.cpp:1680:5:1680:23 | SideEffect | m1680_8 |
| ir.cpp:1683:6:1683:20 | ChiPartial | partial:m1683_3 |
| ir.cpp:1683:6:1683:20 | ChiTotal | total:m1683_2 |
| ir.cpp:1683:26:1683:26 | Address | &:r1683_5 |
| ir.cpp:1683:34:1683:34 | Address | &:r1683_7 |
| ir.cpp:1683:34:1683:34 | Address | &:r1683_7 |
| ir.cpp:1683:34:1683:34 | Address | &:r1683_9 |
| ir.cpp:1683:34:1683:34 | Load | m1683_8 |
| ir.cpp:1683:43:1683:43 | Address | &:r1683_11 |
| ir.cpp:1683:43:1683:43 | Address | &:r1683_11 |
| ir.cpp:1683:43:1683:43 | Address | &:r1683_13 |
| ir.cpp:1683:43:1683:43 | Load | m1683_12 |
| ir.cpp:1685:17:1685:20 | Address | &:r1685_1 |
| ir.cpp:1685:24:1685:44 | Address | &:r1685_2 |
| ir.cpp:1685:24:1685:44 | Address | &:r1685_2 |
| ir.cpp:1685:24:1685:44 | Arg(this) | this:r1685_2 |
| ir.cpp:1685:24:1685:44 | CallTarget | func:r1685_4 |
| ir.cpp:1685:24:1685:44 | ChiPartial | partial:m1685_6 |
| ir.cpp:1685:24:1685:44 | ChiPartial | partial:m1685_8 |
| ir.cpp:1685:24:1685:44 | ChiTotal | total:m1683_4 |
| ir.cpp:1685:24:1685:44 | ChiTotal | total:m1685_3 |
| ir.cpp:1685:24:1685:44 | SideEffect | ~m1683_4 |
| ir.cpp:1685:24:1685:44 | StoreValue | r1685_11 |
| ir.cpp:1685:24:1685:44 | Unary | r1685_2 |
| ir.cpp:1685:24:1685:44 | Unary | r1685_10 |
| ir.cpp:1686:10:1686:13 | Address | &:r1686_1 |
| ir.cpp:1686:10:1686:13 | Address | &:r1686_1 |
| ir.cpp:1686:10:1686:13 | Arg(this) | this:r1686_1 |
| ir.cpp:1686:16:1686:37 | CallTarget | func:r1686_3 |
| ir.cpp:1686:16:1686:37 | ChiPartial | partial:m1686_5 |
| ir.cpp:1686:16:1686:37 | ChiPartial | partial:m1686_7 |
| ir.cpp:1686:16:1686:37 | ChiTotal | total:m1685_7 |
| ir.cpp:1686:16:1686:37 | ChiTotal | total:m1686_2 |
| ir.cpp:1686:16:1686:37 | SideEffect | ~m1685_7 |
| ir.cpp:1688:24:1690:5 | Address | &:r1688_2 |
| ir.cpp:1688:24:1690:5 | Unary | r1688_2 |
| ir.cpp:1688:46:1688:46 | Address | &:r1688_5 |
| ir.cpp:1688:46:1688:46 | Address | &:r1688_5 |
| ir.cpp:1688:46:1688:46 | Address | &:r1688_7 |
| ir.cpp:1688:46:1688:46 | ChiPartial | partial:m1688_3 |
| ir.cpp:1688:46:1688:46 | ChiTotal | total:m1688_2 |
| ir.cpp:1688:46:1688:46 | Load | m1688_6 |
| ir.cpp:1689:28:1689:54 | Address | &:r1689_2 |
| ir.cpp:1689:28:1689:54 | Unary | r1689_2 |
| ir.cpp:1689:50:1689:50 | Address | &:r1689_5 |
| ir.cpp:1689:50:1689:50 | Address | &:r1689_5 |
| ir.cpp:1689:50:1689:50 | Address | &:r1689_7 |
| ir.cpp:1689:50:1689:50 | Address | &:r1689_7 |
| ir.cpp:1689:50:1689:50 | ChiPartial | partial:m1689_3 |
| ir.cpp:1689:50:1689:50 | ChiTotal | total:m1689_2 |
| ir.cpp:1689:50:1689:50 | Load | m1689_6 |
| ir.cpp:1689:50:1689:50 | SideEffect | m1689_3 |
| ir.cpp:1689:50:1689:50 | SideEffect | m1689_8 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_7 |

View File

@@ -1,8 +1,4 @@
missingOperand
| ir.cpp:1688:24:1690:5 | Store: Unknown literal | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | Store: Unknown literal | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1689:28:1689:54 | Store: Unknown literal | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | Store: Unknown literal | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
unexpectedOperand
duplicateOperand
missingPhiOperand
@@ -11,10 +7,6 @@ duplicateChiOperand
sideEffectWithoutPrimary
instructionWithoutSuccessor
| ../../../include/memory.h:68:25:68:33 | CopyValue: (reference to) | Instruction 'CopyValue: (reference to)' has no successors in function '$@'. | ../../../include/memory.h:67:5:67:5 | void std::unique_ptr<int, std::default_delete<int>>::~unique_ptr() | void std::unique_ptr<int, std::default_delete<int>>::~unique_ptr() |
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction
@@ -26,25 +18,6 @@ lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
| ir.cpp:1486:8:1486:8 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1486:8:1486:8 | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() |
| ir.cpp:1683:34:1683:34 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1683:43:1683:43 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:10:1688:21 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:46:1688:46 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:14:1689:25 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
switchInstructionWithoutDefaultEdge
notMarkedAsConflated
wronglyMarkedAsConflated

View File

@@ -8664,184 +8664,6 @@ ir.cpp:
# 1645| v1645_5(void) = AliasedUse : ~m?
# 1645| v1645_6(void) = ExitFunction :
# 1672| void array_structured_binding_non_ref_init()
# 1672| Block 0
# 1672| v1672_1(void) = EnterFunction :
# 1672| mu1672_2(unknown) = AliasedDefinition :
# 1672| mu1672_3(unknown) = InitializeNonLocal :
# 1673| r1673_1(glval<int[2]>) = VariableAddress[xs] :
# 1673| mu1673_2(int[2]) = Uninitialized[xs] : &:r1673_1
# 1673| r1673_3(int) = Constant[0] :
# 1673| r1673_4(glval<int>) = PointerAdd[4] : r1673_1, r1673_3
# 1673| r1673_5(int) = Constant[1] :
# 1673| mu1673_6(int) = Store[?] : &:r1673_4, r1673_5
# 1673| r1673_7(int) = Constant[1] :
# 1673| r1673_8(glval<int>) = PointerAdd[4] : r1673_1, r1673_7
# 1673| r1673_9(int) = Constant[2] :
# 1673| mu1673_10(int) = Store[?] : &:r1673_8, r1673_9
# 1674| r1674_1(glval<int[2]>) = VariableAddress[(unnamed local variable)] :
# 1674| r1674_2(glval<int[2]>) = VariableAddress[xs] :
# 1674| r1674_3(int[2]) = Load[xs] : &:r1674_2, ~m?
# 1674| mu1674_4(int[2]) = Store[(unnamed local variable)] : &:r1674_1, r1674_3
# 1674| r1674_5(glval<int &>) = VariableAddress[x0] :
#-----| r0_1(glval<int[2]>) = VariableAddress[(unnamed local variable)] :
#-----| r0_2(int *) = Convert : r0_1
#-----| r0_3(unsigned long) = Constant[0] :
#-----| r0_4(glval<int>) = PointerAdd[4] : r0_2, r0_3
#-----| mu0_5(int &) = Store[x0] : &:r1674_5, r0_4
# 1674| r1674_6(glval<int &>) = VariableAddress[x1] :
#-----| r0_6(glval<int[2]>) = VariableAddress[(unnamed local variable)] :
#-----| r0_7(int *) = Convert : r0_6
#-----| r0_8(unsigned long) = Constant[1] :
#-----| r0_9(glval<int>) = PointerAdd[4] : r0_7, r0_8
#-----| mu0_10(int &) = Store[x1] : &:r1674_6, r0_9
# 1675| v1675_1(void) = NoOp :
# 1672| v1672_4(void) = ReturnVoid :
# 1672| v1672_5(void) = AliasedUse : ~m?
# 1672| v1672_6(void) = ExitFunction :
# 1680| void CapturedLambdaMyObj::CapturedLambdaMyObj()
# 1680| Block 0
# 1680| v1680_1(void) = EnterFunction :
# 1680| mu1680_2(unknown) = AliasedDefinition :
# 1680| mu1680_3(unknown) = InitializeNonLocal :
# 1680| r1680_4(glval<unknown>) = VariableAddress[#this] :
# 1680| mu1680_5(glval<CapturedLambdaMyObj>) = InitializeParameter[#this] : &:r1680_4
# 1680| r1680_6(glval<CapturedLambdaMyObj>) = Load[#this] : &:r1680_4, ~m?
# 1680| mu1680_7(CapturedLambdaMyObj) = InitializeIndirection[#this] : &:r1680_6
# 1680| v1680_8(void) = NoOp :
# 1680| v1680_9(void) = ReturnIndirection[#this] : &:r1680_6, ~m?
# 1680| v1680_10(void) = ReturnVoid :
# 1680| v1680_11(void) = AliasedUse : ~m?
# 1680| v1680_12(void) = ExitFunction :
# 1683| void captured_lambda(int, int&, int&&)
# 1683| Block 0
# 1683| v1683_1(void) = EnterFunction :
# 1683| mu1683_2(unknown) = AliasedDefinition :
# 1683| mu1683_3(unknown) = InitializeNonLocal :
# 1683| r1683_4(glval<int>) = VariableAddress[x] :
# 1683| mu1683_5(int) = InitializeParameter[x] : &:r1683_4
# 1683| r1683_6(glval<int &>) = VariableAddress[y] :
# 1683| mu1683_7(int &) = InitializeParameter[y] : &:r1683_6
# 1683| r1683_8(int &) = Load[y] : &:r1683_6, ~m?
# 1683| mu1683_9(unknown) = InitializeIndirection[y] : &:r1683_8
# 1683| r1683_10(glval<int &&>) = VariableAddress[z] :
# 1683| mu1683_11(int &&) = InitializeParameter[z] : &:r1683_10
# 1683| r1683_12(int &&) = Load[z] : &:r1683_10, ~m?
# 1683| mu1683_13(unknown) = InitializeIndirection[z] : &:r1683_12
# 1685| r1685_1(glval<CapturedLambdaMyObj &>) = VariableAddress[obj1] :
# 1685| r1685_2(glval<CapturedLambdaMyObj>) = VariableAddress[#temp1685:24] :
# 1685| mu1685_3(CapturedLambdaMyObj) = Uninitialized[#temp1685:24] : &:r1685_2
# 1685| r1685_4(glval<unknown>) = FunctionAddress[CapturedLambdaMyObj] :
# 1685| v1685_5(void) = Call[CapturedLambdaMyObj] : func:r1685_4, this:r1685_2
# 1685| mu1685_6(unknown) = ^CallSideEffect : ~m?
# 1685| mu1685_7(CapturedLambdaMyObj) = ^IndirectMayWriteSideEffect[-1] : &:r1685_2
# 1685| r1685_8(glval<CapturedLambdaMyObj>) = Convert : r1685_2
# 1685| r1685_9(CapturedLambdaMyObj &) = CopyValue : r1685_8
# 1685| mu1685_10(CapturedLambdaMyObj &) = Store[obj1] : &:r1685_1, r1685_9
# 1686| r1686_1(glval<CapturedLambdaMyObj>) = VariableAddress[obj2] :
# 1686| mu1686_2(CapturedLambdaMyObj) = Uninitialized[obj2] : &:r1686_1
# 1686| r1686_3(glval<unknown>) = FunctionAddress[CapturedLambdaMyObj] :
# 1686| v1686_4(void) = Call[CapturedLambdaMyObj] : func:r1686_3, this:r1686_1
# 1686| mu1686_5(unknown) = ^CallSideEffect : ~m?
# 1686| mu1686_6(CapturedLambdaMyObj) = ^IndirectMayWriteSideEffect[-1] : &:r1686_1
# 1688| r1688_1(glval<decltype([...](...){...})>) = VariableAddress[lambda_outer] :
# 1688| r1688_2(glval<decltype([...](...){...})>) = VariableAddress[#temp1688:24] :
# 1688| mu1688_3(decltype([...](...){...})) = Uninitialized[#temp1688:24] : &:r1688_2
# 1688| r1688_4(glval<CapturedLambdaMyObj>) = FieldAddress[obj1] : r1688_2
# 1688| Block 1
# 1688| mu1688_5(CapturedLambdaMyObj) = Store[?] : &:r1688_4
# 1688| r1688_6(glval<CapturedLambdaMyObj>) = FieldAddress[obj2] : r1688_2
# 1688| Block 2
# 1688| mu1688_7(CapturedLambdaMyObj) = Store[?] : &:r1688_6
# 1688| r1688_8(glval<int>) = FieldAddress[x] : r1688_2
# 1688| r1688_9(glval<int>) = VariableAddress[x] :
# 1688| r1688_10(int) = Load[x] : &:r1688_9, ~m?
# 1688| mu1688_11(int) = Store[?] : &:r1688_8, r1688_10
# 1688| r1688_12(glval<int>) = FieldAddress[y] : r1688_2
# 1688| r1688_13(glval<int &>) = VariableAddress[y] :
# 1688| r1688_14(int &) = Load[y] : &:r1688_13, ~m?
# 1690| r1690_1(int) = Load[?] : &:r1688_14, ~m?
# 1690| mu1690_2(int) = Store[?] : &:r1688_12, r1690_1
# 1688| r1688_15(glval<int>) = FieldAddress[z] : r1688_2
# 1688| r1688_16(glval<int &&>) = VariableAddress[z] :
# 1688| r1688_17(int &&) = Load[z] : &:r1688_16, ~m?
# 1690| r1690_3(int) = Load[?] : &:r1688_17, ~m?
# 1690| mu1690_4(int) = Store[?] : &:r1688_15, r1690_3
# 1688| r1688_18(decltype([...](...){...})) = Load[#temp1688:24] : &:r1688_2, ~m?
# 1688| mu1688_19(decltype([...](...){...})) = Store[lambda_outer] : &:r1688_1, r1688_18
# 1691| v1691_1(void) = NoOp :
# 1683| v1683_14(void) = ReturnIndirection[y] : &:r1683_8, ~m?
# 1683| v1683_15(void) = ReturnIndirection[z] : &:r1683_12, ~m?
# 1683| v1683_16(void) = ReturnVoid :
# 1683| v1683_17(void) = AliasedUse : ~m?
# 1683| v1683_18(void) = ExitFunction :
# 1688| void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const
# 1688| Block 0
# 1688| v1688_1(void) = EnterFunction :
# 1688| mu1688_2(unknown) = AliasedDefinition :
# 1688| mu1688_3(unknown) = InitializeNonLocal :
# 1688| r1688_4(glval<unknown>) = VariableAddress[#this] :
# 1688| mu1688_5(glval<decltype([...](...){...})>) = InitializeParameter[#this] : &:r1688_4
# 1688| r1688_6(glval<decltype([...](...){...})>) = Load[#this] : &:r1688_4, ~m?
# 1688| mu1688_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1688_6
# 1689| r1689_1(glval<decltype([...](...){...})>) = VariableAddress[lambda_inner] :
# 1689| r1689_2(glval<decltype([...](...){...})>) = VariableAddress[#temp1689:28] :
# 1689| mu1689_3(decltype([...](...){...})) = Uninitialized[#temp1689:28] : &:r1689_2
# 1689| r1689_4(glval<CapturedLambdaMyObj>) = FieldAddress[obj1] : r1689_2
# 1689| Block 1
# 1689| mu1689_5(CapturedLambdaMyObj) = Store[?] : &:r1689_4
# 1689| r1689_6(glval<CapturedLambdaMyObj>) = FieldAddress[obj2] : r1689_2
# 1689| Block 2
# 1689| mu1689_7(CapturedLambdaMyObj) = Store[?] : &:r1689_6
# 1689| r1689_8(glval<int>) = FieldAddress[x] : r1689_2
# 1689| r1689_9(glval<unknown>) = VariableAddress[#this] :
# 1689| r1689_10(lambda [] type at line 1688, col. 25 *) = Load[#this] : &:r1689_9, ~m?
# 1689| r1689_11(glval<int>) = FieldAddress[x] : r1689_10
# 1689| r1689_12(int) = Load[?] : &:r1689_11, ~m?
# 1689| mu1689_13(int) = Store[?] : &:r1689_8, r1689_12
# 1689| r1689_14(glval<int>) = FieldAddress[y] : r1689_2
# 1689| r1689_15(glval<unknown>) = VariableAddress[#this] :
# 1689| r1689_16(lambda [] type at line 1688, col. 25 *) = Load[#this] : &:r1689_15, ~m?
# 1689| r1689_17(glval<int>) = FieldAddress[y] : r1689_16
# 1689| r1689_18(int) = Load[?] : &:r1689_17, ~m?
# 1689| mu1689_19(int) = Store[?] : &:r1689_14, r1689_18
# 1689| r1689_20(glval<int>) = FieldAddress[z] : r1689_2
# 1689| r1689_21(glval<unknown>) = VariableAddress[#this] :
# 1689| r1689_22(lambda [] type at line 1688, col. 25 *) = Load[#this] : &:r1689_21, ~m?
# 1689| r1689_23(glval<int>) = FieldAddress[z] : r1689_22
# 1689| r1689_24(int) = Load[?] : &:r1689_23, ~m?
# 1689| mu1689_25(int) = Store[?] : &:r1689_20, r1689_24
# 1689| r1689_26(decltype([...](...){...})) = Load[#temp1689:28] : &:r1689_2, ~m?
# 1689| mu1689_27(decltype([...](...){...})) = Store[lambda_inner] : &:r1689_1, r1689_26
# 1690| v1690_1(void) = NoOp :
# 1688| v1688_8(void) = ReturnIndirection[#this] : &:r1688_6, ~m?
# 1688| v1688_9(void) = ReturnVoid :
# 1688| v1688_10(void) = AliasedUse : ~m?
# 1688| v1688_11(void) = ExitFunction :
# 1689| void (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::operator()() const
# 1689| Block 0
# 1689| v1689_1(void) = EnterFunction :
# 1689| mu1689_2(unknown) = AliasedDefinition :
# 1689| mu1689_3(unknown) = InitializeNonLocal :
# 1689| r1689_4(glval<unknown>) = VariableAddress[#this] :
# 1689| mu1689_5(glval<decltype([...](...){...})>) = InitializeParameter[#this] : &:r1689_4
# 1689| r1689_6(glval<decltype([...](...){...})>) = Load[#this] : &:r1689_4, ~m?
# 1689| mu1689_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1689_6
# 1689| v1689_8(void) = NoOp :
# 1689| v1689_9(void) = NoOp :
# 1689| v1689_10(void) = ReturnIndirection[#this] : &:r1689_6, ~m?
# 1689| v1689_11(void) = ReturnVoid :
# 1689| v1689_12(void) = AliasedUse : ~m?
# 1689| v1689_13(void) = ExitFunction :
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0

View File

@@ -6,8 +6,6 @@ missingOperandType
duplicateChiOperand
sideEffectWithoutPrimary
instructionWithoutSuccessor
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction

View File

@@ -6,8 +6,6 @@ missingOperandType
duplicateChiOperand
sideEffectWithoutPrimary
instructionWithoutSuccessor
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction

View File

@@ -35,41 +35,6 @@ edges
| test.cpp:142:11:142:17 | sprintf output argument | test.cpp:143:10:143:16 | command indirection |
| test.cpp:142:31:142:33 | str indirection | test.cpp:142:11:142:17 | sprintf output argument |
| test.cpp:142:31:142:33 | str indirection | test.cpp:142:11:142:17 | sprintf output argument |
| test.cpp:174:9:174:16 | fread output argument | test.cpp:177:20:177:27 | filename indirection |
| test.cpp:174:9:174:16 | fread output argument | test.cpp:178:22:178:26 | flags indirection |
| test.cpp:174:9:174:16 | fread output argument | test.cpp:180:22:180:29 | filename indirection |
| test.cpp:177:13:177:17 | strncat output argument | test.cpp:183:32:183:38 | command indirection |
| test.cpp:177:20:177:27 | filename indirection | test.cpp:177:13:177:17 | strncat output argument |
| test.cpp:177:20:177:27 | filename indirection | test.cpp:177:13:177:17 | strncat output argument |
| test.cpp:178:13:178:19 | strncat output argument | test.cpp:183:32:183:38 | command indirection |
| test.cpp:178:22:178:26 | flags indirection | test.cpp:178:13:178:19 | strncat output argument |
| test.cpp:178:22:178:26 | flags indirection | test.cpp:178:13:178:19 | strncat output argument |
| test.cpp:180:13:180:19 | strncat output argument | test.cpp:183:32:183:38 | command indirection |
| test.cpp:180:22:180:29 | filename indirection | test.cpp:180:13:180:19 | strncat output argument |
| test.cpp:180:22:180:29 | filename indirection | test.cpp:180:13:180:19 | strncat output argument |
| test.cpp:186:47:186:54 | *filename | test.cpp:187:18:187:25 | filename indirection |
| test.cpp:186:47:186:54 | *filename | test.cpp:188:20:188:24 | flags indirection |
| test.cpp:186:47:186:54 | filename | test.cpp:187:18:187:25 | filename indirection |
| test.cpp:186:47:186:54 | filename | test.cpp:188:20:188:24 | flags indirection |
| test.cpp:187:11:187:15 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:187:11:187:15 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:187:18:187:25 | filename indirection | test.cpp:187:11:187:15 | strncat output argument |
| test.cpp:187:18:187:25 | filename indirection | test.cpp:187:11:187:15 | strncat output argument |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:205:10:205:16 | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:205:10:205:16 | command [post update] |
| test.cpp:188:11:188:17 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:11:188:17 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:20:188:24 | flags indirection | test.cpp:188:11:188:17 | strncat output argument |
| test.cpp:188:20:188:24 | flags indirection | test.cpp:188:11:188:17 | strncat output argument |
| test.cpp:194:9:194:16 | fread output argument | test.cpp:196:26:196:33 | filename |
| test.cpp:194:9:194:16 | fread output argument | test.cpp:196:26:196:33 | filename indirection |
| test.cpp:196:10:196:16 | command [post update] | test.cpp:198:32:198:38 | command indirection |
| test.cpp:196:26:196:33 | filename | test.cpp:186:47:186:54 | filename |
| test.cpp:196:26:196:33 | filename indirection | test.cpp:186:47:186:54 | *filename |
| test.cpp:205:10:205:16 | command [post update] | test.cpp:207:32:207:38 | command indirection |
nodes
| test.cpp:16:20:16:23 | argv | semmle.label | argv |
| test.cpp:22:13:22:20 | sprintf output argument | semmle.label | sprintf output argument |
@@ -107,29 +72,6 @@ nodes
| test.cpp:142:11:142:17 | sprintf output argument | semmle.label | sprintf output argument |
| test.cpp:142:31:142:33 | str indirection | semmle.label | str indirection |
| test.cpp:143:10:143:16 | command indirection | semmle.label | command indirection |
| test.cpp:174:9:174:16 | fread output argument | semmle.label | fread output argument |
| test.cpp:177:13:177:17 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:177:20:177:27 | filename indirection | semmle.label | filename indirection |
| test.cpp:178:13:178:19 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:178:22:178:26 | flags indirection | semmle.label | flags indirection |
| test.cpp:180:13:180:19 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:180:22:180:29 | filename indirection | semmle.label | filename indirection |
| test.cpp:183:32:183:38 | command indirection | semmle.label | command indirection |
| test.cpp:186:47:186:54 | *filename | semmle.label | *filename |
| test.cpp:186:47:186:54 | filename | semmle.label | filename |
| test.cpp:187:11:187:15 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:187:18:187:25 | filename indirection | semmle.label | filename indirection |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:188:20:188:24 | flags indirection | semmle.label | flags indirection |
| test.cpp:194:9:194:16 | fread output argument | semmle.label | fread output argument |
| test.cpp:196:10:196:16 | command [post update] | semmle.label | command [post update] |
| test.cpp:196:26:196:33 | filename | semmle.label | filename |
| test.cpp:196:26:196:33 | filename indirection | semmle.label | filename indirection |
| test.cpp:198:32:198:38 | command indirection | semmle.label | command indirection |
| test.cpp:205:10:205:16 | command [post update] | semmle.label | command [post update] |
| test.cpp:207:32:207:38 | command indirection | semmle.label | command indirection |
subpaths
#select
| test.cpp:23:12:23:19 | command1 | test.cpp:16:20:16:23 | argv | test.cpp:23:12:23:19 | command1 indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:16:20:16:23 | argv | user input (a command-line argument) | test.cpp:22:13:22:20 | sprintf output argument | sprintf output argument |
@@ -141,10 +83,3 @@ subpaths
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:25 | call to getenv | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:113:20:113:25 | call to getenv | user input (an environment variable) | test.cpp:114:17:114:17 | Call | Call |
| test.cpp:120:25:120:28 | call to data | test.cpp:119:20:119:25 | call to getenv | test.cpp:120:10:120:30 | call to data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:119:20:119:25 | call to getenv | user input (an environment variable) | test.cpp:120:17:120:17 | Call | Call |
| test.cpp:143:10:143:16 | command | test.cpp:140:9:140:11 | fread output argument | test.cpp:143:10:143:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:140:9:140:11 | fread output argument | user input (String read by fread) | test.cpp:142:11:142:17 | sprintf output argument | sprintf output argument |
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:174:9:174:16 | fread output argument | user input (String read by fread) | test.cpp:177:13:177:17 | strncat output argument | strncat output argument |
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:174:9:174:16 | fread output argument | user input (String read by fread) | test.cpp:178:13:178:19 | strncat output argument | strncat output argument |
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:174:9:174:16 | fread output argument | user input (String read by fread) | test.cpp:180:13:180:19 | strncat output argument | strncat output argument |
| test.cpp:198:32:198:38 | command | test.cpp:194:9:194:16 | fread output argument | test.cpp:198:32:198:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:194:9:194:16 | fread output argument | user input (String read by fread) | test.cpp:187:11:187:15 | strncat output argument | strncat output argument |
| test.cpp:198:32:198:38 | command | test.cpp:194:9:194:16 | fread output argument | test.cpp:198:32:198:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:194:9:194:16 | fread output argument | user input (String read by fread) | test.cpp:188:11:188:17 | strncat output argument | strncat output argument |
| test.cpp:207:32:207:38 | command | test.cpp:194:9:194:16 | fread output argument | test.cpp:207:32:207:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:194:9:194:16 | fread output argument | user input (String read by fread) | test.cpp:187:11:187:15 | strncat output argument | strncat output argument |
| test.cpp:207:32:207:38 | command | test.cpp:194:9:194:16 | fread output argument | test.cpp:207:32:207:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:194:9:194:16 | fread output argument | user input (String read by fread) | test.cpp:188:11:188:17 | strncat output argument | strncat output argument |

View File

@@ -168,43 +168,7 @@ void test15(FILE *f) {
system(command); // GOOD: the user string was converted to an integer and back
}
void test16(FILE *f, bool use_flags) {
// BAD: the user string is injected directly into a command
char command[1000] = "mv ", flags[1000] = "-R", filename[1000];
fread(filename, 1, 1000, f);
if (use_flags) {
strncat(flags, filename, 1000);
strncat(command, flags, 1000);
} else {
strncat(command, filename, 1000);
}
execl("/bin/sh", "sh", "-c", command);
}
void concat(char *command, char *flags, char *filename) {
strncat(flags, filename, 1000);
strncat(command, flags, 1000);
}
void test17(FILE *f) {
// BAD: the user string is injected directly into a command
char command[1000] = "mv ", flags[1000] = "-R", filename[1000];
fread(filename, 1, 1000, f);
concat(command, flags, filename);
execl("/bin/sh", "sh", "-c", command);
}
void test18() {
// GOOD [FALSE POSITIVE]
char command[1000] = "ls ", flags[1000] = "-l", filename[1000] = ".";
concat(command, flags, filename);
execl("/bin/sh", "sh", "-c", command);
}
// TODO: test for call context sensitivity at concatenation site
// open question: do we want to report certain sources even when they're the start of the string?

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* The data flow and taint tracking libraries have been extended with versions of `isBarrierIn`, `isBarrierOut`, and `isBarrierGuard`, respectively `isSanitizerIn`, `isSanitizerOut`, and `isSanitizerGuard`, that support flow states.

View File

@@ -105,12 +105,31 @@ private module ConstantComparisonOperation {
}
}
private class StructuralComparisonConfig extends StructuralComparison::StructuralComparisonConfiguration {
StructuralComparisonConfig() { this = "CompareIdenticalValues" }
override predicate candidate(ControlFlowElement x, ControlFlowElement y) {
exists(ComparisonTest ct |
x = ct.getFirstArgument() and
y = ct.getSecondArgument()
)
}
ComparisonTest getComparisonTest() {
exists(Element x, Element y |
result.getFirstArgument() = x and
result.getSecondArgument() = y and
same(x, y)
)
}
}
/**
* Holds if comparison test `ct` compares two structurally identical
* expressions.
*/
predicate comparesIdenticalValues(ComparisonTest ct) {
StructuralComparison::sameGvn(ct.getFirstArgument(), ct.getSecondArgument())
ct = any(StructuralComparisonConfig c).getComparisonTest()
}
/**

View File

@@ -192,18 +192,13 @@ private import Cached
predicate toGvn = toGvnCached/1;
/**
* Holds if the control flow elements `x` and `y` are structurally equal.
*/
pragma[inline]
predicate sameGvn(ControlFlowElement x, ControlFlowElement y) {
private predicate sameGvn(ControlFlowElement x, ControlFlowElement y) {
pragma[only_bind_into](toGvn(pragma[only_bind_out](x))) =
pragma[only_bind_into](toGvn(pragma[only_bind_out](y)))
}
/**
* DEPRECATED: Use `sameGvn` instead.
*
* A configuration for performing structural comparisons of program elements
* (expressions and statements).
*
@@ -212,7 +207,7 @@ predicate sameGvn(ControlFlowElement x, ControlFlowElement y) {
*
* Each use of the library is identified by a unique string value.
*/
abstract deprecated class StructuralComparisonConfiguration extends string {
abstract class StructuralComparisonConfiguration extends string {
bindingset[this]
StructuralComparisonConfiguration() { any() }
@@ -240,3 +235,55 @@ abstract deprecated class StructuralComparisonConfiguration extends string {
*/
predicate same(ControlFlowElement x, ControlFlowElement y) { candidate(x, y) and sameGvn(x, y) }
}
/**
* INTERNAL: Do not use.
*
* A verbatim copy of the class `StructuralComparisonConfiguration` for internal
* use.
*
* A copy is needed in order to use structural comparison within the standard
* library without running into caching issues.
*/
module Internal {
// Import all uses of the internal library to make sure caching works
private import semmle.code.csharp.controlflow.Guards as G
/**
* A configuration for performing structural comparisons of program elements
* (expressions and statements).
*
* The predicate `candidate()` must be overridden, in order to identify the
* elements for which to perform structural comparison.
*
* Each use of the library is identified by a unique string value.
*/
abstract class InternalStructuralComparisonConfiguration extends string {
bindingset[this]
InternalStructuralComparisonConfiguration() { any() }
/**
* Holds if elements `x` and `y` are candidates for testing structural
* equality.
*
* Subclasses are expected to override this predicate to identify the
* top-level elements which they want to compare. Care should be
* taken to avoid identifying too many pairs of elements, as in general
* there are very many structurally equal subtrees in a program, and
* in order to keep the computation feasible we must focus attention.
*
* Note that this relation is not expected to be symmetric -- it's
* fine to include a pair `(x, y)` but not `(y, x)`.
* In fact, not including the symmetrically implied fact will save
* half the computation time on the structural comparison.
*/
abstract predicate candidate(ControlFlowElement x, ControlFlowElement y);
/**
* Holds if elements `x` and `y` structurally equal. `x` and `y` must be
* flagged as candidates for structural equality, that is,
* `candidate(x, y)` must hold.
*/
predicate same(ControlFlowElement x, ControlFlowElement y) { candidate(x, y) and sameGvn(x, y) }
}
}

View File

@@ -8,7 +8,7 @@ private import dotnet
private import ControlFlow::SuccessorTypes
private import semmle.code.csharp.commons.Assertions
private import semmle.code.csharp.commons.ComparisonTest
private import semmle.code.csharp.commons.StructuralComparison as SC
private import semmle.code.csharp.commons.StructuralComparison::Internal
private import semmle.code.csharp.controlflow.BasicBlocks
private import semmle.code.csharp.controlflow.internal.Completion
private import semmle.code.csharp.frameworks.System
@@ -1798,30 +1798,32 @@ module Internal {
}
/**
* Holds if access/call expression `e` (targeting declaration `target`)
* is a sub expression of a guard that controls whether basic block
* `bb` is reached.
* A helper class for calculating structurally equal access/call expressions.
*/
pragma[noinline]
private predicate candidateAux(AccessOrCallExpr e, Declaration target, BasicBlock bb) {
target = e.getTarget() and
guardControlsSub(_, bb, e)
}
private class ConditionOnExprComparisonConfig extends InternalStructuralComparisonConfiguration {
ConditionOnExprComparisonConfig() { this = "ConditionOnExprComparisonConfig" }
private predicate candidate(AccessOrCallExpr x, AccessOrCallExpr y) {
exists(BasicBlock bb, Declaration d |
candidateAux(x, d, bb) and
y =
any(AccessOrCallExpr e |
e.getAControlFlowNode().getBasicBlock() = bb and
e.getTarget() = d
)
)
}
override predicate candidate(ControlFlowElement x, ControlFlowElement y) {
exists(BasicBlock bb, Declaration d |
this.candidateAux(x, d, bb) and
y =
any(AccessOrCallExpr e |
e.getAControlFlowNode().getBasicBlock() = bb and
e.getTarget() = d
)
)
}
private predicate same(AccessOrCallExpr x, AccessOrCallExpr y) {
candidate(x, y) and
SC::sameGvn(x, y)
/**
* Holds if access/call expression `e` (targeting declaration `target`)
* is a sub expression of a guard that controls whether basic block
* `bb` is reached.
*/
pragma[noinline]
private predicate candidateAux(AccessOrCallExpr e, Declaration target, BasicBlock bb) {
target = e.getTarget() and
guardControlsSub(_, bb, e)
}
}
cached
@@ -1847,7 +1849,7 @@ module Internal {
pragma[nomagic]
private predicate guardControlsSubSame(Guard g, BasicBlock bb, ControlGuardDescendant sub) {
guardControlsSub(g, bb, sub) and
same(sub, _)
any(ConditionOnExprComparisonConfig c).same(sub, _)
}
pragma[nomagic]
@@ -1860,7 +1862,7 @@ module Internal {
guardedBB = guardedCfn.getBasicBlock() and
guardControls(g, guardedBB, v) and
guardControlsSubSame(g, guardedBB, sub) and
same(sub, guarded)
any(ConditionOnExprComparisonConfig c).same(sub, guarded)
}
pragma[nomagic]

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -2031,47 +2031,3 @@ abstract class SyntheticField extends string {
* Holds if the the content `c` is a container.
*/
predicate containerContent(DataFlow::Content c) { c instanceof DataFlow::ElementContent }
/**
* A module containing predicates related to generating models as data.
*/
module Csv {
private string parameterQualifiedTypeNamesToString(DataFlowCallable c) {
result =
concat(Parameter p, int i |
p = c.getParameter(i)
|
p.getType().getQualifiedName(), "," order by i
)
}
/** Holds if the summary should apply for all overrides of `c`. */
predicate isBaseCallableOrPrototype(DataFlowCallable c) {
c.getDeclaringType() instanceof Interface
or
exists(Modifiable m | m = [c.(Modifiable), c.(Accessor).getDeclaration()] |
m.isAbstract()
or
c.getDeclaringType().(Modifiable).isAbstract() and m.(Virtualizable).isVirtual()
)
}
/** Gets a string representing whether the summary should apply for all overrides of `c`. */
private string getCallableOverride(DataFlowCallable c) {
if isBaseCallableOrPrototype(c) then result = "true" else result = "false"
}
/** Computes the first 6 columns for CSV rows of `c`. */
string asPartialModel(DataFlowCallable c) {
exists(string namespace, string type |
c.getDeclaringType().hasQualifiedName(namespace, type) and
result =
namespace + ";" //
+ type + ";" //
+ getCallableOverride(c) + ";" //
+ c.getName() + ";" //
+ "(" + parameterQualifiedTypeNamesToString(c) + ")" //
+ /* ext + */ ";" //
)
}
}

View File

@@ -1056,7 +1056,7 @@ module Private {
|
c.relevantSummary(input, output, preservesValue) and
csv =
c.getCallableCsv() + ";" + getComponentStackCsv(input) + ";" +
c.getCallableCsv() + ";;" + getComponentStackCsv(input) + ";" +
getComponentStackCsv(output) + ";" + renderKind(preservesValue)
)
}

View File

@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -143,16 +123,6 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -143,16 +123,6 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -143,16 +123,6 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -143,16 +123,6 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -143,16 +123,6 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -14,12 +14,24 @@
import csharp
import semmle.code.csharp.commons.StructuralComparison
predicate doubleCheckedLock(Field field, IfStmt unlockedIf) {
exists(LockStmt lock, IfStmt lockedIf |
lock = unlockedIf.getThen().stripSingletonBlocks() and
lockedIf.getParent*() = lock.getBlock() and
sameGvn(unlockedIf.getCondition(), lockedIf.getCondition()) and
field.getAnAccess() = unlockedIf.getCondition().getAChildExpr*()
class DoubleCheckedLock extends StructuralComparisonConfiguration {
DoubleCheckedLock() { this = "double checked lock" }
override predicate candidate(ControlFlowElement x, ControlFlowElement y) {
exists(IfStmt unlockedIf, IfStmt lockedIf, LockStmt lock |
x = unlockedIf.getCondition() and
y = lockedIf.getCondition() and
lock = unlockedIf.getThen().stripSingletonBlocks() and
lockedIf.getParent*() = lock.getBlock()
)
}
}
predicate doubleCheckedLock(Field field, IfStmt ifs) {
exists(DoubleCheckedLock config, LockStmt lock, Expr eq1, Expr eq2 | ifs.getCondition() = eq1 |
lock = ifs.getThen().stripSingletonBlocks() and
config.same(eq1, eq2) and
field.getAnAccess() = eq1.getAChildExpr*()
)
}

View File

@@ -12,8 +12,25 @@
import csharp
import semmle.code.csharp.commons.StructuralComparison
private Expr getAssignedExpr(Stmt stmt) {
result = stmt.stripSingletonBlocks().(ExprStmt).getExpr().(AssignExpr).getLValue()
class StructuralComparisonConfig extends StructuralComparisonConfiguration {
StructuralComparisonConfig() { this = "MissedTernaryOpportunity" }
override predicate candidate(ControlFlowElement x, ControlFlowElement y) {
exists(IfStmt is, AssignExpr ae1 |
ae1 = is.getThen().stripSingletonBlocks().(ExprStmt).getExpr()
|
x = ae1.getLValue() and
exists(AssignExpr ae2 | ae2 = is.getElse().stripSingletonBlocks().(ExprStmt).getExpr() |
y = ae2.getLValue()
)
)
}
IfStmt getIfStmt() {
exists(AssignExpr ae | ae = result.getThen().stripSingletonBlocks().(ExprStmt).getExpr() |
same(ae.getLValue(), _)
)
}
}
from IfStmt is, string what
@@ -23,8 +40,10 @@ where
is.getElse().stripSingletonBlocks() instanceof ReturnStmt and
what = "return"
or
sameGvn(getAssignedExpr(is.getThen()), getAssignedExpr(is.getElse())) and
what = "write to the same variable"
exists(StructuralComparisonConfig c |
is = c.getIfStmt() and
what = "write to the same variable"
)
) and
not exists(IfStmt other | is = other.getElse())
select is,

View File

@@ -13,26 +13,35 @@
import csharp
import semmle.code.csharp.commons.StructuralComparison
private predicate candidate(AsExpr ae, IsExpr ie) {
exists(IfStmt is, TypeAccessPatternExpr tape |
ie = is.getCondition().getAChild*() and
tape = ie.getPattern() and
ae.getTargetType() = tape.getTarget()
|
ae = is.getThen().getAChild*()
or
ae = is.getElse().getAChild*()
)
}
class StructuralComparisonConfig extends StructuralComparisonConfiguration {
StructuralComparisonConfig() { this = "UselessIsBeforeAs" }
private predicate uselessIsBeforeAs(AsExpr ae, IsExpr ie) {
candidate(ae, ie) and
sameGvn(ie.getExpr(), ae.getExpr())
override predicate candidate(ControlFlowElement x, ControlFlowElement y) {
exists(IfStmt is, AsExpr ae, IsExpr ie, TypeAccessPatternExpr tape |
ie = is.getCondition().getAChild*() and
tape = ie.getPattern() and
ae.getTargetType() = tape.getTarget() and
x = ie.getExpr() and
y = ae.getExpr()
|
ae = is.getThen().getAChild*()
or
ae = is.getElse().getAChild*()
)
}
predicate uselessIsBeforeAs(AsExpr ae, IsExpr ie) {
exists(Expr x, Expr y |
same(x, y) and
ie.getExpr() = x and
ae.getExpr() = y
)
}
}
from AsExpr ae, IsExpr ie
where
uselessIsBeforeAs(ae, ie) and
exists(StructuralComparisonConfig c | c.uselessIsBeforeAs(ae, ie)) and
not exists(MethodCall mc | ae = mc.getAnArgument().getAChildExpr*())
select ae,
"This 'as' expression performs a type test - it should be directly compared against null, rendering the 'is' $@ potentially redundant.",

View File

@@ -14,22 +14,24 @@
import csharp
import semmle.code.csharp.commons.StructuralComparison
pragma[noinline]
private predicate same(AssignableAccess x, AssignableAccess y) {
exists(NullCoalescingExpr nce |
x = nce.getLeftOperand() and
y = nce.getRightOperand().getAChildExpr*()
) and
sameGvn(x, y)
class StructuralComparisonConfig extends StructuralComparisonConfiguration {
StructuralComparisonConfig() { this = "UselessNullCoalescingExpression" }
override predicate candidate(ControlFlowElement x, ControlFlowElement y) {
exists(NullCoalescingExpr nce |
x.(Access) = nce.getLeftOperand() and
y.(Access) = nce.getRightOperand().getAChildExpr*()
)
}
NullCoalescingExpr getUselessNullCoalescingExpr() {
exists(AssignableAccess x |
result.getLeftOperand() = x and
forex(AssignableAccess y | same(x, y) | y instanceof AssignableRead and not y.isRefArgument())
)
}
}
private predicate uselessNullCoalescingExpr(NullCoalescingExpr nce) {
exists(AssignableAccess x |
nce.getLeftOperand() = x and
forex(AssignableAccess y | same(x, y) | y instanceof AssignableRead and not y.isRefArgument())
)
}
from NullCoalescingExpr nce
where uselessNullCoalescingExpr(nce)
from StructuralComparisonConfig c, NullCoalescingExpr nce
where nce = c.getUselessNullCoalescingExpr()
select nce, "Both operands of this null-coalescing expression access the same variable or property."

View File

@@ -15,6 +15,18 @@ import csharp
import semmle.code.csharp.commons.ComparisonTest
import semmle.code.csharp.commons.StructuralComparison as SC
/** A structural comparison configuration for comparing the conditions of nested `for` loops. */
class NestedForConditions extends SC::StructuralComparisonConfiguration {
NestedForConditions() { this = "Compare nested for conditions" }
override predicate candidate(ControlFlowElement e1, ControlFlowElement e2) {
exists(NestedForLoopSameVariable nested |
e1 = nested.getInnerForStmt().getCondition() and
e2 = nested.getOuterForStmt().getCondition()
)
}
}
private predicate hasChild(Stmt outer, Element child) {
outer = child.getParent() and
(outer instanceof ForStmt or outer = any(ForStmt f).getBody())
@@ -49,7 +61,9 @@ class NestedForLoopSameVariable extends ForStmt {
}
private predicate haveSameCondition() {
SC::sameGvn(this.getInnerForStmt().getCondition(), this.getOuterForStmt().getCondition())
exists(NestedForConditions config |
config.same(this.getInnerForStmt().getCondition(), this.getOuterForStmt().getCondition())
)
}
private predicate haveSameUpdate() {

View File

@@ -13,25 +13,37 @@
import csharp
import semmle.code.csharp.commons.StructuralComparison
private predicate candidate(AssignExpr ae) {
// Member initializers are never self-assignments, in particular
// not initializers such as `new C { F = F };`
not ae instanceof MemberInitializer and
// Enum field initializers are never self assignments. `enum E { A = 42 }`
not ae.getParent().(Field).getDeclaringType() instanceof Enum and
forall(Expr e | e = ae.getLValue().getAChildExpr*() |
// Non-trivial property accesses may have side-effects,
// so these are not considered
e instanceof PropertyAccess implies e instanceof TrivialPropertyAccess
)
class StructuralComparisonConfig extends StructuralComparisonConfiguration {
StructuralComparisonConfig() { this = "SelfAssignment" }
override predicate candidate(ControlFlowElement x, ControlFlowElement y) {
exists(AssignExpr ae |
// Member initializers are never self-assignments, in particular
// not initializers such as `new C { F = F };`
not ae instanceof MemberInitializer and
// Enum field initializers are never self assignments. `enum E { A = 42 }`
not ae.getParent().(Field).getDeclaringType() instanceof Enum
|
ae.getLValue() = x and
ae.getRValue() = y
) and
forall(Expr e | e = x.(Expr).getAChildExpr*() |
// Non-trivial property accesses may have side-effects,
// so these are not considered
e instanceof PropertyAccess implies e instanceof TrivialPropertyAccess
)
}
AssignExpr getSelfAssignExpr() {
exists(Expr x, Expr y |
same(x, y) and
result.getLValue() = x and
result.getRValue() = y
)
}
}
private predicate selfAssignExpr(AssignExpr ae) {
candidate(ae) and
sameGvn(ae.getLValue(), ae.getRValue())
}
private Declaration getDeclaration(Expr e) {
Declaration getDeclaration(Expr e) {
result = e.(VariableAccess).getTarget()
or
result = e.(MemberAccess).getTarget()
@@ -39,6 +51,6 @@ private Declaration getDeclaration(Expr e) {
result = getDeclaration(e.(ArrayAccess).getQualifier())
}
from AssignExpr ae, Declaration target
where selfAssignExpr(ae) and target = getDeclaration(ae.getLValue())
from StructuralComparisonConfig c, AssignExpr ae, Declaration target
where ae = c.getSelfAssignExpr() and target = getDeclaration(ae.getLValue())
select ae, "This assignment assigns $@ to itself.", target, target.getName()

View File

@@ -13,14 +13,19 @@ import csharp
import semmle.code.csharp.commons.StructuralComparison
import semmle.code.csharp.controlflow.Guards as G
pragma[noinline]
private predicate candidate(MethodCall mc, IndexerRead access) {
mc.getTarget().hasName("ContainsKey") and
access.getQualifier().(G::GuardedExpr).isGuardedBy(mc, mc.getQualifier(), _)
class SameElement extends StructuralComparisonConfiguration {
SameElement() { this = "Same element" }
override predicate candidate(ControlFlowElement e1, ControlFlowElement e2) {
exists(MethodCall mc, IndexerRead access |
mc.getTarget().hasName("ContainsKey") and
access.getQualifier().(G::GuardedExpr).isGuardedBy(mc, mc.getQualifier(), _) and
e1 = mc.getArgument(0) and
e2 = access.getIndex(0)
)
}
}
from MethodCall call, IndexerRead index
where
candidate(call, index) and
sameGvn(call.getArgument(0), index.getIndex(0))
from SameElement element, MethodCall call, IndexerAccess index
where element.same(call.getArgument(0), index.getIndex(0))
select call, "Inefficient use of 'ContainsKey' and $@.", index, "indexer"

View File

@@ -7,12 +7,12 @@ private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
private predicate isRelevantForModels(Callable api) { not api instanceof MainMethod }
/**
* A class of callables that are relevant generating summary, source and sinks models for.
* A class of Callables that are relevant for generating summary, source and sinks models for.
*
* In the Standard library and 3rd party libraries it the callables that can be called
* In the Standard library and 3rd party libraries it the Callables that can be called
* from outside the library itself.
*/
class TargetApi extends DataFlowCallable {
class TargetApi extends Callable {
TargetApi() {
[this.(Modifiable), this.(Accessor).getDeclaration()].isEffectivelyPublic() and
this.fromSource() and
@@ -20,7 +20,44 @@ class TargetApi extends DataFlowCallable {
}
}
predicate asPartialModel = Csv::asPartialModel/1;
private string parameterQualifiedTypeNamesToString(TargetApi api) {
result =
concat(Parameter p, int i |
p = api.getParameter(i)
|
p.getType().getQualifiedName(), "," order by i
)
}
/** Holds if the summary should apply for all overrides of this. */
private predicate isBaseCallableOrPrototype(TargetApi api) {
api.getDeclaringType() instanceof Interface
or
exists(Modifiable m | m = [api.(Modifiable), api.(Accessor).getDeclaration()] |
m.isAbstract()
or
api.getDeclaringType().(Modifiable).isAbstract() and m.(Virtualizable).isVirtual()
)
}
/** Gets a string representing whether the summary should apply for all overrides of this. */
private string getCallableOverride(TargetApi api) {
if isBaseCallableOrPrototype(api) then result = "true" else result = "false"
}
/** Computes the first 6 columns for CSV rows. */
string asPartialModel(TargetApi api) {
exists(string namespace, string type |
api.getDeclaringType().hasQualifiedName(namespace, type) and
result =
namespace + ";" //
+ type + ";" //
+ getCallableOverride(api) + ";" //
+ api.getName() + ";" //
+ "(" + parameterQualifiedTypeNamesToString(api) + ")" //
+ /* ext + */ ";" //
)
}
/**
* Holds for type `t` for fields that are relevant as an intermediate
@@ -49,11 +86,6 @@ string parameterNodeAsInput(DataFlow::ParameterNode p) {
result = "Argument[Qualifier]" and p instanceof InstanceParameterNode
}
pragma[nomagic]
private Parameter getParameter(ReturnNodeExt node, ParameterPosition pos) {
result = node.getEnclosingCallable().getParameter(pos.getPosition())
}
/**
* Gets the model string represention of the the return node `node`.
*/
@@ -62,7 +94,7 @@ string returnNodeAsOutput(ReturnNodeExt node) {
then result = "ReturnValue"
else
exists(ParameterPosition pos | pos = node.getKind().(ParamUpdateReturnKind).getPosition() |
result = parameterAccess(getParameter(node, pos))
result = parameterAccess(node.getEnclosingCallable().getParameter(pos.getPosition()))
or
pos.isThisParameter() and
result = "Argument[Qualifier]"

View File

@@ -1,5 +1,4 @@
import shared.FlowSummaries
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate::Csv
private import semmle.code.csharp.dataflow.ExternalFlow
class IncludeFilteredSummarizedCallable extends IncludeSummarizedCallable {
@@ -15,7 +14,7 @@ class IncludeFilteredSummarizedCallable extends IncludeSummarizedCallable {
) {
this.propagatesFlow(input, output, preservesValue) and
not exists(IncludeSummarizedCallable rsc |
isBaseCallableOrPrototype(rsc) and
rsc.isBaseCallableOrPrototype() and
rsc.propagatesFlow(input, output, preservesValue) and
this.(UnboundCallable).overridesOrImplementsUnbound(rsc)
)

View File

@@ -1,25 +1,28 @@
import csharp
import semmle.code.csharp.commons.StructuralComparison
/**
* All pairs of controls flow elements found in the source and within the same
* enclosing callable excluding all instances of `ThisAccess` to reduce the size
* of the output.
*/
private predicate candidate(ControlFlowElement x, ControlFlowElement y) {
x.fromSource() and
y.fromSource() and
x != y and
x.getEnclosingCallable() = y.getEnclosingCallable() and
not x instanceof ThisAccess
private class StructuralComparisonTest extends StructuralComparisonConfiguration {
StructuralComparisonTest() { this = "StructuralComparisonTest" }
/**
* All pairs of controls flow elements found in the source and within the same
* enclosing callable excluding all instances of `ThisAccess` to reduce the size
* of the output.
*/
override predicate candidate(ControlFlowElement e1, ControlFlowElement e2) {
e1.fromSource() and
e2.fromSource() and
e1 != e2 and
e1.getEnclosingCallable() = e2.getEnclosingCallable() and
not e1 instanceof ThisAccess
}
}
query predicate same(ControlFlowElement x, ControlFlowElement y) {
exists(Location l1, Location l2 |
candidate(x, y) and
sameGvn(x, y) and
l1 = x.getLocation() and
l2 = y.getLocation() and
query predicate same(ControlFlowElement e1, ControlFlowElement e2) {
exists(StructuralComparisonTest sct, Location l1, Location l2 |
sct.same(e1, e2) and
l1 = e1.getLocation() and
l2 = e2.getLocation() and
(
l1.getStartLine() < l2.getStartLine()
or
@@ -28,4 +31,4 @@ query predicate same(ControlFlowElement x, ControlFlowElement y) {
)
}
query predicate gvn(ControlFlowElement x, Gvn gvn) { gvn = toGvn(x) and x.fromSource() }
query predicate gvn(ControlFlowElement e, Gvn gvn) { gvn = toGvn(e) and e.fromSource() }

View File

@@ -1,12 +1,44 @@
import semmle.code.csharp.dataflow.FlowSummary
import semmle.code.csharp.dataflow.internal.FlowSummaryImpl::Private::TestOutput
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
abstract class IncludeSummarizedCallable extends RelevantSummarizedCallable {
IncludeSummarizedCallable() {
[this.(Modifiable), this.(Accessor).getDeclaration()].isEffectivelyPublic()
}
/** Gets the qualified parameter types of this callable as a comma-separated string. */
private string parameterQualifiedTypeNamesToString() {
result =
concat(Parameter p, int i |
p = this.getParameter(i)
|
p.getType().getQualifiedName(), "," order by i
)
}
/** Holds if the summary should apply for all overrides of this. */
predicate isBaseCallableOrPrototype() {
this.getDeclaringType() instanceof Interface
or
exists(Modifiable m | m = [this.(Modifiable), this.(Accessor).getDeclaration()] |
m.isAbstract()
or
this.getDeclaringType().(Modifiable).isAbstract() and m.(Virtualizable).isVirtual()
)
}
/** Gets a string representing whether the summary should apply for all overrides of this. */
private string getCallableOverride() {
if this.isBaseCallableOrPrototype() then result = "true" else result = "false"
}
/** Gets a string representing the callable in semi-colon separated format for use in flow summaries. */
final override string getCallableCsv() { result = Csv::asPartialModel(this) }
final override string getCallableCsv() {
exists(string namespace, string type |
this.getDeclaringType().hasQualifiedName(namespace, type) and
result =
namespace + ";" + type + ";" + this.getCallableOverride() + ";" + this.getName() + ";" + "("
+ this.parameterQualifiedTypeNamesToString() + ")"
)
}
}

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* The data flow and taint tracking libraries have been extended with versions of `isBarrierIn`, `isBarrierOut`, and `isBarrierGuard`, respectively `isSanitizerIn`, `isSanitizerOut`, and `isSanitizerGuard`, that support flow states.

View File

@@ -4,7 +4,6 @@
import Member
import semmle.code.java.security.ExternalProcess
private import semmle.code.java.dataflow.FlowSteps
// --- Standard types ---
/** The class `java.lang.Object`. */
@@ -38,27 +37,6 @@ class StringLengthMethod extends Method {
StringLengthMethod() { this.hasName("length") and this.getDeclaringType() instanceof TypeString }
}
/**
* The methods on the class `java.lang.String` that are used to perform partial matches with a specified substring or char.
*/
class StringPartialMatchMethod extends Method {
StringPartialMatchMethod() {
this.hasName([
"contains", "startsWith", "endsWith", "matches", "indexOf", "lastIndexOf", "regionMatches"
]) and
this.getDeclaringType() instanceof TypeString
}
/**
* Gets the index of the parameter that is being matched against.
*/
int getMatchParameterIndex() {
if this.hasName("regionMatches")
then this.getParameterType(result) instanceof TypeString
else result = 0
}
}
/** The class `java.lang.StringBuffer`. */
class TypeStringBuffer extends Class {
TypeStringBuffer() { this.hasQualifiedName("java.lang", "StringBuffer") }
@@ -250,13 +228,11 @@ class MethodSystemGetenv extends Method {
/**
* Any method named `getProperty` on class `java.lang.System`.
*/
class MethodSystemGetProperty extends ValuePreservingMethod {
class MethodSystemGetProperty extends Method {
MethodSystemGetProperty() {
this.hasName("getProperty") and
this.getDeclaringType() instanceof TypeSystem
}
override predicate returnsValue(int arg) { arg = 1 }
}
/**
@@ -268,9 +244,6 @@ class MethodAccessSystemGetProperty extends MethodAccess {
/**
* Holds if this call has a compile-time constant first argument with the value `propertyName`.
* For example: `System.getProperty("user.dir")`.
*
* Note: Better to use `semmle.code.java.environment.SystemProperty#getSystemProperty` instead
* as that predicate covers ways of accessing the same information via various libraries.
*/
predicate hasCompileTimeConstantGetPropertyName(string propertyName) {
this.getArgument(0).(CompileTimeConstantExpr).getStringValue() = propertyName

View File

@@ -4,7 +4,6 @@
import java
import dataflow.DefUse
private import semmle.code.java.environment.SystemProperty
/**
* A library method that formats a number of its arguments according to a
@@ -313,7 +312,27 @@ private predicate formatStringValue(Expr e, string fmtvalue) {
or
formatStringValue(e.(ChooseExpr).getAResultExpr(), fmtvalue)
or
e = getSystemProperty(["line.separator", "file.separator", "path.separator"]) and fmtvalue = "x" // dummy value
exists(Method getprop, MethodAccess ma, string prop |
e = ma and
ma.getMethod() = getprop and
getprop.hasName("getProperty") and
getprop.getDeclaringType().hasQualifiedName("java.lang", "System") and
getprop.getNumberOfParameters() = 1 and
ma.getAnArgument().(StringLiteral).getValue() = prop and
(prop = "line.separator" or prop = "file.separator" or prop = "path.separator") and
fmtvalue = "x" // dummy value
)
or
exists(Field f |
e = f.getAnAccess() and
f.getDeclaringType() instanceof TypeFile and
fmtvalue = "x" // dummy value
|
f.hasName("pathSeparator") or
f.hasName("pathSeparatorChar") or
f.hasName("separator") or
f.hasName("separatorChar")
)
)
}

View File

@@ -203,7 +203,6 @@ class EnvReadMethod extends Method {
EnvReadMethod() {
this instanceof MethodSystemGetenv or
this instanceof PropertiesGetPropertyMethod or
this instanceof PropertiesGetMethod or
this instanceof MethodSystemGetProperty
}
}

View File

@@ -10,13 +10,11 @@ private import semmle.code.java.dataflow.DataFlow
* ensuring that they are visible to the taint tracking library.
*/
private module Frameworks {
private import semmle.code.java.JDK
private import semmle.code.java.frameworks.jackson.JacksonSerializability
private import semmle.code.java.frameworks.android.AsyncTask
private import semmle.code.java.frameworks.android.Intent
private import semmle.code.java.frameworks.android.SQLite
private import semmle.code.java.frameworks.Guice
private import semmle.code.java.frameworks.Properties
private import semmle.code.java.frameworks.Protobuf
private import semmle.code.java.frameworks.guava.Guava
private import semmle.code.java.frameworks.apache.Lang

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -87,30 +87,12 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -323,7 +305,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate fullInBarrier(NodeEx node, Configuration config) {
private predicate inBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -332,16 +314,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
private predicate outBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -350,15 +323,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -381,19 +345,9 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n | node.asNode() = n |
exists(Node n |
node.asNode() = n and
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -422,8 +376,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -476,8 +430,6 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -519,8 +471,6 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -920,8 +870,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
not inBarrier(node, config) and
not outBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -1016,8 +966,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
not outBarrier(ret, config) and
not inBarrier(out, config)
}
pragma[nomagic]
@@ -1038,8 +988,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
not outBarrier(arg, config) and
not inBarrier(p, config)
}
/**
@@ -1756,31 +1706,18 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1800,9 +1737,6 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1836,40 +1770,42 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
t = node1.getDataFlowType() // irrelevant dummy value
or
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
or
exists(NodeEx mid |
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
)
or
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType()
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
)
)
}
@@ -1883,19 +1819,9 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
}
}
@@ -2769,10 +2695,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable()) and
exists(config)
node.getEnclosingCallable())
}
private predicate localStep(

View File

@@ -1056,7 +1056,7 @@ module Private {
|
c.relevantSummary(input, output, preservesValue) and
csv =
c.getCallableCsv() + ";" + getComponentStackCsv(input) + ";" +
c.getCallableCsv() + ";;" + getComponentStackCsv(input) + ";" +
getComponentStackCsv(output) + ";" + renderKind(preservesValue)
)
}

View File

@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -143,16 +123,6 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -143,16 +123,6 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -1,286 +0,0 @@
/**
* Provides classes and predicates for working with java system properties.
*/
import java
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.frameworks.Properties
private import semmle.code.java.frameworks.apache.Lang
/**
* Gets an expression that retrieves the value of `propertyName` from `System.getProperty()`.
*
* Note: Expression type is not just `String`.
*/
Expr getSystemProperty(string propertyName) {
result = getSystemPropertyFromSystem(propertyName) or
result = getSystemPropertyFromSystemGetProperties(propertyName) or
result = getSystemPropertyFromFile(propertyName) or
result = getSystemPropertyFromApacheSystemUtils(propertyName) or
result = getSystemPropertyFromApacheFileUtils(propertyName) or
result = getSystemPropertyFromGuava(propertyName) or
result = getSystemPropertyFromOperatingSystemMXBean(propertyName) or
result = getSystemPropertyFromSpringProperties(propertyName)
}
private MethodAccess getSystemPropertyFromSystem(string propertyName) {
result.(MethodAccessSystemGetProperty).hasCompileTimeConstantGetPropertyName(propertyName)
or
result.getMethod().hasName("lineSeparator") and propertyName = "line.separator"
}
/**
* A method access that retrieves the value of `propertyName` from the following methods:
* - `System.getProperties().getProperty(...)`
* - `System.getProperties().get(...)`
*/
private MethodAccess getSystemPropertyFromSystemGetProperties(string propertyName) {
exists(Method getMethod |
getMethod instanceof PropertiesGetMethod
or
getMethod instanceof PropertiesGetPropertyMethod and
result.getMethod() = getMethod
) and
result.getArgument(0).(CompileTimeConstantExpr).getStringValue() = propertyName and
localExprFlowPlusInitializers(any(MethodAccess m |
m.getMethod().getDeclaringType() instanceof TypeSystem and
m.getMethod().hasName("getProperties")
), result.getQualifier())
}
private FieldAccess getSystemPropertyFromFile(string propertyName) {
result.getField() instanceof FieldFileSeparator and propertyName = "file.separator"
or
result.getField() instanceof FieldFilePathSeparator and propertyName = "path.separator"
}
/** The field `java.io.File.separator` or `java.io.File.separatorChar` */
private class FieldFileSeparator extends Field {
FieldFileSeparator() {
this.getDeclaringType() instanceof TypeFile and this.hasName(["separator", "separatorChar"])
}
}
/* The field `java.io.File.pathSeparator` or `java.io.File.pathSeparatorChar` */
private class FieldFilePathSeparator extends Field {
FieldFilePathSeparator() {
this.getDeclaringType() instanceof TypeFile and
this.hasName(["pathSeparator", "pathSeparatorChar"])
}
}
/**
* A field access to the system property.
* See: https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/SystemUtils.html
*/
private FieldAccess getSystemPropertyFromApacheSystemUtils(string propertyName) {
exists(Field f | f = result.getField() and f.getDeclaringType() instanceof TypeApacheSystemUtils |
f.hasName("AWT_TOOLKIT") and propertyName = "awt.toolkit"
or
f.hasName("FILE_ENCODING") and propertyName = "file.encoding"
or
f.hasName("FILE_SEPARATOR") and propertyName = "file.separator"
or
f.hasName("JAVA_AWT_FONTS") and propertyName = "java.awt.fonts"
or
f.hasName("JAVA_AWT_GRAPHICSENV") and propertyName = "java.awt.graphicsenv"
or
f.hasName("JAVA_AWT_HEADLESS") and propertyName = "java.awt.headless"
or
f.hasName("JAVA_AWT_PRINTERJOB") and propertyName = "java.awt.printerjob"
or
f.hasName("JAVA_CLASS_PATH") and propertyName = "java.class.path"
or
f.hasName("JAVA_CLASS_VERSION") and propertyName = "java.class.version"
or
f.hasName("JAVA_COMPILER") and propertyName = "java.compiler"
or
f.hasName("JAVA_EXT_DIRS") and propertyName = "java.ext.dirs"
or
f.hasName("JAVA_HOME") and propertyName = "java.home"
or
f.hasName("JAVA_IO_TMPDIR") and propertyName = "java.io.tmpdir"
or
f.hasName("JAVA_LIBRARY_PATH") and propertyName = "java.library.path"
or
f.hasName("JAVA_RUNTIME_NAME") and propertyName = "java.runtime.name"
or
f.hasName("JAVA_RUNTIME_VERSION") and propertyName = "java.runtime.version"
or
f.hasName("JAVA_SPECIFICATION_NAME") and propertyName = "java.specification.name"
or
f.hasName("JAVA_SPECIFICATION_VENDOR") and propertyName = "java.specification.vendor"
or
f.hasName("JAVA_UTIL_PREFS_PREFERENCES_FACTORY") and
propertyName = "java.util.prefs.PreferencesFactory" // This really does break the lowercase convention obeyed everywhere else
or
f.hasName("JAVA_VENDOR") and propertyName = "java.vendor"
or
f.hasName("JAVA_VENDOR_URL") and propertyName = "java.vendor.url"
or
f.hasName("JAVA_VERSION") and propertyName = "java.version"
or
f.hasName("JAVA_VM_INFO") and propertyName = "java.vm.info"
or
f.hasName("JAVA_VM_NAME") and propertyName = "java.vm.name"
or
f.hasName("JAVA_VM_SPECIFICATION_NAME") and propertyName = "java.vm.specification.name"
or
f.hasName("JAVA_VM_SPECIFICATION_VENDOR") and propertyName = "java.vm.specification.vendor"
or
f.hasName("JAVA_VM_VENDOR") and propertyName = "java.vm.vendor"
or
f.hasName("JAVA_VM_VERSION") and propertyName = "java.vm.version"
or
f.hasName("LINE_SEPARATOR") and propertyName = "line.separator"
or
f.hasName("OS_ARCH") and propertyName = "os.arch"
or
f.hasName("OS_NAME") and propertyName = "os.name"
or
f.hasName("OS_VERSION") and propertyName = "os.version"
or
f.hasName("PATH_SEPARATOR") and propertyName = "path.separator"
or
f.hasName("USER_COUNTRY") and propertyName = "user.country"
or
f.hasName("USER_DIR") and propertyName = "user.dir"
or
f.hasName("USER_HOME") and propertyName = "user.home"
or
f.hasName("USER_LANGUAGE") and propertyName = "user.language"
or
f.hasName("USER_NAME") and propertyName = "user.name"
or
f.hasName("USER_TIMEZONE") and propertyName = "user.timezone"
)
}
private MethodAccess getSystemPropertyFromApacheFileUtils(string propertyName) {
exists(Method m |
result.getMethod() = m and
m.getDeclaringType().hasQualifiedName("org.apache.commons.io", "FileUtils")
|
m.hasName(["getTempDirectory", "getTempDirectoryPath"]) and propertyName = "java.io.tmpdir"
or
m.hasName(["getUserDirectory", "getUserDirectoryPath"]) and propertyName = "user.home"
)
}
private MethodAccess getSystemPropertyFromGuava(string propertyName) {
exists(EnumConstant ec |
ec.getDeclaringType().hasQualifiedName("com.google.common.base", "StandardSystemProperty") and
// Example: `StandardSystemProperty.JAVA_IO_TMPDIR.value()`
(
localExprFlowPlusInitializers(ec.getAnAccess(), result.getQualifier()) and
result.getMethod().hasName("value")
)
or
// Example: `System.getProperty(StandardSystemProperty.JAVA_IO_TMPDIR.key())`
exists(MethodAccess keyMa |
localExprFlowPlusInitializers(ec.getAnAccess(), keyMa.getQualifier()) and
keyMa.getMethod().hasName("key") and
localExprFlowPlusInitializers(keyMa, result.(MethodAccessSystemGetProperty).getArgument(0))
)
|
ec.hasName("JAVA_VERSION") and propertyName = "java.version"
or
ec.hasName("JAVA_VENDOR") and propertyName = "java.vendor"
or
ec.hasName("JAVA_VENDOR_URL") and propertyName = "java.vendor.url"
or
ec.hasName("JAVA_HOME") and propertyName = "java.home"
or
ec.hasName("JAVA_VM_SPECIFICATION_VERSION") and propertyName = "java.vm.specification.version"
or
ec.hasName("JAVA_VM_SPECIFICATION_VENDOR") and propertyName = "java.vm.specification.vendor"
or
ec.hasName("JAVA_VM_SPECIFICATION_NAME") and propertyName = "java.vm.specification.name"
or
ec.hasName("JAVA_VM_VERSION") and propertyName = "java.vm.version"
or
ec.hasName("JAVA_VM_VENDOR") and propertyName = "java.vm.vendor"
or
ec.hasName("JAVA_VM_NAME") and propertyName = "java.vm.name"
or
ec.hasName("JAVA_SPECIFICATION_VERSION") and propertyName = "java.specification.version"
or
ec.hasName("JAVA_SPECIFICATION_VENDOR") and propertyName = "java.specification.vendor"
or
ec.hasName("JAVA_SPECIFICATION_NAME") and propertyName = "java.specification.name"
or
ec.hasName("JAVA_CLASS_VERSION") and propertyName = "java.class.version"
or
ec.hasName("JAVA_CLASS_PATH") and propertyName = "java.class.path"
or
ec.hasName("JAVA_LIBRARY_PATH") and propertyName = "java.library.path"
or
ec.hasName("JAVA_IO_TMPDIR") and propertyName = "java.io.tmpdir"
or
ec.hasName("JAVA_COMPILER") and propertyName = "java.compiler"
or
ec.hasName("JAVA_EXT_DIRS") and propertyName = "java.ext.dirs"
or
ec.hasName("OS_NAME") and propertyName = "os.name"
or
ec.hasName("OS_ARCH") and propertyName = "os.arch"
or
ec.hasName("OS_VERSION") and propertyName = "os.version"
or
ec.hasName("FILE_SEPARATOR") and propertyName = "file.separator"
or
ec.hasName("PATH_SEPARATOR") and propertyName = "path.separator"
or
ec.hasName("LINE_SEPARATOR") and propertyName = "line.separator"
or
ec.hasName("USER_NAME") and propertyName = "user.name"
or
ec.hasName("USER_HOME") and propertyName = "user.home"
or
ec.hasName("USER_DIR") and propertyName = "user.dir"
)
}
private MethodAccess getSystemPropertyFromOperatingSystemMXBean(string propertyName) {
exists(Method m |
m = result.getMethod() and
m.getDeclaringType().hasQualifiedName("java.lang.management", "OperatingSystemMXBean")
|
m.getName() = "getName" and propertyName = "os.name"
or
m.getName() = "getArch" and propertyName = "os.arch"
or
m.getName() = "getVersion" and propertyName = "os.version"
)
}
private MethodAccess getSystemPropertyFromSpringProperties(string propertyName) {
exists(Method m |
m = result.getMethod() and
m.getDeclaringType().hasQualifiedName("org.springframework.core", "SpringProperties") and
m.hasName("getProperty")
) and
result.getArgument(0).(CompileTimeConstantExpr).getStringValue() = propertyName
}
/**
* Holds if data can flow from `e1` to `e2` in zero or more
* local (intra-procedural) steps or via local variable intializers
* for final variables.
*/
private predicate localExprFlowPlusInitializers(Expr e1, Expr e2) {
localFlowPlusInitializers(DataFlow::exprNode(e1), DataFlow::exprNode(e2))
}
/**
* Holds if data can flow from `pred` to `succ` in zero or more
* local (intra-procedural) steps or via instance or static variable intializers
* for final variables.
*/
private predicate localFlowPlusInitializers(DataFlow::Node pred, DataFlow::Node succ) {
exists(Variable v | v.isFinal() and pred.asExpr() = v.getInitializer() |
DataFlow::localFlow(DataFlow::exprNode(v.getAnAccess()), succ)
)
or
DataFlow::localFlow(pred, succ)
}

View File

@@ -1,44 +1,25 @@
/* Definitions related to `java.util.Properties`. */
import semmle.code.java.Type
private import semmle.code.java.dataflow.FlowSteps
/**
* The `java.util.Properties` class.
*/
class TypeProperty extends Class {
library class TypeProperty extends Class {
TypeProperty() { hasQualifiedName("java.util", "Properties") }
}
/** The `getProperty` method of the class `java.util.Properties`. */
class PropertiesGetPropertyMethod extends ValuePreservingMethod {
library class PropertiesGetPropertyMethod extends Method {
PropertiesGetPropertyMethod() {
getDeclaringType() instanceof TypeProperty and
hasName("getProperty")
}
override predicate returnsValue(int arg) { arg = 1 }
}
/** The `get` method of the class `java.util.Properties`. */
class PropertiesGetMethod extends Method {
PropertiesGetMethod() {
getDeclaringType() instanceof TypeProperty and
hasName("get")
}
}
/** The `setProperty` method of the class `java.util.Properties`. */
class PropertiesSetPropertyMethod extends Method {
library class PropertiesSetPropertyMethod extends Method {
PropertiesSetPropertyMethod() {
getDeclaringType() instanceof TypeProperty and
hasName("setProperty")
}
}
/**
* The methods of the class `java.util.Properties` that write the contents to an output.
*/
class PropertiesStoreMethod extends Method {
library class PropertiesStoreMethod extends Method {
PropertiesStoreMethod() {
getDeclaringType() instanceof TypeProperty and
(getName().matches("store%") or getName() = "save")

View File

@@ -37,12 +37,3 @@ private class ApacheStrBuilderFluentMethod extends FluentMethod {
this.getReturnType().(RefType).hasQualifiedName("org.apache.commons.lang3.text", "StrBuilder")
}
}
/**
* The class `org.apache.commons.lang.SystemUtils` or `org.apache.commons.lang3.SystemUtils`.
*/
class TypeApacheSystemUtils extends Class {
TypeApacheSystemUtils() {
this.hasQualifiedName(["org.apache.commons.lang", "org.apache.commons.lang3"], "SystemUtils")
}
}

View File

@@ -1,161 +0,0 @@
/**
* Provides classes and predicates for guards that check for the current OS.
*/
import java
import semmle.code.java.controlflow.Guards
private import semmle.code.java.environment.SystemProperty
private import semmle.code.java.frameworks.apache.Lang
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.TaintTracking
/**
* A guard that checks if the current OS is Windows.
* When True, the OS is Windows.
* When False, the OS is not Windows.
*/
abstract class IsWindowsGuard extends Guard { }
/**
* A guard that checks if the current OS is a specific Windows variant.
* When True, the OS is Windows.
* When False, the OS *may* still be Windows.
*/
abstract class IsSpecificWindowsVariant extends Guard { }
/**
* A guard that checks if the current OS is unix or unix-like.
* When True, the OS is unix or unix-like.
* When False, the OS is not unix or unix-like.
*/
abstract class IsUnixGuard extends Guard { }
/**
* A guard that checks if the current OS is a specific unix or unix-like variant.
* When True, the OS is unix or unix-like.
* When False, the OS *may* still be unix or unix-like.
*/
abstract class IsSpecificUnixVariant extends Guard { }
/**
* Holds when `ma` compares the current OS against the string constant `osString`.
*/
private predicate isOsFromSystemProp(MethodAccess ma, string osString) {
TaintTracking::localExprTaint(getSystemProperty("os.name"), ma.getQualifier()) and // Call from System.getProperty (or equivalent) to some partial match method
exists(StringPartialMatchMethod m, CompileTimeConstantExpr matchedStringConstant |
m = ma.getMethod() and
matchedStringConstant.getStringValue().toLowerCase() = osString
|
DataFlow::localExprFlow(matchedStringConstant, ma.getArgument(m.getMatchParameterIndex()))
)
}
private class IsWindowsFromSystemProp extends IsWindowsGuard instanceof MethodAccess {
IsWindowsFromSystemProp() { isOsFromSystemProp(this, any(string s | s.regexpMatch("windows?"))) }
}
/**
* Holds when the Guard is an equality check between the system property with the name `propertyName`
* and the string or char constant `compareToLiteral`, and the branch evaluates to `branch`.
*/
private Guard isOsFromSystemPropertyEqualityCheck(
string propertyName, string compareToLiteral, boolean branch
) {
result
.isEquality(getSystemProperty(propertyName),
any(Literal literal |
(literal instanceof CharacterLiteral or literal instanceof StringLiteral) and
literal.getValue() = compareToLiteral
), branch)
}
private class IsWindowsFromPathSeparator extends IsWindowsGuard {
IsWindowsFromPathSeparator() {
this = isOsFromSystemPropertyEqualityCheck("path.separator", ";", true) or
this = isOsFromSystemPropertyEqualityCheck("path.separator", ":", false)
}
}
private class IsWindowsFromFileSeparator extends IsWindowsGuard {
IsWindowsFromFileSeparator() {
this = isOsFromSystemPropertyEqualityCheck("file.separator", "\\", true) or
this = isOsFromSystemPropertyEqualityCheck("file.separator", "/", false)
}
}
private class IsUnixFromPathSeparator extends IsUnixGuard {
IsUnixFromPathSeparator() {
this = isOsFromSystemPropertyEqualityCheck("path.separator", ":", true) or
this = isOsFromSystemPropertyEqualityCheck("path.separator", ";", false)
}
}
private class IsUnixFromFileSeparator extends IsUnixGuard {
IsUnixFromFileSeparator() {
this = isOsFromSystemPropertyEqualityCheck("file.separator", "/", true) or
this = isOsFromSystemPropertyEqualityCheck("file.separator", "\\", false)
}
}
private class IsUnixFromSystemProp extends IsSpecificUnixVariant instanceof MethodAccess {
IsUnixFromSystemProp() {
isOsFromSystemProp(this, any(string s | s.regexpMatch(["mac.*", "linux.*"])))
}
}
bindingset[fieldNamePattern]
private predicate isOsFromApacheCommons(FieldAccess fa, string fieldNamePattern) {
exists(Field f | f = fa.getField() |
f.getDeclaringType() instanceof TypeApacheSystemUtils and
f.getName().matches(fieldNamePattern)
)
}
private class IsWindowsFromApacheCommons extends IsWindowsGuard instanceof FieldAccess {
IsWindowsFromApacheCommons() { isOsFromApacheCommons(this, "IS_OS_WINDOWS") }
}
private class IsSpecificWindowsVariantFromApacheCommons extends IsSpecificWindowsVariant instanceof FieldAccess {
IsSpecificWindowsVariantFromApacheCommons() { isOsFromApacheCommons(this, "IS_OS_WINDOWS_%") }
}
private class IsUnixFromApacheCommons extends IsUnixGuard instanceof FieldAccess {
IsUnixFromApacheCommons() { isOsFromApacheCommons(this, "IS_OS_UNIX") }
}
private class IsSpecificUnixVariantFromApacheCommons extends IsSpecificUnixVariant instanceof FieldAccess {
IsSpecificUnixVariantFromApacheCommons() {
isOsFromApacheCommons(this,
[
"IS_OS_AIX", "IS_OS_HP_UX", "IS_OS_IRIX", "IS_OS_LINUX", "IS_OS_MAC%", "IS_OS_FREE_BSD",
"IS_OS_OPEN_BSD", "IS_OS_NET_BSD", "IS_OS_SOLARIS", "IS_OS_SUN_OS", "IS_OS_ZOS"
])
}
}
/**
* A guard that checks if the `java.nio.file.FileSystem` supports posix file permissions.
* This is often used to infer if the OS is unix-based and can generally be considered to be true for all unix-based OSes
* ([source](https://en.wikipedia.org/wiki/POSIX#POSIX-oriented_operating_systems)).
* Looks for calls to `contains("posix")` on the `supportedFileAttributeViews()` method returned by `FileSystem`.
*/
private class IsUnixFromPosixFromFileSystem extends IsUnixGuard instanceof MethodAccess {
IsUnixFromPosixFromFileSystem() {
exists(Method m | m = this.getMethod() |
m.getDeclaringType()
.getASupertype*()
.getSourceDeclaration()
.hasQualifiedName("java.util", "Set") and
m.hasName("contains")
) and
this.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "posix" and
exists(Method supportedFileAttributeViewsMethod |
supportedFileAttributeViewsMethod.hasName("supportedFileAttributeViews") and
supportedFileAttributeViewsMethod.getDeclaringType() instanceof TypeFileSystem
|
DataFlow::localExprFlow(any(MethodAccess ma |
ma.getMethod() = supportedFileAttributeViewsMethod
), super.getQualifier())
)
}
}

View File

@@ -11,7 +11,6 @@
*/
import java
import semmle.code.java.os.OSCheck
import TempDirUtils
import DataFlow::PathGraph
import semmle.code.java.dataflow.TaintTracking2
@@ -103,36 +102,11 @@ private class FileCreateTempFileSink extends FileCreationSink {
}
}
/**
* A guard that holds when the program is definitely running under some version of Windows.
*/
abstract private class WindowsOsBarrierGuard extends DataFlow::BarrierGuard { }
private class IsNotUnixBarrierGuard extends WindowsOsBarrierGuard instanceof IsUnixGuard {
override predicate checks(Expr e, boolean branch) {
this.controls(e.getBasicBlock(), branch.booleanNot())
}
}
private class IsWindowsBarrierGuard extends WindowsOsBarrierGuard instanceof IsWindowsGuard {
override predicate checks(Expr e, boolean branch) { this.controls(e.getBasicBlock(), branch) }
}
private class IsSpecificWindowsBarrierGuard extends WindowsOsBarrierGuard instanceof IsSpecificWindowsVariant {
override predicate checks(Expr e, boolean branch) {
branch = true and this.controls(e.getBasicBlock(), branch)
}
}
/**
* A taint tracking configuration tracking the access of the system temporary directory
* flowing to the creation of files or directories.
*/
private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Configuration {
TempDirSystemGetPropertyToCreateConfig() { this = "TempDirSystemGetPropertyToCreateConfig" }
override predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof ExprSystemGetPropertyTempDirTainted
source.asExpr() instanceof MethodAccessSystemGetPropertyTempDirTainted
}
/**
@@ -155,10 +129,6 @@ private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Conf
sanitizer.asExpr() = sanitisingMethodAccess.getArgument(0)
)
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof WindowsOsBarrierGuard
}
}
/**
@@ -177,8 +147,10 @@ private class TempDirSystemGetPropertyDirectlyToMkdirConfig extends TaintTrackin
}
override predicate isSource(DataFlow::Node node) {
exists(ExprSystemGetPropertyTempDirTainted propertyGetExpr, DataFlow::Node callSite |
DataFlow::localFlow(DataFlow::exprNode(propertyGetExpr), callSite)
exists(
MethodAccessSystemGetPropertyTempDirTainted propertyGetMethodAccess, DataFlow::Node callSite
|
DataFlow::localFlow(DataFlow::exprNode(propertyGetMethodAccess), callSite)
|
isFileConstructorArgument(callSite.asExpr(), node.asExpr(), 1)
)

View File

@@ -1,14 +1,10 @@
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.EnumSet;
public class TempDirUsageSafe {
void exampleSafe() throws IOException {
Path temp1 = Files.createTempFile("random", ".txt"); // GOOD: File has permissions `-rw-------`
@@ -34,7 +30,7 @@ public class TempDirUsageSafe {
createTempFile(tempChildFile.toPath()); // GOOD: Good has permissions `-rw-------`
}
static void createTempFile(Path tempDirChild) {
static void createTempFile(Path tempDir) {
try {
if (tempDirChild.getFileSystem().supportedFileAttributeViews().contains("posix")) {
// Explicit permissions setting is only required on unix-like systems because

View File

@@ -3,14 +3,34 @@
*/
import java
private import semmle.code.java.environment.SystemProperty
import semmle.code.java.dataflow.FlowSources
/**
* A method or field access that returns a `String` or `File` that has been tainted by `System.getProperty("java.io.tmpdir")`.
* A method that returns a `String` or `File` that has been tainted by `System.getProperty("java.io.tmpdir")`.
*/
class ExprSystemGetPropertyTempDirTainted extends Expr {
ExprSystemGetPropertyTempDirTainted() { this = getSystemProperty("java.io.tmpdir") }
abstract class MethodAccessSystemGetPropertyTempDirTainted extends MethodAccess { }
/**
* Method access `System.getProperty("java.io.tmpdir")`.
*/
private class MethodAccessSystemGetPropertyTempDir extends MethodAccessSystemGetPropertyTempDirTainted,
MethodAccessSystemGetProperty {
MethodAccessSystemGetPropertyTempDir() {
this.hasCompileTimeConstantGetPropertyName("java.io.tmpdir")
}
}
/**
* A method call to the `org.apache.commons.io.FileUtils` methods `getTempDirectory` or `getTempDirectoryPath`.
*/
private class MethodAccessApacheFileUtilsTempDir extends MethodAccessSystemGetPropertyTempDirTainted {
MethodAccessApacheFileUtilsTempDir() {
exists(Method m |
m.getDeclaringType().hasQualifiedName("org.apache.commons.io", "FileUtils") and
m.hasName(["getTempDirectory", "getTempDirectoryPath"]) and
this.getMethod() = m
)
}
}
/**

View File

@@ -1,7 +0,0 @@
---
category: minorAnalysis
---
* Added new guards `IsWindowsGuard`, `IsSpecificWindowsVariant`, `IsUnixGuard`, and `IsSpecificUnixVariant` to detect OS specific guards.
* Added a new predicate `getSystemProperty` that gets all expressions that retrieve system properties from a variety of sources (eg. alternative JDK API's, Google Guava, Apache Commons, Apache IO, etc..).
* Updated "Local information disclosure in a temporary directory" (`java/local-temp-file-or-directory-information-disclosure`) to remove false-positives when OS is properly used as logical guard.

View File

@@ -5,7 +5,7 @@ private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.internal.ContainerFlow
private import semmle.code.java.dataflow.internal.DataFlowImplCommon
private Method superImpl(Method m) {
Method superImpl(Method m) {
result = m.getAnOverride() and
not exists(result.getAnOverride()) and
not m instanceof ToStringMethod

View File

@@ -60,75 +60,6 @@ jdk/A.java:
# 28| 0: [ArrayTypeAccess] ...[]
# 28| 0: [TypeAccess] String
# 28| 5: [BlockStmt] { ... }
jdk/StringMatch.java:
# 0| [CompilationUnit] StringMatch
# 1| 1: [Class] StringMatch
# 2| 3: [FieldDeclaration] String STR;
# 2| -1: [TypeAccess] String
# 2| 0: [StringLiteral] "the quick brown fox jumps over the lazy dog"
# 4| 4: [Method] a
# 4| 3: [TypeAccess] void
# 4| 5: [BlockStmt] { ... }
# 5| 0: [ExprStmt] <Expr>;
# 5| 0: [MethodAccess] matches(...)
# 5| -1: [VarAccess] STR
# 5| 0: [StringLiteral] "[a-z]+"
# 8| 5: [Method] b
# 8| 3: [TypeAccess] void
# 8| 5: [BlockStmt] { ... }
# 9| 0: [ExprStmt] <Expr>;
# 9| 0: [MethodAccess] contains(...)
# 9| -1: [VarAccess] STR
# 9| 0: [StringLiteral] "the"
# 12| 6: [Method] c
# 12| 3: [TypeAccess] void
# 12| 5: [BlockStmt] { ... }
# 13| 0: [ExprStmt] <Expr>;
# 13| 0: [MethodAccess] startsWith(...)
# 13| -1: [VarAccess] STR
# 13| 0: [StringLiteral] "the"
# 16| 7: [Method] d
# 16| 3: [TypeAccess] void
# 16| 5: [BlockStmt] { ... }
# 17| 0: [ExprStmt] <Expr>;
# 17| 0: [MethodAccess] endsWith(...)
# 17| -1: [VarAccess] STR
# 17| 0: [StringLiteral] "dog"
# 20| 8: [Method] e
# 20| 3: [TypeAccess] void
# 20| 5: [BlockStmt] { ... }
# 21| 0: [ExprStmt] <Expr>;
# 21| 0: [MethodAccess] indexOf(...)
# 21| -1: [VarAccess] STR
# 21| 0: [StringLiteral] "lazy"
# 24| 9: [Method] f
# 24| 3: [TypeAccess] void
# 24| 5: [BlockStmt] { ... }
# 25| 0: [ExprStmt] <Expr>;
# 25| 0: [MethodAccess] lastIndexOf(...)
# 25| -1: [VarAccess] STR
# 25| 0: [StringLiteral] "lazy"
# 28| 10: [Method] g
# 28| 3: [TypeAccess] void
# 28| 5: [BlockStmt] { ... }
# 29| 0: [ExprStmt] <Expr>;
# 29| 0: [MethodAccess] regionMatches(...)
# 29| -1: [VarAccess] STR
# 29| 0: [IntegerLiteral] 0
# 29| 1: [StringLiteral] "fox"
# 29| 2: [IntegerLiteral] 0
# 29| 3: [IntegerLiteral] 4
# 32| 11: [Method] h
# 32| 3: [TypeAccess] void
# 32| 5: [BlockStmt] { ... }
# 33| 0: [ExprStmt] <Expr>;
# 33| 0: [MethodAccess] regionMatches(...)
# 33| -1: [VarAccess] STR
# 33| 0: [BooleanLiteral] true
# 33| 1: [IntegerLiteral] 0
# 33| 2: [StringLiteral] "FOX"
# 33| 3: [IntegerLiteral] 0
# 33| 4: [IntegerLiteral] 4
jdk/SystemGetPropertyCall.java:
# 0| [CompilationUnit] SystemGetPropertyCall
# 3| 1: [Class] SystemGetPropertyCall

View File

@@ -1,8 +0,0 @@
| jdk/StringMatch.java:5:9:5:29 | matches(...) | jdk/StringMatch.java:5:21:5:28 | "[a-z]+" |
| jdk/StringMatch.java:9:9:9:27 | contains(...) | jdk/StringMatch.java:9:22:9:26 | "the" |
| jdk/StringMatch.java:13:9:13:29 | startsWith(...) | jdk/StringMatch.java:13:24:13:28 | "the" |
| jdk/StringMatch.java:17:9:17:27 | endsWith(...) | jdk/StringMatch.java:17:22:17:26 | "dog" |
| jdk/StringMatch.java:21:9:21:27 | indexOf(...) | jdk/StringMatch.java:21:21:21:26 | "lazy" |
| jdk/StringMatch.java:25:9:25:31 | lastIndexOf(...) | jdk/StringMatch.java:25:25:25:30 | "lazy" |
| jdk/StringMatch.java:29:9:29:41 | regionMatches(...) | jdk/StringMatch.java:29:30:29:34 | "fox" |
| jdk/StringMatch.java:33:9:33:47 | regionMatches(...) | jdk/StringMatch.java:33:36:33:40 | "FOX" |

View File

@@ -1,5 +0,0 @@
import java
from MethodAccess ma, StringPartialMatchMethod m
where ma.getMethod() = m
select ma, ma.getArgument(m.getMatchParameterIndex())

View File

@@ -1,35 +0,0 @@
public class StringMatch {
private static String STR = "the quick brown fox jumps over the lazy dog";
void a() {
STR.matches("[a-z]+");
}
void b() {
STR.contains("the");
}
void c() {
STR.startsWith("the");
}
void d() {
STR.endsWith("dog");
}
void e() {
STR.indexOf("lazy");
}
void f() {
STR.lastIndexOf("lazy");
}
void g() {
STR.regionMatches(0, "fox", 0, 4);
}
void h() {
STR.regionMatches(true, 0, "FOX", 0, 4);
}
}

View File

@@ -1,30 +0,0 @@
import java.io.File;
import java.util.Properties;
import org.apache.commons.lang3.SystemUtils;
import com.google.common.base.StandardSystemProperty;
public class SystemPropertyAccess {
private static final Properties SYSTEM_PROPERTIES = System.getProperties();
void test() {
System.getProperty("os.name");
System.getProperty("os.name", "default");
System.getProperties().getProperty("os.name");
System.getProperties().get("java.io.tmpdir");
SYSTEM_PROPERTIES.getProperty("java.home");
SYSTEM_PROPERTIES.get("file.encoding");
System.lineSeparator();
String awtToolkit = SystemUtils.AWT_TOOLKIT;
String fileEncoding = SystemUtils.FILE_ENCODING;
String tmpDir = SystemUtils.JAVA_IO_TMPDIR;
String separator = File.separator;
char separatorChar = File.separatorChar;
String pathSeparator = File.pathSeparator;
char pathSeparatorChar = File.pathSeparatorChar;
StandardSystemProperty.JAVA_VERSION.value();
StandardSystemProperty property = StandardSystemProperty.JAVA_VERSION;
property.value();
System.getProperty(StandardSystemProperty.JAVA_IO_TMPDIR.key());
}
}

View File

@@ -1,57 +0,0 @@
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:93:5:93:50 | AWT_TOOLKIT | awt.toolkit |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:115:5:115:52 | FILE_ENCODING | file.encoding |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:141:5:142:53 | FILE_SEPARATOR | file.separator |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:160:5:160:53 | JAVA_AWT_FONTS | java.awt.fonts |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:178:5:178:59 | JAVA_AWT_GRAPHICSENV | java.awt.graphicsenv |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:199:5:199:56 | JAVA_AWT_HEADLESS | java.awt.headless |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:217:5:217:58 | JAVA_AWT_PRINTERJOB | java.awt.printerjob |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:235:5:235:54 | JAVA_CLASS_PATH | java.class.path |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:253:5:253:57 | JAVA_CLASS_VERSION | java.class.version |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:272:5:272:52 | JAVA_COMPILER | java.compiler |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:308:5:308:52 | JAVA_EXT_DIRS | java.ext.dirs |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:326:5:326:48 | JAVA_HOME | java.home |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:344:5:344:53 | JAVA_IO_TMPDIR | java.io.tmpdir |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:362:5:362:56 | JAVA_LIBRARY_PATH | java.library.path |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:381:5:381:56 | JAVA_RUNTIME_NAME | java.runtime.name |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:400:5:400:59 | JAVA_RUNTIME_VERSION | java.runtime.version |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:418:5:418:62 | JAVA_SPECIFICATION_NAME | java.specification.name |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:436:5:436:64 | JAVA_SPECIFICATION_VENDOR | java.specification.vendor |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:473:5:474:13 | JAVA_UTIL_PREFS_PREFERENCES_FACTORY | java.util.prefs.PreferencesFactory |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:492:5:492:50 | JAVA_VENDOR | java.vendor |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:510:5:510:54 | JAVA_VENDOR_URL | java.vendor.url |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:528:5:528:51 | JAVA_VERSION | java.version |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:547:5:547:51 | JAVA_VM_INFO | java.vm.info |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:565:5:565:51 | JAVA_VM_NAME | java.vm.name |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:583:5:583:65 | JAVA_VM_SPECIFICATION_NAME | java.vm.specification.name |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:601:5:601:67 | JAVA_VM_SPECIFICATION_VENDOR | java.vm.specification.vendor |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:637:5:637:53 | JAVA_VM_VENDOR | java.vm.vendor |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:655:5:655:54 | JAVA_VM_VERSION | java.vm.version |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:674:5:675:53 | LINE_SEPARATOR | line.separator |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:693:5:693:46 | OS_ARCH | os.arch |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:711:5:711:46 | OS_NAME | os.name |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:729:5:729:49 | OS_VERSION | os.version |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:749:5:750:53 | PATH_SEPARATOR | path.separator |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:770:5:770:73 | USER_COUNTRY | user.country |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:788:5:788:47 | USER_DIR | user.dir |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:806:5:806:48 | USER_HOME | user.home |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:825:5:825:52 | USER_LANGUAGE | user.language |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:843:5:843:48 | USER_NAME | user.name |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:861:5:861:52 | USER_TIMEZONE | user.timezone |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1762:47:1762:63 | JAVA_AWT_HEADLESS | java.awt.headless |
| SystemPropertyAccess.java:10:9:10:37 | getProperty(...) | os.name |
| SystemPropertyAccess.java:11:9:11:48 | getProperty(...) | os.name |
| SystemPropertyAccess.java:12:9:12:53 | getProperty(...) | os.name |
| SystemPropertyAccess.java:13:9:13:52 | get(...) | java.io.tmpdir |
| SystemPropertyAccess.java:14:9:14:50 | getProperty(...) | java.home |
| SystemPropertyAccess.java:15:9:15:46 | get(...) | file.encoding |
| SystemPropertyAccess.java:16:9:16:30 | lineSeparator(...) | line.separator |
| SystemPropertyAccess.java:17:29:17:51 | SystemUtils.AWT_TOOLKIT | awt.toolkit |
| SystemPropertyAccess.java:18:31:18:55 | SystemUtils.FILE_ENCODING | file.encoding |
| SystemPropertyAccess.java:19:25:19:50 | SystemUtils.JAVA_IO_TMPDIR | java.io.tmpdir |
| SystemPropertyAccess.java:20:28:20:41 | File.separator | file.separator |
| SystemPropertyAccess.java:21:30:21:47 | File.separatorChar | file.separator |
| SystemPropertyAccess.java:22:32:22:49 | File.pathSeparator | path.separator |
| SystemPropertyAccess.java:23:34:23:55 | File.pathSeparatorChar | path.separator |
| SystemPropertyAccess.java:24:9:24:51 | value(...) | java.version |
| SystemPropertyAccess.java:26:9:26:24 | value(...) | java.version |
| SystemPropertyAccess.java:27:9:27:71 | getProperty(...) | java.io.tmpdir |

View File

@@ -1,6 +0,0 @@
import default
import semmle.code.java.environment.SystemProperty
from Expr systemPropertyAccess, string propertyName
where systemPropertyAccess = getSystemProperty(propertyName)
select systemPropertyAccess, propertyName

View File

@@ -1 +0,0 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../stubs/apache-commons-lang3-3.7/:${testdir}/../../stubs/guava-30.0/

View File

@@ -1,147 +0,0 @@
import java.io.File;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import org.apache.commons.lang3.SystemUtils;
public class Test {
/**
* Should only be called on windows
*/
private void onlyOnWindows() {}
/**
* Should only be called on unix-like systems
*/
private void onlyOnUnix() {}
void testWindows() {
if (System.getProperty("os.name").contains("Windows")) {
onlyOnWindows();
}
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
onlyOnWindows();
}
if (System.getProperty("os.name").toLowerCase().contains("window")) {
onlyOnWindows();
}
if (System.getProperty("os.name").toUpperCase().contains("WINDOWS")) {
onlyOnWindows();
}
if (SystemUtils.IS_OS_WINDOWS) {
onlyOnWindows();
} else {
onlyOnUnix();
}
if (SystemUtils.IS_OS_WINDOWS_XP) {
onlyOnWindows();
} else {
// Might be another version of windows
}
if (File.pathSeparatorChar == ';') {
onlyOnWindows();
}
if (File.pathSeparator == ";") {
onlyOnWindows();
}
if (File.separatorChar == '\\') {
onlyOnWindows();
}
if (File.separator == "\\") {
onlyOnWindows();
}
if (System.getProperty("path.separator").equals(";")) {
onlyOnWindows();
}
}
void testUnix() {
if (Path.of("whatever").getFileSystem().supportedFileAttributeViews().contains("posix")) {
onlyOnUnix();
}
if (FileSystems.getDefault().supportedFileAttributeViews().contains("posix")) {
onlyOnUnix();
}
if (SystemUtils.IS_OS_UNIX) {
onlyOnUnix();
} else {
// Reasonable assumption, maybe not 100% accurate, but it's 'good enough'
onlyOnWindows();
}
if (File.pathSeparatorChar == ':') {
onlyOnUnix();
}
if (File.pathSeparator == ":") {
onlyOnUnix();
}
if (File.separatorChar == '/') {
onlyOnUnix();
}
if (File.separator == "/") {
onlyOnUnix();
}
if (System.getProperty("path.separator").equals(":")) {
onlyOnUnix();
}
}
void testLinux() {
if (System.getProperty("os.name").toLowerCase().contains("linux")) {
onlyOnUnix();
}
if (System.getProperty("os.name").contains("Linux")) {
onlyOnUnix();
}
if (SystemUtils.IS_OS_LINUX) {
onlyOnUnix();
} else {
// Might be another different unix-like system, so this can't be `onlyOnWindows()`.
}
if (!SystemUtils.IS_OS_LINUX) {
// Might be another different unix-like system, so this can't be `onlyOnWindows()`.
} else {
onlyOnUnix();
}
}
void testMacOs() {
if (System.getProperty("os.name").contains("Mac OS X")) {
onlyOnUnix();
}
if (System.getProperty("os.name").toLowerCase().contains("mac")) {
onlyOnUnix();
}
if (SystemUtils.IS_OS_MAC) {
onlyOnUnix();
} else {
// Can't assume this is windows, it could be another unix-like OS
}
if (SystemUtils.IS_OS_MAC_OSX_MOJAVE) {
onlyOnUnix();
}
}
}

View File

@@ -1 +0,0 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../stubs/apache-commons-lang3-3.7/

View File

@@ -1,37 +0,0 @@
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1079:5:1079:80 | IS_OS_AIX |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1091:5:1091:82 | IS_OS_HP_UX |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1115:5:1115:81 | IS_OS_IRIX |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1127:5:1127:82 | IS_OS_LINUX |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1139:5:1139:80 | IS_OS_MAC |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1151:5:1151:84 | IS_OS_MAC_OSX |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1163:5:1163:92 | IS_OS_MAC_OSX_CHEETAH |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1175:5:1175:89 | IS_OS_MAC_OSX_PUMA |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1187:5:1187:91 | IS_OS_MAC_OSX_JAGUAR |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1199:5:1199:92 | IS_OS_MAC_OSX_PANTHER |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1211:5:1211:90 | IS_OS_MAC_OSX_TIGER |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1223:5:1223:92 | IS_OS_MAC_OSX_LEOPARD |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1235:5:1235:97 | IS_OS_MAC_OSX_SNOW_LEOPARD |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1247:5:1247:89 | IS_OS_MAC_OSX_LION |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1259:5:1259:98 | IS_OS_MAC_OSX_MOUNTAIN_LION |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1271:5:1271:94 | IS_OS_MAC_OSX_MAVERICKS |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1283:5:1283:93 | IS_OS_MAC_OSX_YOSEMITE |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1295:5:1295:95 | IS_OS_MAC_OSX_EL_CAPITAN |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1307:5:1307:91 | IS_OS_MAC_OSX_SIERRA |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1319:5:1319:96 | IS_OS_MAC_OSX_HIGH_SIERRA |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1331:5:1331:91 | IS_OS_MAC_OSX_MOJAVE |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1343:5:1343:93 | IS_OS_MAC_OSX_CATALINA |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1355:5:1355:92 | IS_OS_MAC_OSX_BIG_SUR |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1367:5:1367:85 | IS_OS_FREE_BSD |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1379:5:1379:85 | IS_OS_OPEN_BSD |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1391:5:1391:84 | IS_OS_NET_BSD |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1415:5:1415:84 | IS_OS_SOLARIS |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1427:5:1427:83 | IS_OS_SUN_OS |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1625:5:1625:80 | IS_OS_ZOS |
| Test.java:107:13:107:73 | contains(...) |
| Test.java:111:13:111:59 | contains(...) |
| Test.java:115:13:115:35 | SystemUtils.IS_OS_LINUX |
| Test.java:121:14:121:36 | SystemUtils.IS_OS_LINUX |
| Test.java:129:13:129:62 | contains(...) |
| Test.java:133:14:133:72 | contains(...) |
| Test.java:137:14:137:34 | SystemUtils.IS_OS_MAC |
| Test.java:143:14:143:45 | SystemUtils.IS_OS_MAC_OSX_MOJAVE |

View File

@@ -1,5 +0,0 @@
import default
import semmle.code.java.os.OSCheck
from IsSpecificUnixVariant isAnyUnix
select isAnyUnix

View File

@@ -1,14 +0,0 @@
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1463:5:1463:89 | IS_OS_WINDOWS_2000 |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1475:5:1475:89 | IS_OS_WINDOWS_2003 |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1487:5:1487:89 | IS_OS_WINDOWS_2008 |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1499:5:1499:89 | IS_OS_WINDOWS_2012 |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1511:5:1511:87 | IS_OS_WINDOWS_95 |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1523:5:1523:87 | IS_OS_WINDOWS_98 |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1535:5:1535:87 | IS_OS_WINDOWS_ME |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1547:5:1547:87 | IS_OS_WINDOWS_NT |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1559:5:1559:87 | IS_OS_WINDOWS_XP |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1572:5:1572:90 | IS_OS_WINDOWS_VISTA |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1584:5:1584:86 | IS_OS_WINDOWS_7 |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1596:5:1596:86 | IS_OS_WINDOWS_8 |
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1608:5:1608:87 | IS_OS_WINDOWS_10 |
| Test.java:42:13:42:40 | SystemUtils.IS_OS_WINDOWS_XP |

View File

@@ -1,5 +0,0 @@
import default
import semmle.code.java.os.OSCheck
from IsSpecificWindowsVariant isAnyWindows
select isAnyWindows

View File

@@ -1,9 +0,0 @@
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1439:5:1439:81 | IS_OS_UNIX |
| Test.java:70:13:70:95 | contains(...) |
| Test.java:74:13:74:84 | contains(...) |
| Test.java:78:13:78:34 | SystemUtils.IS_OS_UNIX |
| Test.java:85:13:85:41 | ... == ... |
| Test.java:89:13:89:37 | ... == ... |
| Test.java:93:13:93:37 | ... == ... |
| Test.java:97:13:97:33 | ... == ... |
| Test.java:101:13:101:60 | equals(...) |

View File

@@ -1,5 +0,0 @@
import default
import semmle.code.java.os.OSCheck
from IsUnixGuard isUnix
select isUnix

View File

@@ -1,11 +0,0 @@
| ../../stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/SystemUtils.java:1451:5:1451:84 | IS_OS_WINDOWS |
| Test.java:20:13:20:61 | contains(...) |
| Test.java:24:13:24:75 | contains(...) |
| Test.java:28:13:28:74 | contains(...) |
| Test.java:32:13:32:75 | contains(...) |
| Test.java:36:13:36:37 | SystemUtils.IS_OS_WINDOWS |
| Test.java:48:13:48:41 | ... == ... |
| Test.java:52:13:52:37 | ... == ... |
| Test.java:56:13:56:38 | ... == ... |
| Test.java:60:13:60:34 | ... == ... |
| Test.java:64:13:64:60 | equals(...) |

View File

@@ -1,5 +0,0 @@
import default
import semmle.code.java.os.OSCheck
from IsWindowsGuard isWindows
select isWindows

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