mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge pull request #13595 from hvitved/csharp/use-shared-cfg-pack
C#: Adopt shared CFG construction library from shared `controlflow` pack
This commit is contained in:
@@ -483,10 +483,6 @@
|
|||||||
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll",
|
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll",
|
||||||
"swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll"
|
"swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll"
|
||||||
],
|
],
|
||||||
"CFG": [
|
|
||||||
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",
|
|
||||||
"swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImplShared.qll"
|
|
||||||
],
|
|
||||||
"TypeTracker": [
|
"TypeTracker": [
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll"
|
"ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll"
|
||||||
|
|||||||
@@ -2,15 +2,14 @@ import csharp
|
|||||||
import semmle.code.csharp.controlflow.internal.Completion
|
import semmle.code.csharp.controlflow.internal.Completion
|
||||||
import semmle.code.csharp.controlflow.internal.PreBasicBlocks
|
import semmle.code.csharp.controlflow.internal.PreBasicBlocks
|
||||||
import ControlFlow
|
import ControlFlow
|
||||||
import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl
|
import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl::Consistency
|
||||||
import semmle.code.csharp.controlflow.internal.Splitting
|
import semmle.code.csharp.controlflow.internal.Splitting
|
||||||
import Consistency
|
|
||||||
|
|
||||||
private predicate splitBB(ControlFlow::BasicBlock bb) {
|
private predicate splitBB(ControlFlow::BasicBlock bb) {
|
||||||
exists(ControlFlow::Node first |
|
exists(ControlFlow::Node first |
|
||||||
first = bb.getFirstNode() and
|
first = bb.getFirstNode() and
|
||||||
first.isJoin() and
|
first.isJoin() and
|
||||||
strictcount(first.getAPredecessor().getElement()) = 1
|
strictcount(first.getAPredecessor().getAstNode()) = 1
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ private class MyConsistencyConfiguration extends ConsistencyConfiguration {
|
|||||||
// TODO: Remove once static initializers are folded into the
|
// TODO: Remove once static initializers are folded into the
|
||||||
// static constructors
|
// static constructors
|
||||||
exists(ControlFlow::Node cfn |
|
exists(ControlFlow::Node cfn |
|
||||||
cfn.getElement() = any(FieldOrProperty f | f.isStatic()).getAChild+() and
|
cfn.getAstNode() = any(FieldOrProperty f | f.isStatic()).getAChild+() and
|
||||||
cfn = n.getControlFlowNode()
|
cfn = n.getControlFlowNode()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ private class MyConsistencyConfiguration extends ConsistencyConfiguration {
|
|||||||
// TODO: Remove once static initializers are folded into the
|
// TODO: Remove once static initializers are folded into the
|
||||||
// static constructors
|
// static constructors
|
||||||
exists(ControlFlow::Node cfn |
|
exists(ControlFlow::Node cfn |
|
||||||
cfn.getElement() = any(FieldOrProperty f | f.isStatic()).getAChild+() and
|
cfn.getAstNode() = any(FieldOrProperty f | f.isStatic()).getAChild+() and
|
||||||
cfn = call.getControlFlowNode()
|
cfn = call.getControlFlowNode()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ extractor: csharp
|
|||||||
library: true
|
library: true
|
||||||
upgrades: upgrades
|
upgrades: upgrades
|
||||||
dependencies:
|
dependencies:
|
||||||
|
codeql/controlflow: ${workspace}
|
||||||
codeql/dataflow: ${workspace}
|
codeql/dataflow: ${workspace}
|
||||||
codeql/mad: ${workspace}
|
codeql/mad: ${workspace}
|
||||||
codeql/ssa: ${workspace}
|
codeql/ssa: ${workspace}
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
/** Provides classes for assertions. */
|
/** Provides classes for assertions. */
|
||||||
|
|
||||||
private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl
|
|
||||||
private import semmle.code.csharp.frameworks.system.Diagnostics
|
private import semmle.code.csharp.frameworks.system.Diagnostics
|
||||||
private import semmle.code.csharp.frameworks.system.diagnostics.Contracts
|
private import semmle.code.csharp.frameworks.system.diagnostics.Contracts
|
||||||
private import semmle.code.csharp.frameworks.test.VisualStudio
|
private import semmle.code.csharp.frameworks.test.VisualStudio
|
||||||
private import semmle.code.csharp.frameworks.System
|
private import semmle.code.csharp.frameworks.System
|
||||||
private import ControlFlow
|
|
||||||
private import ControlFlow::BasicBlocks
|
|
||||||
|
|
||||||
private newtype TAssertionFailure =
|
private newtype TAssertionFailure =
|
||||||
TExceptionAssertionFailure(Class c) or
|
TExceptionAssertionFailure(Class c) or
|
||||||
|
|||||||
@@ -400,13 +400,13 @@ class ExitBasicBlock extends BasicBlock {
|
|||||||
|
|
||||||
private module JoinBlockPredecessors {
|
private module JoinBlockPredecessors {
|
||||||
private import ControlFlow::Nodes
|
private import ControlFlow::Nodes
|
||||||
private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl
|
private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl as Impl
|
||||||
|
|
||||||
int getId(JoinBlockPredecessor jbp) {
|
int getId(JoinBlockPredecessor jbp) {
|
||||||
exists(ControlFlowTree::Range_ t | ControlFlowTree::idOf(t, result) |
|
exists(Impl::AstNode n | result = n.getId() |
|
||||||
t = jbp.getFirstNode().getElement()
|
n = jbp.getFirstNode().getAstNode()
|
||||||
or
|
or
|
||||||
t = jbp.(EntryBasicBlock).getCallable()
|
n = jbp.(EntryBasicBlock).getCallable()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ private import ControlFlow
|
|||||||
private import ControlFlow::BasicBlocks
|
private import ControlFlow::BasicBlocks
|
||||||
private import SuccessorTypes
|
private import SuccessorTypes
|
||||||
private import semmle.code.csharp.Caching
|
private import semmle.code.csharp.Caching
|
||||||
private import internal.ControlFlowGraphImpl
|
private import internal.ControlFlowGraphImpl as Impl
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A program element that can possess control flow. That is, either a statement or
|
* A program element that can possess control flow. That is, either a statement or
|
||||||
@@ -39,20 +39,20 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
|
|||||||
* several `ControlFlow::Node`s, for example to represent the continuation
|
* several `ControlFlow::Node`s, for example to represent the continuation
|
||||||
* flow in a `try/catch/finally` construction.
|
* flow in a `try/catch/finally` construction.
|
||||||
*/
|
*/
|
||||||
Nodes::ElementNode getAControlFlowNode() { result.getElement() = this }
|
Nodes::ElementNode getAControlFlowNode() { result.getAstNode() = this }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a first control flow node executed within this element.
|
* Gets a first control flow node executed within this element.
|
||||||
*/
|
*/
|
||||||
Nodes::ElementNode getAControlFlowEntryNode() {
|
Nodes::ElementNode getAControlFlowEntryNode() {
|
||||||
result = getAControlFlowEntryNode(this).getAControlFlowNode()
|
result = Impl::getAControlFlowEntryNode(this).(ControlFlowElement).getAControlFlowNode()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a potential last control flow node executed within this element.
|
* Gets a potential last control flow node executed within this element.
|
||||||
*/
|
*/
|
||||||
Nodes::ElementNode getAControlFlowExitNode() {
|
Nodes::ElementNode getAControlFlowExitNode() {
|
||||||
result = getAControlFlowExitNode(this).getAControlFlowNode()
|
result = Impl::getAControlFlowExitNode(this).(ControlFlowElement).getAControlFlowNode()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,7 +88,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
|
|||||||
) {
|
) {
|
||||||
// Only calculate dominance by explicit recursion for split nodes;
|
// Only calculate dominance by explicit recursion for split nodes;
|
||||||
// all other nodes can use regular CFG dominance
|
// all other nodes can use regular CFG dominance
|
||||||
this instanceof SplitControlFlowElement and
|
this instanceof Impl::SplitAstNode and
|
||||||
cb.getLastNode() = this.getAControlFlowNode() and
|
cb.getLastNode() = this.getAControlFlowNode() and
|
||||||
succ = cb.getASuccessorByType(s)
|
succ = cb.getASuccessorByType(s)
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
|
|||||||
succ.dominates(pred)
|
succ.dominates(pred)
|
||||||
or
|
or
|
||||||
// `pred` might be another split of this element
|
// `pred` might be another split of this element
|
||||||
pred.getLastNode().getElement() = this and
|
pred.getLastNode().getAstNode() = this and
|
||||||
t = s
|
t = s
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ module ControlFlow {
|
|||||||
private import semmle.code.csharp.controlflow.BasicBlocks as BBs
|
private import semmle.code.csharp.controlflow.BasicBlocks as BBs
|
||||||
import semmle.code.csharp.controlflow.internal.SuccessorType
|
import semmle.code.csharp.controlflow.internal.SuccessorType
|
||||||
private import SuccessorTypes
|
private import SuccessorTypes
|
||||||
private import internal.ControlFlowGraphImpl
|
private import internal.ControlFlowGraphImpl as Impl
|
||||||
private import internal.Splitting as Splitting
|
private import internal.Splitting as Splitting
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,18 +25,16 @@ module ControlFlow {
|
|||||||
* Only nodes that can be reached from the callable entry point are included in
|
* Only nodes that can be reached from the callable entry point are included in
|
||||||
* the CFG.
|
* the CFG.
|
||||||
*/
|
*/
|
||||||
class Node extends TCfgNode {
|
class Node extends Impl::Node {
|
||||||
/** Gets a textual representation of this control flow node. */
|
|
||||||
string toString() { none() }
|
|
||||||
|
|
||||||
/** Gets the control flow element that this node corresponds to, if any. */
|
/** Gets the control flow element that this node corresponds to, if any. */
|
||||||
ControlFlowElement getElement() { none() }
|
final ControlFlowElement getAstNode() { result = super.getAstNode() }
|
||||||
|
|
||||||
/** Gets the location of this control flow node. */
|
/**
|
||||||
Location getLocation() { result = this.getElement().getLocation() }
|
* DEPRECATED: Use `getAstNode` instead.
|
||||||
|
*
|
||||||
/** Holds if this control flow node has conditional successors. */
|
* Gets the control flow element that this node corresponds to, if any.
|
||||||
predicate isCondition() { exists(this.getASuccessorByType(any(ConditionalSuccessor e))) }
|
*/
|
||||||
|
deprecated ControlFlowElement getElement() { result = this.getAstNode() }
|
||||||
|
|
||||||
/** Gets the basic block that this control flow node belongs to. */
|
/** Gets the basic block that this control flow node belongs to. */
|
||||||
BasicBlock getBasicBlock() { result.getANode() = this }
|
BasicBlock getBasicBlock() { result.getANode() = this }
|
||||||
@@ -183,7 +181,7 @@ module ControlFlow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a successor node of a given type, if any. */
|
/** Gets a successor node of a given type, if any. */
|
||||||
Node getASuccessorByType(SuccessorType t) { result = getASuccessor(this, t) }
|
Node getASuccessorByType(SuccessorType t) { result = this.getASuccessor(t) }
|
||||||
|
|
||||||
/** Gets an immediate successor, if any. */
|
/** Gets an immediate successor, if any. */
|
||||||
Node getASuccessor() { result = this.getASuccessorByType(_) }
|
Node getASuccessor() { result = this.getASuccessorByType(_) }
|
||||||
@@ -234,80 +232,39 @@ module ControlFlow {
|
|||||||
result = this.getASuccessorByType(any(BooleanSuccessor t | t.getValue() = false))
|
result = this.getASuccessorByType(any(BooleanSuccessor t | t.getValue() = false))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if this node has more than one predecessor. */
|
|
||||||
predicate isJoin() { strictcount(this.getAPredecessor()) > 1 }
|
|
||||||
|
|
||||||
/** Holds if this node has more than one successor. */
|
|
||||||
predicate isBranch() { strictcount(this.getASuccessor()) > 1 }
|
|
||||||
|
|
||||||
/** Gets the enclosing callable of this control flow node. */
|
/** Gets the enclosing callable of this control flow node. */
|
||||||
final Callable getEnclosingCallable() { result = getNodeCfgScope(this) }
|
final Callable getEnclosingCallable() { result = Impl::getNodeCfgScope(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Provides different types of control flow nodes. */
|
/** Provides different types of control flow nodes. */
|
||||||
module Nodes {
|
module Nodes {
|
||||||
/** A node for a callable entry point. */
|
/** A node for a callable entry point. */
|
||||||
class EntryNode extends Node, TEntryNode {
|
class EntryNode extends Node instanceof Impl::EntryNode {
|
||||||
/** Gets the callable that this entry applies to. */
|
/** Gets the callable that this entry applies to. */
|
||||||
Callable getCallable() { this = TEntryNode(result) }
|
Callable getCallable() { result = this.getScope() }
|
||||||
|
|
||||||
override BasicBlocks::EntryBlock getBasicBlock() { result = Node.super.getBasicBlock() }
|
override BasicBlocks::EntryBlock getBasicBlock() { result = Node.super.getBasicBlock() }
|
||||||
|
|
||||||
private Assignable getAssignable() { this = TEntryNode(result) }
|
|
||||||
|
|
||||||
override Location getLocation() {
|
|
||||||
result in [this.getCallable().getLocation(), this.getAssignable().getLocation()]
|
|
||||||
}
|
|
||||||
|
|
||||||
override string toString() {
|
|
||||||
result = "enter " + [this.getCallable().toString(), this.getAssignable().toString()]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A node for a callable exit point, annotated with the type of exit. */
|
/** A node for a callable exit point, annotated with the type of exit. */
|
||||||
class AnnotatedExitNode extends Node, TAnnotatedExitNode {
|
class AnnotatedExitNode extends Node instanceof Impl::AnnotatedExitNode {
|
||||||
private CfgScope scope;
|
/** Holds if this node represent a normal exit. */
|
||||||
private boolean normal;
|
final predicate isNormal() { super.isNormal() }
|
||||||
|
|
||||||
AnnotatedExitNode() { this = TAnnotatedExitNode(scope, normal) }
|
|
||||||
|
|
||||||
/** Gets the callable that this exit applies to. */
|
/** Gets the callable that this exit applies to. */
|
||||||
CfgScope getCallable() { result = scope }
|
Callable getCallable() { result = this.getScope() }
|
||||||
|
|
||||||
/** Holds if this node represents a normal exit. */
|
|
||||||
predicate isNormal() { normal = true }
|
|
||||||
|
|
||||||
override BasicBlocks::AnnotatedExitBlock getBasicBlock() {
|
override BasicBlocks::AnnotatedExitBlock getBasicBlock() {
|
||||||
result = Node.super.getBasicBlock()
|
result = Node.super.getBasicBlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
override Location getLocation() { result = scope.getLocation() }
|
|
||||||
|
|
||||||
override string toString() {
|
|
||||||
exists(string s |
|
|
||||||
normal = true and s = "normal"
|
|
||||||
or
|
|
||||||
normal = false and s = "abnormal"
|
|
||||||
|
|
|
||||||
result = "exit " + scope + " (" + s + ")"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A node for a callable exit point. */
|
/** A node for a callable exit point. */
|
||||||
class ExitNode extends Node, TExitNode {
|
class ExitNode extends Node instanceof Impl::ExitNode {
|
||||||
private CfgScope scope;
|
|
||||||
|
|
||||||
ExitNode() { this = TExitNode(scope) }
|
|
||||||
|
|
||||||
/** Gets the callable that this exit applies to. */
|
/** Gets the callable that this exit applies to. */
|
||||||
Callable getCallable() { result = scope }
|
Callable getCallable() { result = this.getScope() }
|
||||||
|
|
||||||
override BasicBlocks::ExitBlock getBasicBlock() { result = Node.super.getBasicBlock() }
|
override BasicBlocks::ExitBlock getBasicBlock() { result = Node.super.getBasicBlock() }
|
||||||
|
|
||||||
override Location getLocation() { result = scope.getLocation() }
|
|
||||||
|
|
||||||
override string toString() { result = "exit " + scope }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -317,35 +274,19 @@ module ControlFlow {
|
|||||||
* the element is in unreachable (dead) code, and multiple when there are
|
* the element is in unreachable (dead) code, and multiple when there are
|
||||||
* different splits for the element.
|
* different splits for the element.
|
||||||
*/
|
*/
|
||||||
class ElementNode extends Node, TElementNode {
|
class ElementNode extends Node instanceof Impl::AstCfgNode {
|
||||||
private Splits splits;
|
|
||||||
private ControlFlowElement cfe;
|
|
||||||
|
|
||||||
ElementNode() { this = TElementNode(_, cfe, splits) }
|
|
||||||
|
|
||||||
override ControlFlowElement getElement() { result = cfe }
|
|
||||||
|
|
||||||
override string toString() {
|
|
||||||
result = "[" + this.getSplitsString() + "] " + cfe.toString()
|
|
||||||
or
|
|
||||||
not exists(this.getSplitsString()) and result = cfe.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets a comma-separated list of strings for each split in this node, if any. */
|
/** Gets a comma-separated list of strings for each split in this node, if any. */
|
||||||
string getSplitsString() {
|
final string getSplitsString() { result = super.getSplitsString() }
|
||||||
result = splits.toString() and
|
|
||||||
result != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets a split for this control flow node, if any. */
|
/** Gets a split for this control flow node, if any. */
|
||||||
Split getASplit() { result = splits.getASplit() }
|
final Split getASplit() { result = super.getASplit() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control-flow node for an expression. */
|
/** A control-flow node for an expression. */
|
||||||
class ExprNode extends ElementNode {
|
class ExprNode extends ElementNode {
|
||||||
Expr e;
|
Expr e;
|
||||||
|
|
||||||
ExprNode() { e = unique(Expr e_ | e_ = this.getElement() | e_) }
|
ExprNode() { e = unique(Expr e_ | e_ = this.getAstNode() | e_) }
|
||||||
|
|
||||||
/** Gets the expression that this control-flow node belongs to. */
|
/** Gets the expression that this control-flow node belongs to. */
|
||||||
Expr getExpr() { result = e }
|
Expr getExpr() { result = e }
|
||||||
|
|||||||
@@ -1946,7 +1946,7 @@ module Internal {
|
|||||||
|
|
|
|
||||||
def =
|
def =
|
||||||
guarded
|
guarded
|
||||||
.getElement()
|
.getAstNode()
|
||||||
.(AccessOrCallExpr)
|
.(AccessOrCallExpr)
|
||||||
.getAnSsaQualifier(guarded.getBasicBlock().getANode()) and
|
.getAnSsaQualifier(guarded.getBasicBlock().getANode()) and
|
||||||
if v.isReferentialProperty()
|
if v.isReferentialProperty()
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,69 +0,0 @@
|
|||||||
private import csharp as CS
|
|
||||||
private import ControlFlowGraphImpl as Impl
|
|
||||||
private import Completion as Comp
|
|
||||||
private import Splitting as Splitting
|
|
||||||
private import SuccessorType as ST
|
|
||||||
private import semmle.code.csharp.Caching
|
|
||||||
|
|
||||||
class ControlFlowTreeBase = Impl::ControlFlowTree::Range;
|
|
||||||
|
|
||||||
class ControlFlowElement = CS::ControlFlowElement;
|
|
||||||
|
|
||||||
class Completion = Comp::Completion;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hold if `c` represents normal evaluation of a statement or an
|
|
||||||
* expression.
|
|
||||||
*/
|
|
||||||
predicate completionIsNormal(Completion c) { c instanceof Comp::NormalCompletion }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hold if `c` represents simple (normal) evaluation of a statement or an
|
|
||||||
* expression.
|
|
||||||
*/
|
|
||||||
predicate completionIsSimple(Completion c) { c instanceof Comp::SimpleCompletion }
|
|
||||||
|
|
||||||
/** Holds if `c` is a valid completion for `e`. */
|
|
||||||
predicate completionIsValidFor(Completion c, ControlFlowElement e) { c.isValidFor(e) }
|
|
||||||
|
|
||||||
class CfgScope = Impl::CfgScope;
|
|
||||||
|
|
||||||
/** Gets the CFG scope for `e`. */
|
|
||||||
CfgScope getCfgScope(ControlFlowElement e) {
|
|
||||||
Stages::ControlFlowStage::forceCachingInSameStage() and
|
|
||||||
result = e.getEnclosingCallable()
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate scopeFirst = Impl::scopeFirst/2;
|
|
||||||
|
|
||||||
predicate scopeLast = Impl::scopeLast/3;
|
|
||||||
|
|
||||||
/** The maximum number of splits allowed for a given node. */
|
|
||||||
int maxSplits() { result = 5 }
|
|
||||||
|
|
||||||
class SplitKindBase = Splitting::TSplitKind;
|
|
||||||
|
|
||||||
class Split = Splitting::Split;
|
|
||||||
|
|
||||||
class SuccessorType = ST::SuccessorType;
|
|
||||||
|
|
||||||
/** Gets a successor type that matches completion `c`. */
|
|
||||||
SuccessorType getAMatchingSuccessorType(Completion c) { result = c.getAMatchingSuccessorType() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hold if `c` represents simple (normal) evaluation of a statement or an
|
|
||||||
* expression.
|
|
||||||
*/
|
|
||||||
predicate successorTypeIsSimple(SuccessorType t) {
|
|
||||||
t instanceof ST::SuccessorTypes::NormalSuccessor
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if `t` is an abnormal exit type out of a callable. */
|
|
||||||
predicate isAbnormalExitType(SuccessorType t) {
|
|
||||||
t instanceof ST::SuccessorTypes::ExceptionSuccessor or
|
|
||||||
t instanceof ST::SuccessorTypes::ExitSuccessor
|
|
||||||
}
|
|
||||||
|
|
||||||
class Location = CS::Location;
|
|
||||||
|
|
||||||
class Node = CS::ControlFlow::Node;
|
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
import csharp
|
import csharp
|
||||||
private import Completion
|
private import Completion
|
||||||
private import ControlFlowGraphImpl
|
private import ControlFlowGraphImpl
|
||||||
private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow
|
private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow as Cfg
|
||||||
|
|
||||||
private predicate startsBB(ControlFlowElement cfe) {
|
private predicate startsBB(ControlFlowElement cfe) {
|
||||||
not succ(_, cfe, _) and
|
not succ(_, cfe, _) and
|
||||||
@@ -55,7 +55,7 @@ private predicate bbIDominates(PreBasicBlock dom, PreBasicBlock bb) =
|
|||||||
class PreBasicBlock extends ControlFlowElement {
|
class PreBasicBlock extends ControlFlowElement {
|
||||||
PreBasicBlock() { startsBB(this) }
|
PreBasicBlock() { startsBB(this) }
|
||||||
|
|
||||||
PreBasicBlock getASuccessorByType(SuccessorType t) {
|
PreBasicBlock getASuccessorByType(Cfg::SuccessorType t) {
|
||||||
succ(this.getLastElement(), result, any(Completion c | t = c.getAMatchingSuccessorType()))
|
succ(this.getLastElement(), result, any(Completion c | t = c.getAMatchingSuccessorType()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ class ConditionBlock extends PreBasicBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate controls(PreBasicBlock controlled, SuccessorTypes::ConditionalSuccessor s) {
|
predicate controls(PreBasicBlock controlled, Cfg::SuccessorTypes::ConditionalSuccessor s) {
|
||||||
exists(PreBasicBlock succ, ConditionalCompletion c | this.immediatelyControls(succ, c) |
|
exists(PreBasicBlock succ, ConditionalCompletion c | this.immediatelyControls(succ, c) |
|
||||||
succ.dominates(controlled) and
|
succ.dominates(controlled) and
|
||||||
s = c.getAMatchingSuccessorType()
|
s = c.getAMatchingSuccessorType()
|
||||||
|
|||||||
@@ -7,8 +7,7 @@
|
|||||||
import csharp
|
import csharp
|
||||||
private import Completion
|
private import Completion
|
||||||
private import ControlFlowGraphImpl
|
private import ControlFlowGraphImpl
|
||||||
private import SuccessorTypes
|
private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow as Cfg
|
||||||
private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow
|
|
||||||
private import semmle.code.csharp.controlflow.internal.PreSsa
|
private import semmle.code.csharp.controlflow.internal.PreSsa
|
||||||
|
|
||||||
cached
|
cached
|
||||||
@@ -83,7 +82,7 @@ module InitializerSplitting {
|
|||||||
* Gets a control flow element that is a syntactic descendant of the
|
* Gets a control flow element that is a syntactic descendant of the
|
||||||
* initializer expression.
|
* initializer expression.
|
||||||
*/
|
*/
|
||||||
ControlFlowElement getAnInitializerDescendant() {
|
AstNode getAnInitializerDescendant() {
|
||||||
result = this.getInitializer()
|
result = this.getInitializer()
|
||||||
or
|
or
|
||||||
result = this.getAnInitializerDescendant().getAChild()
|
result = this.getAnInitializerDescendant().getAChild()
|
||||||
@@ -193,49 +192,49 @@ module InitializerSplitting {
|
|||||||
private class InitializerSplitKind extends SplitKind, TInitializerSplitKind {
|
private class InitializerSplitKind extends SplitKind, TInitializerSplitKind {
|
||||||
override int getListOrder() { result = 0 }
|
override int getListOrder() { result = 0 }
|
||||||
|
|
||||||
override predicate isEnabled(ControlFlowElement cfe) { this.appliesTo(cfe) }
|
override predicate isEnabled(AstNode cfe) { this.appliesTo(cfe) }
|
||||||
|
|
||||||
override string toString() { result = "Initializer" }
|
override string toString() { result = "Initializer" }
|
||||||
}
|
}
|
||||||
|
|
||||||
int getNextListOrder() { result = 1 }
|
int getNextListOrder() { result = 1 }
|
||||||
|
|
||||||
private class InitializerSplitImpl extends SplitImpl, InitializerSplit {
|
private class InitializerSplitImpl extends SplitImpl instanceof InitializerSplit {
|
||||||
override InitializerSplitKind getKind() { any() }
|
override InitializerSplitKind getKind() { any() }
|
||||||
|
|
||||||
override predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
|
||||||
exists(ConstructorInitializer ci |
|
exists(ConstructorInitializer ci |
|
||||||
last(ci, pred, c) and
|
last(ci, pred, c) and
|
||||||
succ(pred, succ, c) and
|
succ(pred, succ, c) and
|
||||||
succ = any(InitializedInstanceMember m).getAnInitializerDescendant() and
|
succ = any(InitializedInstanceMember m).getAnInitializerDescendant() and
|
||||||
this.getConstructor() = ci.getConstructor()
|
super.getConstructor() = ci.getConstructor()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasEntryScope(CfgScope scope, ControlFlowElement first) {
|
override predicate hasEntryScope(CfgScope scope, AstNode first) {
|
||||||
scopeFirst(scope, first) and
|
scopeFirst(scope, first) and
|
||||||
scope = this.getConstructor() and
|
scope = super.getConstructor() and
|
||||||
first = any(InitializedInstanceMember m).getAnInitializerDescendant()
|
first = any(InitializedInstanceMember m).getAnInitializerDescendant()
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasExit(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
|
||||||
this.appliesTo(pred) and
|
this.appliesTo(pred) and
|
||||||
succ(pred, succ, c) and
|
succ(pred, succ, c) and
|
||||||
not succ = any(InitializedInstanceMember m).getAnInitializerDescendant() and
|
not succ = any(InitializedInstanceMember m).getAnInitializerDescendant() and
|
||||||
succ.getEnclosingCallable() = this.getConstructor()
|
succ.(ControlFlowElement).getEnclosingCallable() = super.getConstructor()
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) {
|
override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) {
|
||||||
this.appliesTo(last) and
|
this.appliesTo(last) and
|
||||||
scopeLast(scope, last, c) and
|
scopeLast(scope, last, c) and
|
||||||
scope = this.getConstructor()
|
scope = super.getConstructor()
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) {
|
||||||
this.appliesSucc(pred, succ, c) and
|
this.appliesSucc(pred, succ, c) and
|
||||||
succ =
|
succ =
|
||||||
any(InitializedInstanceMember m |
|
any(InitializedInstanceMember m |
|
||||||
constructorInitializes(this.getConstructor(), m.getInitializer())
|
constructorInitializes(super.getConstructor(), m.getInitializer())
|
||||||
).getAnInitializerDescendant()
|
).getAnInitializerDescendant()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,17 +266,22 @@ module ConditionalCompletionSplitting {
|
|||||||
private class ConditionalCompletionSplitKind extends SplitKind, TConditionalCompletionSplitKind {
|
private class ConditionalCompletionSplitKind extends SplitKind, TConditionalCompletionSplitKind {
|
||||||
override int getListOrder() { result = InitializerSplitting::getNextListOrder() }
|
override int getListOrder() { result = InitializerSplitting::getNextListOrder() }
|
||||||
|
|
||||||
override predicate isEnabled(ControlFlowElement cfe) { this.appliesTo(cfe) }
|
override predicate isEnabled(AstNode cfe) { this.appliesTo(cfe) }
|
||||||
|
|
||||||
override string toString() { result = "ConditionalCompletion" }
|
override string toString() { result = "ConditionalCompletion" }
|
||||||
}
|
}
|
||||||
|
|
||||||
int getNextListOrder() { result = InitializerSplitting::getNextListOrder() + 1 }
|
int getNextListOrder() { result = InitializerSplitting::getNextListOrder() + 1 }
|
||||||
|
|
||||||
private class ConditionalCompletionSplitImpl extends SplitImpl, ConditionalCompletionSplit {
|
private class ConditionalCompletionSplitImpl extends SplitImpl instanceof ConditionalCompletionSplit
|
||||||
|
{
|
||||||
|
ConditionalCompletion completion;
|
||||||
|
|
||||||
|
ConditionalCompletionSplitImpl() { this = TConditionalCompletionSplit(completion) }
|
||||||
|
|
||||||
override ConditionalCompletionSplitKind getKind() { any() }
|
override ConditionalCompletionSplitKind getKind() { any() }
|
||||||
|
|
||||||
override predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
|
||||||
succ(pred, succ, c) and
|
succ(pred, succ, c) and
|
||||||
last(succ, _, completion) and
|
last(succ, _, completion) and
|
||||||
(
|
(
|
||||||
@@ -334,23 +338,21 @@ module ConditionalCompletionSplitting {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasEntryScope(CfgScope scope, ControlFlowElement first) { none() }
|
override predicate hasEntryScope(CfgScope scope, AstNode first) { none() }
|
||||||
|
|
||||||
override predicate hasExit(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
|
||||||
this.appliesTo(pred) and
|
this.appliesTo(pred) and
|
||||||
succ(pred, succ, c) and
|
succ(pred, succ, c) and
|
||||||
if c instanceof ConditionalCompletion then completion = c else any()
|
if c instanceof ConditionalCompletion then completion = c else any()
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) {
|
override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) {
|
||||||
this.appliesTo(last) and
|
this.appliesTo(last) and
|
||||||
scopeLast(scope, last, c) and
|
scopeLast(scope, last, c) and
|
||||||
if c instanceof ConditionalCompletion then completion = c else any()
|
if c instanceof ConditionalCompletion then completion = c else any()
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) { none() }
|
||||||
none()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,7 +360,7 @@ module AssertionSplitting {
|
|||||||
import semmle.code.csharp.commons.Assertions
|
import semmle.code.csharp.commons.Assertions
|
||||||
private import semmle.code.csharp.ExprOrStmtParent
|
private import semmle.code.csharp.ExprOrStmtParent
|
||||||
|
|
||||||
private ControlFlowElement getAnAssertionDescendant(Assertion a) {
|
private AstNode getAnAssertionDescendant(Assertion a) {
|
||||||
result = a
|
result = a
|
||||||
or
|
or
|
||||||
result = getAnAssertionDescendant(a).getAChild()
|
result = getAnAssertionDescendant(a).getAChild()
|
||||||
@@ -401,17 +403,23 @@ module AssertionSplitting {
|
|||||||
private class AssertionSplitKind extends SplitKind, TAssertionSplitKind {
|
private class AssertionSplitKind extends SplitKind, TAssertionSplitKind {
|
||||||
override int getListOrder() { result = ConditionalCompletionSplitting::getNextListOrder() }
|
override int getListOrder() { result = ConditionalCompletionSplitting::getNextListOrder() }
|
||||||
|
|
||||||
override predicate isEnabled(ControlFlowElement cfe) { this.appliesTo(cfe) }
|
override predicate isEnabled(AstNode cfe) { this.appliesTo(cfe) }
|
||||||
|
|
||||||
override string toString() { result = "Assertion" }
|
override string toString() { result = "Assertion" }
|
||||||
}
|
}
|
||||||
|
|
||||||
int getNextListOrder() { result = ConditionalCompletionSplitting::getNextListOrder() + 1 }
|
int getNextListOrder() { result = ConditionalCompletionSplitting::getNextListOrder() + 1 }
|
||||||
|
|
||||||
private class AssertionSplitImpl extends SplitImpl, AssertionSplit {
|
private class AssertionSplitImpl extends SplitImpl instanceof AssertionSplit {
|
||||||
|
Assertion a;
|
||||||
|
boolean success;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
AssertionSplitImpl() { this = TAssertionSplit(a, i, success) }
|
||||||
|
|
||||||
override AssertionSplitKind getKind() { any() }
|
override AssertionSplitKind getKind() { any() }
|
||||||
|
|
||||||
override predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
|
||||||
exists(AssertMethod m |
|
exists(AssertMethod m |
|
||||||
last(a.getExpr(i), pred, c) and
|
last(a.getExpr(i), pred, c) and
|
||||||
succ(pred, succ, c) and
|
succ(pred, succ, c) and
|
||||||
@@ -440,9 +448,9 @@ module AssertionSplitting {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasEntryScope(CfgScope scope, ControlFlowElement first) { none() }
|
override predicate hasEntryScope(CfgScope scope, AstNode first) { none() }
|
||||||
|
|
||||||
override predicate hasExit(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
|
||||||
this.appliesTo(pred) and
|
this.appliesTo(pred) and
|
||||||
pred = a and
|
pred = a and
|
||||||
succ(pred, succ, c) and
|
succ(pred, succ, c) and
|
||||||
@@ -455,7 +463,7 @@ module AssertionSplitting {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) {
|
override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) {
|
||||||
this.appliesTo(last) and
|
this.appliesTo(last) and
|
||||||
last = a and
|
last = a and
|
||||||
scopeLast(scope, last, c) and
|
scopeLast(scope, last, c) and
|
||||||
@@ -468,7 +476,7 @@ module AssertionSplitting {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) {
|
||||||
this.appliesSucc(pred, succ, c) and
|
this.appliesSucc(pred, succ, c) and
|
||||||
succ = getAnAssertionDescendant(a)
|
succ = getAnAssertionDescendant(a)
|
||||||
}
|
}
|
||||||
@@ -484,8 +492,8 @@ module FinallySplitting {
|
|||||||
* then the `finally` block must end with a `return` as well (provided that
|
* then the `finally` block must end with a `return` as well (provided that
|
||||||
* the `finally` block exits normally).
|
* the `finally` block exits normally).
|
||||||
*/
|
*/
|
||||||
class FinallySplitType extends SuccessorType {
|
class FinallySplitType extends Cfg::SuccessorType {
|
||||||
FinallySplitType() { not this instanceof ConditionalSuccessor }
|
FinallySplitType() { not this instanceof Cfg::SuccessorTypes::ConditionalSuccessor }
|
||||||
|
|
||||||
/** Holds if this split type matches entry into a `finally` block with completion `c`. */
|
/** Holds if this split type matches entry into a `finally` block with completion `c`. */
|
||||||
predicate isSplitForEntryCompletion(Completion c) {
|
predicate isSplitForEntryCompletion(Completion c) {
|
||||||
@@ -493,22 +501,22 @@ module FinallySplitting {
|
|||||||
then
|
then
|
||||||
// If the entry into the `finally` block completes with any normal completion,
|
// If the entry into the `finally` block completes with any normal completion,
|
||||||
// it simply means normal execution after the `finally` block
|
// it simply means normal execution after the `finally` block
|
||||||
this instanceof NormalSuccessor
|
this instanceof Cfg::SuccessorTypes::NormalSuccessor
|
||||||
else this = c.getAMatchingSuccessorType()
|
else this = c.getAMatchingSuccessorType()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A control flow element that belongs to a `finally` block. */
|
/** A control flow element that belongs to a `finally` block. */
|
||||||
private class FinallyControlFlowElement extends ControlFlowElement {
|
private class FinallyAstNode extends AstNode {
|
||||||
private Statements::TryStmtTree try;
|
private Statements::TryStmtTree try;
|
||||||
|
|
||||||
FinallyControlFlowElement() { this = try.getAFinallyDescendant() }
|
FinallyAstNode() { this = try.getAFinallyDescendant() }
|
||||||
|
|
||||||
/** Gets the immediate `try` block that this node belongs to. */
|
/** Gets the immediate `try` block that this node belongs to. */
|
||||||
Statements::TryStmtTree getTryStmt() { result = try }
|
Statements::TryStmtTree getTryStmt() { result = try }
|
||||||
|
|
||||||
/** Holds if this node is the entry node in the `finally` block it belongs to. */
|
/** Holds if this node is the entry node in the `finally` block it belongs to. */
|
||||||
predicate isEntryNode() { first(try.getFinally(), this) }
|
predicate isEntryNode() { first(try.(TryStmt).getFinally(), this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -547,7 +555,7 @@ module FinallySplitting {
|
|||||||
int getNestLevel() { result = nestLevel }
|
int getNestLevel() { result = nestLevel }
|
||||||
|
|
||||||
override string toString() {
|
override string toString() {
|
||||||
if type instanceof NormalSuccessor
|
if type instanceof Cfg::SuccessorTypes::NormalSuccessor
|
||||||
then result = ""
|
then result = ""
|
||||||
else
|
else
|
||||||
if nestLevel > 0
|
if nestLevel > 0
|
||||||
@@ -577,38 +585,34 @@ module FinallySplitting {
|
|||||||
override string toString() { result = "Finally (" + nestLevel + ")" }
|
override string toString() { result = "Finally (" + nestLevel + ")" }
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[nomagic]
|
||||||
private predicate hasEntry0(
|
private predicate hasEntry0(AstNode pred, FinallyAstNode succ, int nestLevel, Completion c) {
|
||||||
ControlFlowElement pred, FinallyControlFlowElement succ, int nestLevel, Completion c
|
|
||||||
) {
|
|
||||||
succ.isEntryNode() and
|
succ.isEntryNode() and
|
||||||
nestLevel = succ.getTryStmt().nestLevel() and
|
nestLevel = succ.getTryStmt().nestLevel() and
|
||||||
succ(pred, succ, c)
|
succ(pred, succ, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FinallySplitImpl extends SplitImpl, FinallySplit {
|
private class FinallySplitImpl extends SplitImpl instanceof FinallySplit {
|
||||||
override FinallySplitKind getKind() { result.getNestLevel() = this.getNestLevel() }
|
override FinallySplitKind getKind() { result.getNestLevel() = super.getNestLevel() }
|
||||||
|
|
||||||
override predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
|
||||||
hasEntry0(pred, succ, this.getNestLevel(), c) and
|
hasEntry0(pred, succ, super.getNestLevel(), c) and
|
||||||
this.getType().isSplitForEntryCompletion(c)
|
super.getType().isSplitForEntryCompletion(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasEntryScope(CfgScope scope, ControlFlowElement first) { none() }
|
override predicate hasEntryScope(CfgScope scope, AstNode first) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this split applies to control flow element `pred`, where `pred`
|
* Holds if this split applies to control flow element `pred`, where `pred`
|
||||||
* is a valid predecessor.
|
* is a valid predecessor.
|
||||||
*/
|
*/
|
||||||
private predicate appliesToPredecessor(ControlFlowElement pred) {
|
private predicate appliesToPredecessor(AstNode pred) {
|
||||||
this.appliesTo(pred) and
|
this.appliesTo(pred) and
|
||||||
(succ(pred, _, _) or scopeLast(_, pred, _))
|
(succ(pred, _, _) or scopeLast(_, pred, _))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate exit0(
|
private predicate exit0(AstNode pred, Statements::TryStmtTree try, int nestLevel, Completion c) {
|
||||||
ControlFlowElement pred, Statements::TryStmtTree try, int nestLevel, Completion c
|
|
||||||
) {
|
|
||||||
this.appliesToPredecessor(pred) and
|
this.appliesToPredecessor(pred) and
|
||||||
nestLevel = try.nestLevel() and
|
nestLevel = try.nestLevel() and
|
||||||
last(try, pred, c)
|
last(try, pred, c)
|
||||||
@@ -619,10 +623,10 @@ module FinallySplitting {
|
|||||||
* `inherited` indicates whether `c` is an inherited completion from a `try`/
|
* `inherited` indicates whether `c` is an inherited completion from a `try`/
|
||||||
* `catch` block.
|
* `catch` block.
|
||||||
*/
|
*/
|
||||||
private predicate exit(ControlFlowElement pred, Completion c, boolean inherited) {
|
private predicate exit(AstNode pred, Completion c, boolean inherited) {
|
||||||
exists(TryStmt try, FinallySplitType type |
|
exists(TryStmt try, FinallySplitType type |
|
||||||
this.exit0(pred, try, this.getNestLevel(), c) and
|
this.exit0(pred, try, super.getNestLevel(), c) and
|
||||||
type = this.getType()
|
type = super.getType()
|
||||||
|
|
|
|
||||||
if last(try.getFinally(), pred, c)
|
if last(try.getFinally(), pred, c)
|
||||||
then
|
then
|
||||||
@@ -635,14 +639,14 @@ module FinallySplitting {
|
|||||||
or
|
or
|
||||||
not c instanceof NormalCompletion
|
not c instanceof NormalCompletion
|
||||||
or
|
or
|
||||||
type instanceof NormalSuccessor
|
type instanceof Cfg::SuccessorTypes::NormalSuccessor
|
||||||
)
|
)
|
||||||
else (
|
else (
|
||||||
// Finally block can exit with completion `c` inherited from try/catch
|
// Finally block can exit with completion `c` inherited from try/catch
|
||||||
// block: must match this split
|
// block: must match this split
|
||||||
inherited = true and
|
inherited = true and
|
||||||
type = c.getAMatchingSuccessorType() and
|
type = c.getAMatchingSuccessorType() and
|
||||||
not type instanceof NormalSuccessor
|
not type instanceof Cfg::SuccessorTypes::NormalSuccessor
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -672,15 +676,15 @@ module FinallySplitting {
|
|||||||
// is "normal" (corresponding to `b1 = true` and `b2 = false`), then the inner
|
// is "normal" (corresponding to `b1 = true` and `b2 = false`), then the inner
|
||||||
// split must be able to exit with an `ExceptionA` completion.
|
// split must be able to exit with an `ExceptionA` completion.
|
||||||
this.appliesToPredecessor(pred) and
|
this.appliesToPredecessor(pred) and
|
||||||
exists(FinallySplitImpl outer |
|
exists(FinallySplit outer |
|
||||||
outer.getNestLevel() = this.getNestLevel() - 1 and
|
outer.getNestLevel() = super.getNestLevel() - 1 and
|
||||||
outer.exit(pred, c, inherited) and
|
outer.(FinallySplitImpl).exit(pred, c, inherited) and
|
||||||
this.getType() instanceof NormalSuccessor and
|
super.getType() instanceof Cfg::SuccessorTypes::NormalSuccessor and
|
||||||
inherited = true
|
inherited = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasExit(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
|
||||||
succ(pred, succ, c) and
|
succ(pred, succ, c) and
|
||||||
(
|
(
|
||||||
this.exit(pred, c, _)
|
this.exit(pred, c, _)
|
||||||
@@ -689,7 +693,7 @@ module FinallySplitting {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) {
|
override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) {
|
||||||
scopeLast(scope, last, c) and
|
scopeLast(scope, last, c) and
|
||||||
(
|
(
|
||||||
this.exit(last, c, _)
|
this.exit(last, c, _)
|
||||||
@@ -698,17 +702,17 @@ module FinallySplitting {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) {
|
||||||
this.appliesSucc(pred, succ, c) and
|
this.appliesSucc(pred, succ, c) and
|
||||||
succ =
|
succ =
|
||||||
any(FinallyControlFlowElement fcfe |
|
any(FinallyAstNode fcfe |
|
||||||
if fcfe.isEntryNode()
|
if fcfe.isEntryNode()
|
||||||
then
|
then
|
||||||
// entering a nested `finally` block
|
// entering a nested `finally` block
|
||||||
fcfe.getTryStmt().nestLevel() > this.getNestLevel()
|
fcfe.getTryStmt().nestLevel() > super.getNestLevel()
|
||||||
else
|
else
|
||||||
// staying in the same (possibly nested) `finally` block as `pred`
|
// staying in the same (possibly nested) `finally` block as `pred`
|
||||||
fcfe.getTryStmt().nestLevel() >= this.getNestLevel()
|
fcfe.getTryStmt().nestLevel() >= super.getNestLevel()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -774,20 +778,20 @@ module ExceptionHandlerSplitting {
|
|||||||
|
|
||||||
int getNextListOrder() { result = FinallySplitting::getNextListOrder() + 1 }
|
int getNextListOrder() { result = FinallySplitting::getNextListOrder() + 1 }
|
||||||
|
|
||||||
private class ExceptionHandlerSplitImpl extends SplitImpl, ExceptionHandlerSplit {
|
private class ExceptionHandlerSplitImpl extends SplitImpl instanceof ExceptionHandlerSplit {
|
||||||
override ExceptionHandlerSplitKind getKind() { any() }
|
override ExceptionHandlerSplitKind getKind() { any() }
|
||||||
|
|
||||||
override predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
|
||||||
// Entry into first catch clause
|
// Entry into first catch clause
|
||||||
exists(Statements::TryStmtTree ts |
|
exists(Statements::TryStmtTree ts |
|
||||||
this.getExceptionClass() = ts.getAThrownException(pred, c)
|
super.getExceptionClass() = ts.getAThrownException(pred, c)
|
||||||
|
|
|
|
||||||
succ(pred, succ, c) and
|
succ(pred, succ, c) and
|
||||||
succ = ts.getCatchClause(0).(SpecificCatchClause)
|
succ = ts.(TryStmt).getCatchClause(0).(SpecificCatchClause)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasEntryScope(CfgScope scope, ControlFlowElement first) { none() }
|
override predicate hasEntryScope(CfgScope scope, AstNode first) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this split applies to catch clause `scc`. The parameter `match`
|
* Holds if this split applies to catch clause `scc`. The parameter `match`
|
||||||
@@ -796,9 +800,9 @@ module ExceptionHandlerSplitting {
|
|||||||
*/
|
*/
|
||||||
private predicate appliesToCatchClause(SpecificCatchClause scc, TMatch match) {
|
private predicate appliesToCatchClause(SpecificCatchClause scc, TMatch match) {
|
||||||
exists(Statements::TryStmtTree ts, ExceptionClass ec |
|
exists(Statements::TryStmtTree ts, ExceptionClass ec |
|
||||||
ec = this.getExceptionClass() and
|
ec = super.getExceptionClass() and
|
||||||
ec = ts.getAThrownException(_, _) and
|
ec = ts.getAThrownException(_, _) and
|
||||||
scc = ts.getACatchClause()
|
scc = ts.(TryStmt).getACatchClause()
|
||||||
|
|
|
|
||||||
if scc.getCaughtExceptionType() = ec.getABaseType*()
|
if scc.getCaughtExceptionType() = ec.getABaseType*()
|
||||||
then match = TAlways()
|
then match = TAlways()
|
||||||
@@ -813,7 +817,7 @@ module ExceptionHandlerSplitting {
|
|||||||
* Holds if this split applies to control flow element `pred`, where `pred`
|
* Holds if this split applies to control flow element `pred`, where `pred`
|
||||||
* is a valid predecessor with completion `c`.
|
* is a valid predecessor with completion `c`.
|
||||||
*/
|
*/
|
||||||
private predicate appliesToPredecessor(ControlFlowElement pred, Completion c) {
|
private predicate appliesToPredecessor(AstNode pred, Completion c) {
|
||||||
this.appliesTo(pred) and
|
this.appliesTo(pred) and
|
||||||
(succ(pred, _, c) or scopeLast(_, pred, c)) and
|
(succ(pred, _, c) or scopeLast(_, pred, c)) and
|
||||||
(
|
(
|
||||||
@@ -843,18 +847,18 @@ module ExceptionHandlerSplitting {
|
|||||||
* with throw completion `c`, because it belongs to the last `catch` clause
|
* with throw completion `c`, because it belongs to the last `catch` clause
|
||||||
* in a `try` statement.
|
* in a `try` statement.
|
||||||
*/
|
*/
|
||||||
private predicate hasLastExit(ControlFlowElement pred, ThrowCompletion c) {
|
private predicate hasLastExit(AstNode pred, ThrowCompletion c) {
|
||||||
this.appliesToPredecessor(pred, c) and
|
this.appliesToPredecessor(pred, c) and
|
||||||
exists(TryStmt ts, SpecificCatchClause scc, int last |
|
exists(TryStmt ts, SpecificCatchClause scc, int last |
|
||||||
last(ts.getCatchClause(last), pred, c)
|
last(ts.getCatchClause(last), pred, c)
|
||||||
|
|
|
|
||||||
ts.getCatchClause(last) = scc and
|
ts.getCatchClause(last) = scc and
|
||||||
scc.isLast() and
|
scc.isLast() and
|
||||||
c.getExceptionClass() = this.getExceptionClass()
|
c.getExceptionClass() = super.getExceptionClass()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasExit(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
|
||||||
this.appliesToPredecessor(pred, c) and
|
this.appliesToPredecessor(pred, c) and
|
||||||
succ(pred, succ, c) and
|
succ(pred, succ, c) and
|
||||||
(
|
(
|
||||||
@@ -869,13 +873,13 @@ module ExceptionHandlerSplitting {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) {
|
override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) {
|
||||||
// Exit out from last `catch` clause (no catch clauses match)
|
// Exit out from last `catch` clause (no catch clauses match)
|
||||||
this.hasLastExit(last, c) and
|
this.hasLastExit(last, c) and
|
||||||
scopeLast(scope, last, c)
|
scopeLast(scope, last, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) {
|
||||||
this.appliesToPredecessor(pred, c) and
|
this.appliesToPredecessor(pred, c) and
|
||||||
this.appliesSucc(pred, succ, c) and
|
this.appliesSucc(pred, succ, c) and
|
||||||
not first(any(SpecificCatchClause scc).getBlock(), succ) and
|
not first(any(SpecificCatchClause scc).getBlock(), succ) and
|
||||||
@@ -916,7 +920,7 @@ module BooleanSplitting {
|
|||||||
abstract predicate correlatesConditions(ConditionBlock cb1, ConditionBlock cb2, boolean inverted);
|
abstract predicate correlatesConditions(ConditionBlock cb1, ConditionBlock cb2, boolean inverted);
|
||||||
|
|
||||||
/** Holds if control flow element `cfe` starts a split of this kind. */
|
/** Holds if control flow element `cfe` starts a split of this kind. */
|
||||||
predicate startsSplit(ControlFlowElement cfe) {
|
predicate startsSplit(AstNode cfe) {
|
||||||
this.correlatesConditions(any(ConditionBlock cb | cb.getLastElement() = cfe), _, _)
|
this.correlatesConditions(any(ConditionBlock cb | cb.getLastElement() = cfe), _, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1078,27 +1082,26 @@ module BooleanSplitting {
|
|||||||
override string toString() { result = kind.toString() }
|
override string toString() { result = kind.toString() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[nomagic]
|
||||||
private predicate hasEntry0(
|
private predicate hasEntry0(
|
||||||
ControlFlowElement pred, ControlFlowElement succ, BooleanSplitSubKind kind, boolean b,
|
AstNode pred, AstNode succ, BooleanSplitSubKind kind, boolean b, Completion c
|
||||||
Completion c
|
|
||||||
) {
|
) {
|
||||||
kind.startsSplit(pred) and
|
kind.startsSplit(pred) and
|
||||||
succ(pred, succ, c) and
|
succ(pred, succ, c) and
|
||||||
b = c.getInnerCompletion().(BooleanCompletion).getValue()
|
b = c.getInnerCompletion().(BooleanCompletion).getValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BooleanSplitImpl extends SplitImpl, BooleanSplit {
|
private class BooleanSplitImpl extends SplitImpl instanceof BooleanSplit {
|
||||||
override BooleanSplitKind getKind() { result.getSubKind() = this.getSubKind() }
|
override BooleanSplitKind getKind() { result.getSubKind() = super.getSubKind() }
|
||||||
|
|
||||||
override predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
|
||||||
hasEntry0(pred, succ, this.getSubKind(), this.getBranch(), c)
|
hasEntry0(pred, succ, super.getSubKind(), super.getBranch(), c)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasEntryScope(CfgScope scope, ControlFlowElement first) { none() }
|
override predicate hasEntryScope(CfgScope scope, AstNode first) { none() }
|
||||||
|
|
||||||
private ConditionBlock getACorrelatedCondition(boolean inverted) {
|
private ConditionBlock getACorrelatedCondition(boolean inverted) {
|
||||||
this.getSubKind().correlatesConditions(_, result, inverted)
|
super.getSubKind().correlatesConditions(_, result, inverted)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1107,35 +1110,35 @@ module BooleanSplitting {
|
|||||||
*/
|
*/
|
||||||
private predicate appliesToBlock(PreBasicBlock bb, Completion c) {
|
private predicate appliesToBlock(PreBasicBlock bb, Completion c) {
|
||||||
this.appliesTo(bb) and
|
this.appliesTo(bb) and
|
||||||
exists(ControlFlowElement last | last = bb.getLastElement() |
|
exists(AstNode last | last = bb.getLastElement() |
|
||||||
(succ(last, _, c) or scopeLast(_, last, c)) and
|
(succ(last, _, c) or scopeLast(_, last, c)) and
|
||||||
// Respect the value recorded in this split for all correlated conditions
|
// Respect the value recorded in this split for all correlated conditions
|
||||||
forall(boolean inverted | bb = this.getACorrelatedCondition(inverted) |
|
forall(boolean inverted | bb = this.getACorrelatedCondition(inverted) |
|
||||||
c.getInnerCompletion() instanceof BooleanCompletion
|
c.getInnerCompletion() instanceof BooleanCompletion
|
||||||
implies
|
implies
|
||||||
c.getInnerCompletion().(BooleanCompletion).getValue() =
|
c.getInnerCompletion().(BooleanCompletion).getValue() =
|
||||||
this.getBranch().booleanXor(inverted)
|
super.getBranch().booleanXor(inverted)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasExit(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
|
||||||
exists(PreBasicBlock bb | this.appliesToBlock(bb, c) |
|
exists(PreBasicBlock bb | this.appliesToBlock(bb, c) |
|
||||||
pred = bb.getLastElement() and
|
pred = bb.getLastElement() and
|
||||||
succ(pred, succ, c) and
|
succ(pred, succ, c) and
|
||||||
// Exit this split if we can no longer reach a correlated condition
|
// Exit this split if we can no longer reach a correlated condition
|
||||||
not this.getSubKind().canReachCorrelatedCondition(succ)
|
not super.getSubKind().canReachCorrelatedCondition(succ)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) {
|
override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) {
|
||||||
exists(PreBasicBlock bb | this.appliesToBlock(bb, c) |
|
exists(PreBasicBlock bb | this.appliesToBlock(bb, c) |
|
||||||
last = bb.getLastElement() and
|
last = bb.getLastElement() and
|
||||||
scopeLast(scope, last, c)
|
scopeLast(scope, last, c)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) {
|
||||||
exists(PreBasicBlock bb, Completion c0 | this.appliesToBlock(bb, c0) |
|
exists(PreBasicBlock bb, Completion c0 | this.appliesToBlock(bb, c0) |
|
||||||
pred = bb.getAnElement() and
|
pred = bb.getAnElement() and
|
||||||
this.appliesSucc(pred, succ, c) and
|
this.appliesSucc(pred, succ, c) and
|
||||||
@@ -1144,7 +1147,7 @@ module BooleanSplitting {
|
|||||||
implies
|
implies
|
||||||
(
|
(
|
||||||
// We must still be able to reach a correlated condition to stay in this split
|
// We must still be able to reach a correlated condition to stay in this split
|
||||||
this.getSubKind().canReachCorrelatedCondition(succ) and
|
super.getSubKind().canReachCorrelatedCondition(succ) and
|
||||||
c = c0
|
c = c0
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -1174,15 +1177,15 @@ module LoopSplitting {
|
|||||||
*/
|
*/
|
||||||
abstract class AnalyzableLoopStmt extends LoopStmt {
|
abstract class AnalyzableLoopStmt extends LoopStmt {
|
||||||
/** Holds if the step `pred --c--> succ` should start the split. */
|
/** Holds if the step `pred --c--> succ` should start the split. */
|
||||||
abstract predicate start(ControlFlowElement pred, ControlFlowElement succ, Completion c);
|
abstract predicate start(AstNode pred, AstNode succ, Completion c);
|
||||||
|
|
||||||
/** Holds if the step `pred --c--> succ` should stop the split. */
|
/** Holds if the step `pred --c--> succ` should stop the split. */
|
||||||
abstract predicate stop(ControlFlowElement pred, ControlFlowElement succ, Completion c);
|
abstract predicate stop(AstNode pred, AstNode succ, Completion c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if any step `pred --c--> _` should be pruned from the control flow graph.
|
* Holds if any step `pred --c--> _` should be pruned from the control flow graph.
|
||||||
*/
|
*/
|
||||||
abstract predicate pruneLoopCondition(ControlFlowElement pred, ConditionalCompletion c);
|
abstract predicate pruneLoopCondition(AstNode pred, ConditionalCompletion c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the body is guaranteed to be executed at least once. If not, the
|
* Holds if the body is guaranteed to be executed at least once. If not, the
|
||||||
@@ -1219,17 +1222,17 @@ module LoopSplitting {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate start(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate start(AstNode pred, AstNode succ, Completion c) {
|
||||||
last(this.getIterableExpr(), pred, c) and
|
last(this.getIterableExpr(), pred, c) and
|
||||||
succ = this
|
succ = this
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate stop(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate stop(AstNode pred, AstNode succ, Completion c) {
|
||||||
pred = this and
|
pred = this and
|
||||||
succ(pred, succ, c)
|
succ(pred, succ, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate pruneLoopCondition(ControlFlowElement pred, ConditionalCompletion c) {
|
override predicate pruneLoopCondition(AstNode pred, ConditionalCompletion c) {
|
||||||
pred = this and
|
pred = this and
|
||||||
c = any(EmptinessCompletion ec | if v.isEmpty() then not ec.isEmpty() else ec.isEmpty())
|
c = any(EmptinessCompletion ec | if v.isEmpty() then not ec.isEmpty() else ec.isEmpty())
|
||||||
}
|
}
|
||||||
@@ -1298,36 +1301,40 @@ module LoopSplitting {
|
|||||||
override string toString() { result = "Unroll" }
|
override string toString() { result = "Unroll" }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class LoopUnrollingSplitImpl extends SplitImpl, LoopSplit {
|
private class LoopUnrollingSplitImpl extends SplitImpl instanceof LoopSplit {
|
||||||
|
AnalyzableLoopStmt loop;
|
||||||
|
|
||||||
|
LoopUnrollingSplitImpl() { this = TLoopSplit(loop) }
|
||||||
|
|
||||||
override LoopSplitKind getKind() { result = TLoopSplitKind(loop) }
|
override LoopSplitKind getKind() { result = TLoopSplitKind(loop) }
|
||||||
|
|
||||||
override predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
|
||||||
loop.start(pred, succ, c)
|
loop.start(pred, succ, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasEntryScope(CfgScope scope, ControlFlowElement first) { none() }
|
override predicate hasEntryScope(CfgScope scope, AstNode first) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this split applies to control flow element `pred`, where `pred`
|
* Holds if this split applies to control flow element `pred`, where `pred`
|
||||||
* is a valid predecessor.
|
* is a valid predecessor.
|
||||||
*/
|
*/
|
||||||
private predicate appliesToPredecessor(ControlFlowElement pred, Completion c) {
|
private predicate appliesToPredecessor(AstNode pred, Completion c) {
|
||||||
this.appliesTo(pred) and
|
this.appliesTo(pred) and
|
||||||
(succ(pred, _, c) or scopeLast(_, pred, c)) and
|
(succ(pred, _, c) or scopeLast(_, pred, c)) and
|
||||||
not loop.pruneLoopCondition(pred, c)
|
not loop.pruneLoopCondition(pred, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasExit(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
|
||||||
this.appliesToPredecessor(pred, c) and
|
this.appliesToPredecessor(pred, c) and
|
||||||
loop.stop(pred, succ, c)
|
loop.stop(pred, succ, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) {
|
override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) {
|
||||||
this.appliesToPredecessor(last, c) and
|
this.appliesToPredecessor(last, c) and
|
||||||
scopeLast(scope, last, c)
|
scopeLast(scope, last, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) {
|
||||||
this.appliesToPredecessor(pred, c) and
|
this.appliesToPredecessor(pred, c) and
|
||||||
this.appliesSucc(pred, succ, c) and
|
this.appliesSucc(pred, succ, c) and
|
||||||
not loop.stop(pred, succ, c)
|
not loop.stop(pred, succ, c)
|
||||||
|
|||||||
@@ -411,7 +411,7 @@ module Ssa {
|
|||||||
* This is either an expression, for example `x = 0`, a parameter, or a
|
* This is either an expression, for example `x = 0`, a parameter, or a
|
||||||
* callable. Phi nodes have no associated syntax element.
|
* callable. Phi nodes have no associated syntax element.
|
||||||
*/
|
*/
|
||||||
Element getElement() { result = this.getControlFlowNode().getElement() }
|
Element getElement() { result = this.getControlFlowNode().getAstNode() }
|
||||||
|
|
||||||
/** Gets the callable to which this SSA definition belongs. */
|
/** Gets the callable to which this SSA definition belongs. */
|
||||||
final Callable getEnclosingCallable() {
|
final Callable getEnclosingCallable() {
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ private ControlFlowElement getANonExactScopeChild(ControlFlowScope scope) {
|
|||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, boolean exactScope) {
|
private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, boolean exactScope) {
|
||||||
result.getANode().getElement() = getANonExactScopeChild(scope) and
|
result.getANode().getAstNode() = getANonExactScopeChild(scope) and
|
||||||
exactScope = false
|
exactScope = false
|
||||||
or
|
or
|
||||||
scope.isExact() and
|
scope.isExact() and
|
||||||
result.getANode().getElement() = scope and
|
result.getANode().getAstNode() = scope and
|
||||||
exactScope = true
|
exactScope = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,10 +104,10 @@ private module Cached {
|
|||||||
newtype TDataFlowCall =
|
newtype TDataFlowCall =
|
||||||
TNonDelegateCall(ControlFlow::Nodes::ElementNode cfn, DispatchCall dc) {
|
TNonDelegateCall(ControlFlow::Nodes::ElementNode cfn, DispatchCall dc) {
|
||||||
DataFlowImplCommon::forceCachingInSameStage() and
|
DataFlowImplCommon::forceCachingInSameStage() and
|
||||||
cfn.getElement() = dc.getCall()
|
cfn.getAstNode() = dc.getCall()
|
||||||
} or
|
} or
|
||||||
TExplicitDelegateLikeCall(ControlFlow::Nodes::ElementNode cfn, DelegateLikeCall dc) {
|
TExplicitDelegateLikeCall(ControlFlow::Nodes::ElementNode cfn, DelegateLikeCall dc) {
|
||||||
cfn.getElement() = dc
|
cfn.getAstNode() = dc
|
||||||
} or
|
} or
|
||||||
TTransitiveCapturedCall(ControlFlow::Nodes::ElementNode cfn, Callable target) {
|
TTransitiveCapturedCall(ControlFlow::Nodes::ElementNode cfn, Callable target) {
|
||||||
transitiveCapturedCallTarget(cfn, target)
|
transitiveCapturedCallTarget(cfn, target)
|
||||||
|
|||||||
@@ -819,7 +819,7 @@ private module Cached {
|
|||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TNode =
|
newtype TNode =
|
||||||
TExprNode(ControlFlow::Nodes::ElementNode cfn) { cfn.getElement() instanceof Expr } or
|
TExprNode(ControlFlow::Nodes::ElementNode cfn) { cfn.getAstNode() instanceof Expr } or
|
||||||
TCilExprNode(CIL::Expr e) { e.getImplementation() instanceof CIL::BestImplementation } or
|
TCilExprNode(CIL::Expr e) { e.getImplementation() instanceof CIL::BestImplementation } or
|
||||||
TCilSsaDefinitionExtNode(CilSsaImpl::DefinitionExt def) or
|
TCilSsaDefinitionExtNode(CilSsaImpl::DefinitionExt def) or
|
||||||
TSsaDefinitionExtNode(SsaImpl::DefinitionExt def) {
|
TSsaDefinitionExtNode(SsaImpl::DefinitionExt def) {
|
||||||
@@ -835,19 +835,19 @@ private module Cached {
|
|||||||
not c.(Modifiable).isStatic()
|
not c.(Modifiable).isStatic()
|
||||||
} or
|
} or
|
||||||
TYieldReturnNode(ControlFlow::Nodes::ElementNode cfn) {
|
TYieldReturnNode(ControlFlow::Nodes::ElementNode cfn) {
|
||||||
any(Callable c).canYieldReturn(cfn.getElement())
|
any(Callable c).canYieldReturn(cfn.getAstNode())
|
||||||
} or
|
} or
|
||||||
TAsyncReturnNode(ControlFlow::Nodes::ElementNode cfn) {
|
TAsyncReturnNode(ControlFlow::Nodes::ElementNode cfn) {
|
||||||
any(Callable c | c.(Modifiable).isAsync()).canReturn(cfn.getElement())
|
any(Callable c | c.(Modifiable).isAsync()).canReturn(cfn.getAstNode())
|
||||||
} or
|
} or
|
||||||
TImplicitCapturedArgumentNode(ControlFlow::Nodes::ElementNode cfn, LocalScopeVariable v) {
|
TImplicitCapturedArgumentNode(ControlFlow::Nodes::ElementNode cfn, LocalScopeVariable v) {
|
||||||
exists(Ssa::ExplicitDefinition def | def.isCapturedVariableDefinitionFlowIn(_, cfn, _) |
|
exists(Ssa::ExplicitDefinition def | def.isCapturedVariableDefinitionFlowIn(_, cfn, _) |
|
||||||
v = def.getSourceVariable().getAssignable()
|
v = def.getSourceVariable().getAssignable()
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TMallocNode(ControlFlow::Nodes::ElementNode cfn) { cfn.getElement() instanceof ObjectCreation } or
|
TMallocNode(ControlFlow::Nodes::ElementNode cfn) { cfn.getAstNode() instanceof ObjectCreation } or
|
||||||
TObjectInitializerNode(ControlFlow::Nodes::ElementNode cfn) {
|
TObjectInitializerNode(ControlFlow::Nodes::ElementNode cfn) {
|
||||||
cfn.getElement().(ObjectCreation).hasInitializer()
|
cfn.getAstNode().(ObjectCreation).hasInitializer()
|
||||||
} or
|
} or
|
||||||
TExprPostUpdateNode(ControlFlow::Nodes::ExprNode cfn) {
|
TExprPostUpdateNode(ControlFlow::Nodes::ExprNode cfn) {
|
||||||
cfn = LocalFlow::getAPostUpdateNodeForArg(_)
|
cfn = LocalFlow::getAPostUpdateNodeForArg(_)
|
||||||
@@ -1256,7 +1256,7 @@ private module ArgumentNodes {
|
|||||||
result.asCallable() = cfn.getEnclosingCallable()
|
result.asCallable() = cfn.getEnclosingCallable()
|
||||||
}
|
}
|
||||||
|
|
||||||
override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() }
|
override Type getTypeImpl() { result = cfn.getAstNode().(Expr).getType() }
|
||||||
|
|
||||||
override Location getLocationImpl() { result = cfn.getLocation() }
|
override Location getLocationImpl() { result = cfn.getLocation() }
|
||||||
|
|
||||||
@@ -1397,7 +1397,7 @@ private module ReturnNodes {
|
|||||||
private ControlFlow::Nodes::ElementNode cfn;
|
private ControlFlow::Nodes::ElementNode cfn;
|
||||||
private Expr expr;
|
private Expr expr;
|
||||||
|
|
||||||
AsyncReturnNode() { this = TAsyncReturnNode(cfn) and expr = cfn.getElement() }
|
AsyncReturnNode() { this = TAsyncReturnNode(cfn) and expr = cfn.getAstNode() }
|
||||||
|
|
||||||
Expr getExpr() { result = expr }
|
Expr getExpr() { result = expr }
|
||||||
|
|
||||||
@@ -2106,7 +2106,7 @@ private module PostUpdateNodes {
|
|||||||
result.asCallable() = cfn.getEnclosingCallable()
|
result.asCallable() = cfn.getEnclosingCallable()
|
||||||
}
|
}
|
||||||
|
|
||||||
override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() }
|
override Type getTypeImpl() { result = cfn.getAstNode().(Expr).getType() }
|
||||||
|
|
||||||
override ControlFlow::Node getControlFlowNodeImpl() { none() }
|
override ControlFlow::Node getControlFlowNodeImpl() { none() }
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ class ExprNode extends Node, TExprNode_ {
|
|||||||
*/
|
*/
|
||||||
Expr getExprAtNode(ControlFlow::Nodes::ElementNode cfn) {
|
Expr getExprAtNode(ControlFlow::Nodes::ElementNode cfn) {
|
||||||
this = TExprNode(cfn) and
|
this = TExprNode(cfn) and
|
||||||
result = cfn.getElement()
|
result = cfn.getAstNode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ module ExposedForTestingOnly {
|
|||||||
* Holds if the `i`th node of basic block `bb` reads source variable `v`.
|
* Holds if the `i`th node of basic block `bb` reads source variable `v`.
|
||||||
*/
|
*/
|
||||||
private predicate variableReadActual(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v) {
|
private predicate variableReadActual(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v) {
|
||||||
v.getAnAccess().(AssignableRead) = bb.getNode(i).getElement()
|
v.getAnAccess().(AssignableRead) = bb.getNode(i).getAstNode()
|
||||||
}
|
}
|
||||||
|
|
||||||
private module SourceVariableImpl {
|
private module SourceVariableImpl {
|
||||||
@@ -939,7 +939,7 @@ private module CapturedVariableLivenessImpl {
|
|||||||
CapturedReadLocalScopeVariable captured, Callable c, boolean libraryDelegateCall
|
CapturedReadLocalScopeVariable captured, Callable c, boolean libraryDelegateCall
|
||||||
) {
|
) {
|
||||||
implicitReadCandidate(v, call) and
|
implicitReadCandidate(v, call) and
|
||||||
c = getARuntimeTarget(call.getElement(), libraryDelegateCall) and
|
c = getARuntimeTarget(call.getAstNode(), libraryDelegateCall) and
|
||||||
captured = v.getAssignable() and
|
captured = v.getAssignable() and
|
||||||
capturerReads(_, captured)
|
capturerReads(_, captured)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ private ControlFlowElement getANonExactScopeChild(ControlFlowScope scope) {
|
|||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, boolean exactScope) {
|
private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, boolean exactScope) {
|
||||||
result.getANode().getElement() = getANonExactScopeChild(scope) and
|
result.getANode().getAstNode() = getANonExactScopeChild(scope) and
|
||||||
exactScope = false
|
exactScope = false
|
||||||
or
|
or
|
||||||
scope.isExact() and
|
scope.isExact() and
|
||||||
result.getANode().getElement() = scope and
|
result.getANode().getAstNode() = scope and
|
||||||
exactScope = true
|
exactScope = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ private class PhiInputEdgeBlock extends BasicBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int getId(PhiInputEdgeBlock bb) {
|
private int getId(PhiInputEdgeBlock bb) {
|
||||||
exists(CfgImpl::ControlFlowTree::Range_ t | CfgImpl::ControlFlowTree::idOf(t, result) |
|
exists(CfgImpl::AstNode n | result = n.getId() |
|
||||||
t = bb.getFirstNode().getElement()
|
n = bb.getFirstNode().getAstNode()
|
||||||
or
|
or
|
||||||
t = bb.(ControlFlow::BasicBlocks::EntryBlock).getCallable()
|
n = bb.(ControlFlow::BasicBlocks::EntryBlock).getCallable()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
import csharp
|
import csharp
|
||||||
|
|
||||||
predicate lockedFieldUpdate(LockStmt lock, Field f, AssignableDefinition def) {
|
predicate lockedFieldUpdate(LockStmt lock, Field f, AssignableDefinition def) {
|
||||||
lock.getAChild+() = def.getAControlFlowNode().getElement() and
|
lock.getAChild+() = def.getAControlFlowNode().getAstNode() and
|
||||||
def.getTarget() = f
|
def.getTarget() = f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ ControlFlow::Node unlockedReachable(Callable a) {
|
|||||||
result = a.getEntryPoint()
|
result = a.getEntryPoint()
|
||||||
or
|
or
|
||||||
exists(ControlFlow::Node mid | mid = unlockedReachable(a) |
|
exists(ControlFlow::Node mid | mid = unlockedReachable(a) |
|
||||||
not mid.getElement() instanceof LockingCall and
|
not mid.getAstNode() instanceof LockingCall and
|
||||||
result = mid.getASuccessor()
|
result = mid.getASuccessor()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,20 +81,20 @@ class NestedForLoopSameVariable extends ForStmt {
|
|||||||
|
|
||||||
/** Finds elements inside the outer loop that are no longer guarded by the loop invariant. */
|
/** Finds elements inside the outer loop that are no longer guarded by the loop invariant. */
|
||||||
private ControlFlow::Node getAnUnguardedNode() {
|
private ControlFlow::Node getAnUnguardedNode() {
|
||||||
hasChild(this.getOuterForStmt().getBody(), result.getElement()) and
|
hasChild(this.getOuterForStmt().getBody(), result.getAstNode()) and
|
||||||
(
|
(
|
||||||
result =
|
result =
|
||||||
this.getCondition().(ControlFlowElement).getAControlFlowExitNode().getAFalseSuccessor()
|
this.getCondition().(ControlFlowElement).getAControlFlowExitNode().getAFalseSuccessor()
|
||||||
or
|
or
|
||||||
exists(ControlFlow::Node mid | mid = this.getAnUnguardedNode() |
|
exists(ControlFlow::Node mid | mid = this.getAnUnguardedNode() |
|
||||||
mid.getASuccessor() = result and
|
mid.getASuccessor() = result and
|
||||||
not exists(this.getAComparisonTest(result.getElement()))
|
not exists(this.getAComparisonTest(result.getAstNode()))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private VariableAccess getAnUnguardedAccess() {
|
private VariableAccess getAnUnguardedAccess() {
|
||||||
result = this.getAnUnguardedNode().getElement() and
|
result = this.getAnUnguardedNode().getAstNode() and
|
||||||
result.getTarget() = iteration
|
result.getTarget() = iteration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ import csharp
|
|||||||
|
|
||||||
// Iterate the control flow until we reach a Stmt
|
// Iterate the control flow until we reach a Stmt
|
||||||
Stmt findSuccessorStmt(ControlFlow::Node n) {
|
Stmt findSuccessorStmt(ControlFlow::Node n) {
|
||||||
result = n.getElement()
|
result = n.getAstNode()
|
||||||
or
|
or
|
||||||
not n.getElement() instanceof Stmt and result = findSuccessorStmt(n.getASuccessor())
|
not n.getAstNode() instanceof Stmt and result = findSuccessorStmt(n.getASuccessor())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a successor statement to s
|
// Return a successor statement to s
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ private predicate equalsMethodChild(EqualsMethod equals, Element child) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate nodeBeforeParameterAccess(ControlFlow::Node node) {
|
predicate nodeBeforeParameterAccess(ControlFlow::Node node) {
|
||||||
exists(EqualsMethod equals | equals.getBody() = node.getElement())
|
exists(EqualsMethod equals | equals.getBody() = node.getAstNode())
|
||||||
or
|
or
|
||||||
exists(EqualsMethod equals, Parameter param, ControlFlow::Node mid |
|
exists(EqualsMethod equals, Parameter param, ControlFlow::Node mid |
|
||||||
equals.getParameter(0) = param and
|
equals.getParameter(0) = param and
|
||||||
equalsMethodChild(equals, mid.getElement()) and
|
equalsMethodChild(equals, mid.getAstNode()) and
|
||||||
nodeBeforeParameterAccess(mid) and
|
nodeBeforeParameterAccess(mid) and
|
||||||
not param.getAnAccess() = mid.getElement() and
|
not param.getAnAccess() = mid.getAstNode() and
|
||||||
mid.getASuccessor() = node
|
mid.getASuccessor() = node
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,16 +58,16 @@ predicate sessionUse(MemberAccess ma) {
|
|||||||
/** A control flow step that is not sanitised by a call to clear the session. */
|
/** A control flow step that is not sanitised by a call to clear the session. */
|
||||||
predicate controlStep(ControlFlow::Node s1, ControlFlow::Node s2) {
|
predicate controlStep(ControlFlow::Node s1, ControlFlow::Node s2) {
|
||||||
s2 = s1.getASuccessor() and
|
s2 = s1.getASuccessor() and
|
||||||
not sessionEndMethod(s2.getElement().(MethodCall).getTarget())
|
not sessionEndMethod(s2.getAstNode().(MethodCall).getTarget())
|
||||||
}
|
}
|
||||||
|
|
||||||
from
|
from
|
||||||
ControlFlow::Node loginCall, Method loginMethod, ControlFlow::Node sessionUse,
|
ControlFlow::Node loginCall, Method loginMethod, ControlFlow::Node sessionUse,
|
||||||
ControlFlow::SuccessorType fromLoginFlow
|
ControlFlow::SuccessorType fromLoginFlow
|
||||||
where
|
where
|
||||||
loginMethod = loginCall.getElement().(MethodCall).getTarget() and
|
loginMethod = loginCall.getAstNode().(MethodCall).getTarget() and
|
||||||
loginMethod(loginMethod, fromLoginFlow) and
|
loginMethod(loginMethod, fromLoginFlow) and
|
||||||
sessionUse(sessionUse.getElement()) and
|
sessionUse(sessionUse.getAstNode()) and
|
||||||
controlStep+(loginCall.getASuccessorByType(fromLoginFlow), sessionUse)
|
controlStep+(loginCall.getASuccessorByType(fromLoginFlow), sessionUse)
|
||||||
select sessionUse, "This session has not been invalidated following the call to $@.", loginCall,
|
select sessionUse, "This session has not been invalidated following the call to $@.", loginCall,
|
||||||
loginMethod.getName()
|
loginMethod.getName()
|
||||||
|
|||||||
@@ -2,5 +2,5 @@ import csharp
|
|||||||
|
|
||||||
query predicate deadCode(MethodCall c) {
|
query predicate deadCode(MethodCall c) {
|
||||||
c.getTarget().getName() = "DeadCode" and
|
c.getTarget().getName() = "DeadCode" and
|
||||||
not exists(ControlFlow::Node node | node.getElement() = c)
|
not exists(ControlFlow::Node node | node.getAstNode() = c)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,6 @@
|
|||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import Common
|
import Common
|
||||||
import semmle.code.csharp.controlflow.internal.ControlFlowGraphImplShared::TestOutput
|
import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl::TestOutput
|
||||||
|
|
||||||
private class MyRelevantNode extends RelevantNode, SourceControlFlowNode { }
|
private class MyRelevantNode extends RelevantNode, SourceControlFlowNode { }
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import csharp
|
import csharp
|
||||||
import ControlFlow
|
import ControlFlow
|
||||||
import Common
|
import Common
|
||||||
import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl
|
import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl as Impl
|
||||||
import semmle.code.csharp.controlflow.internal.Splitting as Splitting
|
import semmle.code.csharp.controlflow.internal.Splitting as Splitting
|
||||||
import Nodes
|
import Nodes
|
||||||
|
|
||||||
@@ -16,11 +16,11 @@ class MyFinallySplitControlFlowNode extends ElementNode {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Statements::TryStmtTree getTryStmt() { this.getElement() = result.getAFinallyDescendant() }
|
Impl::Statements::TryStmtTree getTryStmt() { this.getAstNode() = result.getAFinallyDescendant() }
|
||||||
}
|
}
|
||||||
|
|
||||||
query predicate finallyNode(MyFinallySplitControlFlowNode f, TryStmt try) { try = f.getTryStmt() }
|
query predicate finallyNode(MyFinallySplitControlFlowNode f, TryStmt try) { try = f.getTryStmt() }
|
||||||
|
|
||||||
query predicate entryPoint(Callable c, SourceControlFlowElement cfn) {
|
query predicate entryPoint(Callable c, SourceControlFlowElement cfn) {
|
||||||
c.getEntryPoint().getASuccessor().getElement() = cfn
|
c.getEntryPoint().getASuccessor().getAstNode() = cfn
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import csharp
|
|||||||
|
|
||||||
query predicate countSplits(ControlFlowElement cfe, int i) {
|
query predicate countSplits(ControlFlowElement cfe, int i) {
|
||||||
not cfe.fromLibrary() and
|
not cfe.fromLibrary() and
|
||||||
i = strictcount(ControlFlow::Nodes::ElementNode n | n.getElement() = cfe)
|
i = strictcount(ControlFlow::Nodes::ElementNode n | n.getAstNode() = cfe)
|
||||||
}
|
}
|
||||||
|
|
||||||
query predicate ssaDef(Ssa::Definition def) { any() }
|
query predicate ssaDef(Ssa::Definition def) { any() }
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl
|
|||||||
import semmle.code.csharp.dataflow.internal.SsaImpl as SsaImpl
|
import semmle.code.csharp.dataflow.internal.SsaImpl as SsaImpl
|
||||||
|
|
||||||
class CallableWithSplitting extends Callable {
|
class CallableWithSplitting extends Callable {
|
||||||
CallableWithSplitting() { this = any(SplitControlFlowElement e).getEnclosingCallable() }
|
CallableWithSplitting() { this = any(SplitAstNode n).getEnclosingCallable() }
|
||||||
}
|
}
|
||||||
|
|
||||||
query predicate defReadInconsistency(
|
query predicate defReadInconsistency(
|
||||||
@@ -57,8 +57,8 @@ query predicate readReadInconsistency(
|
|||||||
not PreSsa::adjacentReadPairSameVar(read1, read2) and
|
not PreSsa::adjacentReadPairSameVar(read1, read2) and
|
||||||
// Exclude split CFG elements because SSA may be more precise than pre-SSA
|
// Exclude split CFG elements because SSA may be more precise than pre-SSA
|
||||||
// in those cases
|
// in those cases
|
||||||
not read1 instanceof SplitControlFlowElement and
|
not read1 instanceof SplitAstNode and
|
||||||
not read2 instanceof SplitControlFlowElement
|
not read2 instanceof SplitAstNode
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ query predicate phiInconsistency(
|
|||||||
|
|
|
|
||||||
edef.getADefinition() = adef and
|
edef.getADefinition() = adef and
|
||||||
phi.definesAt(_, bb, _) and
|
phi.definesAt(_, bb, _) and
|
||||||
cfe = bb.getFirstNode().getElement()
|
cfe = bb.getFirstNode().getAstNode()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -89,7 +89,7 @@ query predicate phiInconsistency(
|
|||||||
edef = phi.getAnUltimateDefinition() and
|
edef = phi.getAnUltimateDefinition() and
|
||||||
edef.getADefinition() = adef and
|
edef.getADefinition() = adef and
|
||||||
phi.definesAt(_, bb, _) and
|
phi.definesAt(_, bb, _) and
|
||||||
cfe = bb.getFirstNode().getElement() and
|
cfe = bb.getFirstNode().getAstNode() and
|
||||||
not exists(PreSsa::PhiNode prePhi |
|
not exists(PreSsa::PhiNode prePhi |
|
||||||
adef = prePhi.getAnInput+().getDefinition() and
|
adef = prePhi.getAnInput+().getDefinition() and
|
||||||
cfe = prePhi.getBasicBlock().getFirstElement()
|
cfe = prePhi.getBasicBlock().getFirstElement()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import csharp
|
import csharp
|
||||||
|
|
||||||
query predicate edges(ControlFlow::Node node, ControlFlow::Node successor, string attr, string val) {
|
query predicate edges(ControlFlow::Node node, ControlFlow::Node successor, string attr, string val) {
|
||||||
not node.getElement().fromLibrary() and
|
not node.getAstNode().fromLibrary() and
|
||||||
exists(ControlFlow::SuccessorType t | successor = node.getASuccessorByType(t) |
|
exists(ControlFlow::SuccessorType t | successor = node.getASuccessorByType(t) |
|
||||||
attr = "semmle.label" and
|
attr = "semmle.label" and
|
||||||
val = t.toString()
|
val = t.toString()
|
||||||
|
|||||||
@@ -12,5 +12,5 @@ class UnknownCall extends Call {
|
|||||||
}
|
}
|
||||||
|
|
||||||
query predicate edges(ControlFlow::Node n1, ControlFlow::Node n2) {
|
query predicate edges(ControlFlow::Node n1, ControlFlow::Node n2) {
|
||||||
not n1.getElement().fromLibrary() and n2 = n1.getASuccessor()
|
not n1.getAstNode().fromLibrary() and n2 = n1.getASuccessor()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -937,23 +937,6 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the CFG scope of node `n`. Unlike `getCfgScope`, this predicate
|
|
||||||
* is calculated based on reachability from an entry node, and it may
|
|
||||||
* yield different results for AST elements that are split into multiple
|
|
||||||
* scopes.
|
|
||||||
*/
|
|
||||||
cached
|
|
||||||
CfgScope getNodeCfgScope(Node n) {
|
|
||||||
n = TEntryNode(result)
|
|
||||||
or
|
|
||||||
n = TAnnotatedExitNode(result, _)
|
|
||||||
or
|
|
||||||
n = TExitNode(result)
|
|
||||||
or
|
|
||||||
n = TAstNode(result, _, _)
|
|
||||||
}
|
|
||||||
|
|
||||||
cached
|
cached
|
||||||
module Public {
|
module Public {
|
||||||
/**
|
/**
|
||||||
@@ -974,6 +957,23 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
|||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
AstNode getAControlFlowExitNode(AstNode n) { last(n, result, _) }
|
AstNode getAControlFlowExitNode(AstNode n) { last(n, result, _) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the CFG scope of node `n`. Unlike `getCfgScope`, this predicate
|
||||||
|
* is calculated based on reachability from an entry node, and it may
|
||||||
|
* yield different results for AST elements that are split into multiple
|
||||||
|
* scopes.
|
||||||
|
*/
|
||||||
|
cached
|
||||||
|
CfgScope getNodeCfgScope(Node n) {
|
||||||
|
n = TEntryNode(result)
|
||||||
|
or
|
||||||
|
n = TAnnotatedExitNode(result, _)
|
||||||
|
or
|
||||||
|
n = TExitNode(result)
|
||||||
|
or
|
||||||
|
n = TAstNode(result, _, _)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user