Merge pull request #7288 from hvitved/cfg/enclosing-scope

Shared CFG: Include CFG scope in `TElementNode`
This commit is contained in:
Tom Hvitved
2021-12-09 13:39:48 +01:00
committed by GitHub
8 changed files with 95 additions and 72 deletions

View File

@@ -15,7 +15,7 @@ private import SuccessorTypes
*/
class BasicBlock extends TBasicBlockStart {
/** Gets the scope of this basic block. */
CfgScope getScope() { result = this.getAPredecessor().getScope() }
final CfgScope getScope() { result = this.getFirstNode().getScope() }
/** Gets an immediate successor of this basic block, if any. */
BasicBlock getASuccessor() { result = this.getASuccessor(_) }
@@ -322,8 +322,6 @@ private predicate entryBB(BasicBlock bb) { bb.getFirstNode() instanceof EntryNod
*/
class EntryBasicBlock extends BasicBlock {
EntryBasicBlock() { entryBB(this) }
override CfgScope getScope() { this.getFirstNode() = TEntryNode(result) }
}
/**

View File

@@ -67,7 +67,7 @@ class AstCfgNode extends CfgNode, TElementNode {
private Splits splits;
private AstNode n;
AstCfgNode() { this = TElementNode(n, splits) }
AstCfgNode() { this = TElementNode(_, n, splits) }
final override AstNode getNode() { result = n }

View File

@@ -44,7 +44,7 @@ class CfgNode extends TCfgNode {
final predicate isCondition() { exists(this.getASuccessor(any(BooleanSuccessor bs))) }
/** Gets the scope of this node. */
final CfgScope getScope() { result = this.getBasicBlock().getScope() }
final CfgScope getScope() { result = getNodeCfgScope(this) }
/** Gets the basic block that this control flow node belongs to. */
BasicBlock getBasicBlock() { result.getANode() = this }

View File

@@ -342,7 +342,7 @@ private predicate succExitSplits(
ControlFlowElement pred, Splits predSplits, CfgScope succ, SuccessorType t
) {
exists(Reachability::SameSplitsBlock b, Completion c | pred = b.getAnElement() |
b.isReachable(predSplits) and
b.isReachable(succ, predSplits) and
t = getAMatchingSuccessorType(c) and
scopeLast(succ, pred, c) and
forall(SplitImpl predSplit | predSplit = predSplits.getASplit() |
@@ -399,7 +399,7 @@ private module SuccSplits {
ControlFlowElement succ, Completion c
) {
pred = b.getAnElement() and
b.isReachable(predSplits) and
b.isReachable(_, predSplits) and
succ(pred, succ, c)
}
@@ -728,12 +728,12 @@ private module Reachability {
* Holds if the elements of this block are reachable from a callable entry
* point, with the splits `splits`.
*/
predicate isReachable(Splits splits) {
predicate isReachable(CfgScope scope, Splits splits) {
// Base case
succEntrySplits(_, this, splits, _)
succEntrySplits(scope, this, splits, _)
or
// Recursive case
exists(SameSplitsBlock pred, Splits predSplits | pred.isReachable(predSplits) |
exists(SameSplitsBlock pred, Splits predSplits | pred.isReachable(scope, predSplits) |
this = pred.getASuccessor(predSplits, splits)
)
}
@@ -791,18 +791,20 @@ private module Cached {
newtype TCfgNode =
TEntryNode(CfgScope scope) { succEntrySplits(scope, _, _, _) } or
TAnnotatedExitNode(CfgScope scope, boolean normal) {
exists(Reachability::SameSplitsBlock b, SuccessorType t | b.isReachable(_) |
exists(Reachability::SameSplitsBlock b, SuccessorType t | b.isReachable(scope, _) |
succExitSplits(b.getAnElement(), _, scope, t) and
if isAbnormalExitType(t) then normal = false else normal = true
)
} or
TExitNode(CfgScope scope) {
exists(Reachability::SameSplitsBlock b | b.isReachable(_) |
exists(Reachability::SameSplitsBlock b | b.isReachable(scope, _) |
succExitSplits(b.getAnElement(), _, scope, _)
)
} or
TElementNode(ControlFlowElement cfe, Splits splits) {
exists(Reachability::SameSplitsBlock b | b.isReachable(splits) | cfe = b.getAnElement())
TElementNode(CfgScope scope, ControlFlowElement cfe, Splits splits) {
exists(Reachability::SameSplitsBlock b | b.isReachable(scope, splits) |
cfe = b.getAnElement()
)
}
/** Gets a successor node of a given flow type, if any. */
@@ -810,24 +812,24 @@ private module Cached {
TCfgNode getASuccessor(TCfgNode pred, SuccessorType t) {
// Callable entry node -> callable body
exists(ControlFlowElement succElement, Splits succSplits, CfgScope scope |
result = TElementNode(succElement, succSplits) and
result = TElementNode(scope, succElement, succSplits) and
pred = TEntryNode(scope) and
succEntrySplits(scope, succElement, succSplits, t)
)
or
exists(ControlFlowElement predElement, Splits predSplits |
pred = TElementNode(predElement, predSplits)
exists(CfgScope scope, ControlFlowElement predElement, Splits predSplits |
pred = TElementNode(pragma[only_bind_into](scope), predElement, predSplits)
|
// Element node -> callable exit (annotated)
exists(CfgScope scope, boolean normal |
result = TAnnotatedExitNode(scope, normal) and
exists(boolean normal |
result = TAnnotatedExitNode(pragma[only_bind_into](scope), normal) and
succExitSplits(predElement, predSplits, scope, t) and
if isAbnormalExitType(t) then normal = false else normal = true
)
or
// Element node -> element node
exists(ControlFlowElement succElement, Splits succSplits, Completion c |
result = TElementNode(succElement, succSplits)
result = TElementNode(pragma[only_bind_into](scope), succElement, succSplits)
|
succSplits(predElement, predSplits, succElement, succSplits, c) and
t = getAMatchingSuccessorType(c)
@@ -853,6 +855,23 @@ private module Cached {
*/
cached
ControlFlowElement getAControlFlowExitNode(ControlFlowElement cfe) { last(cfe, 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(TCfgNode n) {
n = TEntryNode(result)
or
n = TAnnotatedExitNode(result, _)
or
n = TExitNode(result)
or
n = TElementNode(result, _, _)
}
}
import Cached