Shared: Address review comments for shared basic block library

This commit is contained in:
Simon Friis Vindum
2025-01-17 13:11:49 +01:00
parent 8b20b0d334
commit 4d05b6a0a5
7 changed files with 96 additions and 85 deletions

View File

@@ -96,9 +96,9 @@ private module CfgInput implements CfgShared::InputSig<Location> {
t instanceof ST::SuccessorTypes::ExitSuccessor t instanceof ST::SuccessorTypes::ExitSuccessor
} }
predicate idOfAstNode(AstNode node, int id) { node.getId() = id } int idOfAstNode(AstNode node) { result = node.getId() }
predicate idOfCfgScope(CfgScope node, int id) { idOfAstNode(node, id) } int idOfCfgScope(CfgScope node) { result = idOfAstNode(node) }
} }
private module CfgSplittingInput implements CfgShared::SplittingInputSig<Location, CfgInput> { private module CfgSplittingInput implements CfgShared::SplittingInputSig<Location, CfgInput> {

View File

@@ -4,11 +4,9 @@ private import codeql.ruby.AST
private import codeql.ruby.ast.internal.AST private import codeql.ruby.ast.internal.AST
private import codeql.ruby.ast.internal.TreeSitter private import codeql.ruby.ast.internal.TreeSitter
private import codeql.ruby.controlflow.ControlFlowGraph private import codeql.ruby.controlflow.ControlFlowGraph
private import codeql.ruby.controlflow.ControlFlowGraph as Cfg
private import internal.ControlFlowGraphImpl as CfgImpl private import internal.ControlFlowGraphImpl as CfgImpl
private import CfgNodes private import CfgNodes
private import SuccessorTypes private import SuccessorTypes
private import codeql.controlflow.BasicBlock as BB
private import CfgImpl::BasicBlocks as BasicBlocksImpl private import CfgImpl::BasicBlocks as BasicBlocksImpl
/** /**

View File

@@ -65,9 +65,9 @@ private module CfgInput implements CfgShared::InputSig<Location> {
private predicate idOf(Ruby::AstNode node, int id) = equivalenceRelation(id/2)(node, id) private predicate idOf(Ruby::AstNode node, int id) = equivalenceRelation(id/2)(node, id)
predicate idOfAstNode(AstNode node, int id) { idOf(AstInternal::toGeneratedInclSynth(node), id) } int idOfAstNode(AstNode node) { idOf(AstInternal::toGeneratedInclSynth(node), result) }
predicate idOfCfgScope(CfgScope node, int id) { idOfAstNode(node, id) } int idOfCfgScope(CfgScope node) { result = idOfAstNode(node) }
} }
private module CfgSplittingInput implements CfgShared::SplittingInputSig<Location, CfgInput> { private module CfgSplittingInput implements CfgShared::SplittingInputSig<Location, CfgInput> {

View File

@@ -56,11 +56,9 @@ private module CfgInput implements InputSig<Location> {
private predicate idOfDbAstNode(Raw::AstNode x, int y) = equivalenceRelation(id/2)(x, y) private predicate idOfDbAstNode(Raw::AstNode x, int y) = equivalenceRelation(id/2)(x, y)
// TODO: does not work if fresh ipa entities (`ipa: on:`) turn out to be first of the block // TODO: does not work if fresh ipa entities (`ipa: on:`) turn out to be first of the block
predicate idOfAstNode(AstNode node, int id) { int idOfAstNode(AstNode node) { idOfDbAstNode(Synth::convertAstNodeToRaw(node), result) }
idOfDbAstNode(Synth::convertAstNodeToRaw(node), id)
}
predicate idOfCfgScope(CfgScope node, int id) { idOfAstNode(node, id) } int idOfCfgScope(CfgScope node) { result = idOfAstNode(node) }
} }
private module CfgSplittingInput implements SplittingInputSig<Location, CfgInput> { private module CfgSplittingInput implements SplittingInputSig<Location, CfgInput> {

View File

@@ -1,13 +1,15 @@
/** /**
* This modules provides an implementation of a basic block class based based * This modules provides an implementation of a basic block class based on a
* on a control flow graph implementation. * control flow graph implementation.
* *
* INTERNAL use only. This is an experimental API subject to change without * INTERNAL use only. This is an experimental API subject to change without
* notice. * notice.
*/ */
private import codeql.util.Location
/** Provides the language-specific input specification. */ /** Provides the language-specific input specification. */
signature module InputSig { signature module InputSig<LocationSig Location> {
class SuccessorType; class SuccessorType;
/** Hold if `t` represents a conditional successor type. */ /** Hold if `t` represents a conditional successor type. */
@@ -16,21 +18,31 @@ signature module InputSig {
/** The class of control flow nodes. */ /** The class of control flow nodes. */
class Node { class Node {
string toString(); string toString();
/** Gets the location of this control flow node. */
Location getLocation();
} }
/** Gets an immediate successor of this node. */
Node nodeGetASuccessor(Node node, SuccessorType t); Node nodeGetASuccessor(Node node, SuccessorType t);
/** Holds if `node` is the beginning of an entry basic block. */ /**
predicate nodeIsEntry(Node node); * Holds if `node` represents an entry node to be used when calculating
* dominance.
*/
predicate nodeIsDominanceEntry(Node node);
/** Holds if `node` is the beginning of an entry basic block. */ /**
predicate nodeIsExit(Node node); * Holds if `node` represents an exit node to be used when calculating
* post dominance.
*/
predicate nodeIsPostDominanceExit(Node node);
} }
/** /**
* Provides a basic block construction on top of a control flow graph. * Provides a basic block construction on top of a control flow graph.
*/ */
module Make<InputSig Input> { module Make<LocationSig Location, InputSig<Location> Input> {
private import Input private import Input
final class BasicBlock = BasicBlockImpl; final class BasicBlock = BasicBlockImpl;
@@ -42,6 +54,7 @@ module Make<InputSig Input> {
/** Holds if this node has more than one predecessor. */ /** Holds if this node has more than one predecessor. */
private predicate nodeIsJoin(Node node) { strictcount(nodeGetAPredecessor(node, _)) > 1 } private predicate nodeIsJoin(Node node) { strictcount(nodeGetAPredecessor(node, _)) > 1 }
/** Holds if this node has more than one successor. */
private predicate nodeIsBranch(Node node) { strictcount(nodeGetASuccessor(node, _)) > 1 } private predicate nodeIsBranch(Node node) { strictcount(nodeGetASuccessor(node, _)) > 1 }
/** /**
@@ -49,6 +62,9 @@ module Make<InputSig Input> {
* without branches or joins. * without branches or joins.
*/ */
private class BasicBlockImpl extends TBasicBlockStart { private class BasicBlockImpl extends TBasicBlockStart {
/** Gets the location of this basic block. */
Location getLocation() { result = this.getFirstNode().getLocation() }
/** Gets an immediate successor of this basic block, if any. */ /** Gets an immediate successor of this basic block, if any. */
BasicBlock getASuccessor() { result = this.getASuccessor(_) } BasicBlock getASuccessor() { result = this.getASuccessor(_) }
@@ -64,6 +80,7 @@ module Make<InputSig Input> {
BasicBlock getAPredecessor(SuccessorType t) { result.getASuccessor(t) = this } BasicBlock getAPredecessor(SuccessorType t) { result.getASuccessor(t) = this }
/** Gets the control flow node at a specific (zero-indexed) position in this basic block. */ /** Gets the control flow node at a specific (zero-indexed) position in this basic block. */
cached
Node getNode(int pos) { bbIndex(this.getFirstNode(), result, pos) } Node getNode(int pos) { bbIndex(this.getFirstNode(), result, pos) }
/** Gets a control flow node in this basic block. */ /** Gets a control flow node in this basic block. */
@@ -166,52 +183,6 @@ module Make<InputSig Input> {
cached cached
newtype TBasicBlock = TBasicBlockStart(Node cfn) { startsBB(cfn) } newtype TBasicBlock = TBasicBlockStart(Node cfn) { startsBB(cfn) }
/** Holds if `cfn` starts a new basic block. */
private predicate startsBB(Node cfn) {
not exists(nodeGetAPredecessor(cfn, _)) and exists(nodeGetASuccessor(cfn, _))
or
nodeIsJoin(cfn)
or
nodeIsBranch(nodeGetAPredecessor(cfn, _))
or
// In cases such as
//
// ```rb
// if x or y
// foo
// else
// bar
// ```
//
// we have a CFG that looks like
//
// x --false--> [false] x or y --false--> bar
// \ |
// --true--> y --false--
// \
// --true--> [true] x or y --true--> foo
//
// and we want to ensure that both `foo` and `bar` start a new basic block.
exists(nodeGetAPredecessor(cfn, any(SuccessorType s | successorTypeIsCondition(s))))
}
/**
* Holds if `succ` is a control flow successor of `pred` within
* the same basic block.
*/
private predicate intraBBSucc(Node pred, Node succ) {
succ = nodeGetASuccessor(pred, _) and
not startsBB(succ)
}
/**
* Holds if `bbStart` is the first node in a basic block and `cfn` is the
* `i`th node in the same basic block.
*/
cached
predicate bbIndex(Node bbStart, Node cfn, int i) =
shortestDistances(startsBB/1, intraBBSucc/2)(bbStart, cfn, i)
/** /**
* Holds if the first node of basic block `succ` is a control flow * Holds if the first node of basic block `succ` is a control flow
* successor of the last node of basic block `pred`. * successor of the last node of basic block `pred`.
@@ -227,7 +198,7 @@ module Make<InputSig Input> {
private predicate predBB(BasicBlock succ, BasicBlock pred) { succBB(pred, succ) } private predicate predBB(BasicBlock succ, BasicBlock pred) { succBB(pred, succ) }
/** Holds if `bb` is an exit basic block that represents normal exit. */ /** Holds if `bb` is an exit basic block that represents normal exit. */
private predicate exitBB(BasicBlock bb) { nodeIsExit(bb.getANode()) } private predicate exitBB(BasicBlock bb) { nodeIsPostDominanceExit(bb.getANode()) }
/** Holds if `dom` is an immediate post-dominator of `bb`. */ /** Holds if `dom` is an immediate post-dominator of `bb`. */
cached cached
@@ -237,6 +208,51 @@ module Make<InputSig Input> {
private import Cached private import Cached
/** Holds if `cfn` starts a new basic block. */
private predicate startsBB(Node cfn) {
not exists(nodeGetAPredecessor(cfn, _)) and exists(nodeGetASuccessor(cfn, _))
or
nodeIsJoin(cfn)
or
nodeIsBranch(nodeGetAPredecessor(cfn, _))
or
// In cases such as
//
// ```rb
// if x or y
// foo
// else
// bar
// ```
//
// we have a CFG that looks like
//
// x --false--> [false] x or y --false--> bar
// \ |
// --true--> y --false--
// \
// --true--> [true] x or y --true--> foo
//
// and we want to ensure that both `foo` and `bar` start a new basic block.
exists(nodeGetAPredecessor(cfn, any(SuccessorType s | successorTypeIsCondition(s))))
}
/**
* Holds if `succ` is a control flow successor of `pred` within
* the same basic block.
*/
predicate intraBBSucc(Node pred, Node succ) {
succ = nodeGetASuccessor(pred, _) and
not startsBB(succ)
}
/**
* Holds if `bbStart` is the first node in a basic block and `cfn` is the
* `i`th node in the same basic block.
*/
private predicate bbIndex(Node bbStart, Node cfn, int i) =
shortestDistances(startsBB/1, intraBBSucc/2)(bbStart, cfn, i)
/** Holds if `bb` is an entry basic block. */ /** Holds if `bb` is an entry basic block. */
private predicate entryBB(BasicBlock bb) { nodeIsEntry(bb.getFirstNode()) } private predicate entryBB(BasicBlock bb) { nodeIsDominanceEntry(bb.getFirstNode()) }
} }

View File

@@ -83,14 +83,14 @@ signature module InputSig<LocationSig Location> {
* basic block. * basic block.
*/ */
bindingset[node] bindingset[node]
default predicate idOfAstNode(AstNode node, int id) { none() } int idOfAstNode(AstNode node);
/** /**
* Gets an `id` of `scope`. This is used to order the predecessors of a join * Gets an `id` of `scope`. This is used to order the predecessors of a join
* basic block. * basic block.
*/ */
bindingset[scope] bindingset[scope]
default predicate idOfCfgScope(CfgScope scope, int id) { none() } int idOfCfgScope(CfgScope scope);
} }
/** Provides input needed for CFG splitting. */ /** Provides input needed for CFG splitting. */
@@ -1537,7 +1537,7 @@ module MakeWithSplitting<
private class NodeAlias = Node; private class NodeAlias = Node;
private module BasicBlockInputSig implements BB::InputSig { private module BasicBlockInputSig implements BB::InputSig<Location> {
class SuccessorType = Input::SuccessorType; class SuccessorType = Input::SuccessorType;
predicate successorTypeIsCondition = Input::successorTypeIsCondition/1; predicate successorTypeIsCondition = Input::successorTypeIsCondition/1;
@@ -1546,20 +1546,19 @@ module MakeWithSplitting<
Node nodeGetASuccessor(Node node, SuccessorType t) { result = node.getASuccessor(t) } Node nodeGetASuccessor(Node node, SuccessorType t) { result = node.getASuccessor(t) }
predicate nodeIsEntry(Node node) { node instanceof EntryNode } predicate nodeIsDominanceEntry(Node node) { node instanceof EntryNode }
predicate nodeIsExit(Node node) { node.(AnnotatedExitNode).isNormal() } predicate nodeIsPostDominanceExit(Node node) { node.(AnnotatedExitNode).isNormal() }
} }
private module BasicBlockImpl = BB::Make<BasicBlockInputSig>; private module BasicBlockImpl = BB::Make<Location, BasicBlockInputSig>;
/** /**
* A basic block, that is, a maximal straight-line sequence of control flow nodes * A basic block, that is, a maximal straight-line sequence of control flow nodes
* without branches or joins. * without branches or joins.
*/ */
final class BasicBlock extends BasicBlockImpl::BasicBlock { final class BasicBlock extends BasicBlockImpl::BasicBlock {
// We extend `BasicBlockImpl::BasicBlock` to add the `getScope` and // We extend `BasicBlockImpl::BasicBlock` to add the `getScope`.
// `getLocation`.
/** Gets the scope of this basic block. */ /** Gets the scope of this basic block. */
CfgScope getScope() { CfgScope getScope() {
if this instanceof EntryBasicBlock if this instanceof EntryBasicBlock
@@ -1567,9 +1566,6 @@ module MakeWithSplitting<
else result = this.getAPredecessor().getScope() else result = this.getAPredecessor().getScope()
} }
/** Gets the location of this basic block. */
Location getLocation() { result = this.getFirstNode().getLocation() }
/** Gets an immediate successor of this basic block, if any. */ /** Gets an immediate successor of this basic block, if any. */
BasicBlock getASuccessor() { result = super.getASuccessor() } BasicBlock getASuccessor() { result = super.getASuccessor() }
@@ -1678,10 +1674,13 @@ module MakeWithSplitting<
} }
private module JoinBlockPredecessors { private module JoinBlockPredecessors {
int getId(JoinPredecessorBasicBlock jbp) { predicate hasIdAndKind(JoinPredecessorBasicBlock jbp, int id, int kind) {
idOfAstNode(jbp.getFirstNode().(AstCfgNode).getAstNode(), result) id = idOfCfgScope(jbp.(EntryBasicBlock).getScope()) and
kind = 0
or or
idOfCfgScope(jbp.(EntryBasicBlock).getScope(), result) not jbp instanceof EntryBasicBlock and
id = idOfAstNode(jbp.getFirstNode().(AstCfgNode).getAstNode()) and
kind = 1
} }
string getSplitString(JoinPredecessorBasicBlock jbp) { string getSplitString(JoinPredecessorBasicBlock jbp) {
@@ -1699,10 +1698,10 @@ module MakeWithSplitting<
cached cached
JoinPredecessorBasicBlock getJoinBlockPredecessor(JoinBasicBlock jb, int i) { JoinPredecessorBasicBlock getJoinBlockPredecessor(JoinBasicBlock jb, int i) {
result = result =
rank[i + 1](JoinPredecessorBasicBlock jbp | rank[i + 1](JoinPredecessorBasicBlock jbp, int id, int kind |
jbp = jb.getAPredecessor() jbp = jb.getAPredecessor() and JoinBlockPredecessors::hasIdAndKind(jbp, id, kind)
| |
jbp order by JoinBlockPredecessors::getId(jbp), JoinBlockPredecessors::getSplitString(jbp) jbp order by id, kind, JoinBlockPredecessors::getSplitString(jbp)
) )
} }

View File

@@ -106,9 +106,9 @@ module CfgInput implements InputSig<Location> {
result = n.(FuncDeclElement).getAst() result = n.(FuncDeclElement).getAst()
} }
predicate idOfAstNode(AstNode node, int id) { idOf(projectToAst(node), id) } int idOfAstNode(AstNode node) { idOf(projectToAst(node), result) }
predicate idOfCfgScope(CfgScope node, int id) { idOf(node, id) } int idOfCfgScope(CfgScope node) { idOf(node, result) }
} }
private module CfgSplittingInput implements SplittingInputSig<Location, CfgInput> { private module CfgSplittingInput implements SplittingInputSig<Location, CfgInput> {