mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Dataflow: Introduce NodeRegions for use in isUnreachableInCall.
This commit is contained in:
@@ -264,7 +264,15 @@ class DataFlowCall extends Expr instanceof Call {
|
||||
Function getEnclosingCallable() { result = this.getEnclosingFunction() }
|
||||
}
|
||||
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation
|
||||
class NodeRegion instanceof Unit {
|
||||
string toString() { result = "NodeRegion" }
|
||||
|
||||
predicate contains(Node n) { none() }
|
||||
|
||||
int totalOrder() { result = 1 }
|
||||
}
|
||||
|
||||
predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call) { none() } // stub implementation
|
||||
|
||||
/**
|
||||
* Holds if access paths with `c` at their head always should be tracked at high
|
||||
|
||||
@@ -1247,16 +1247,30 @@ module IsUnreachableInCall {
|
||||
any(G::IRGuardCondition guard).ensuresLt(left, right, k, block, areEqual)
|
||||
}
|
||||
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) {
|
||||
class NodeRegion instanceof IRBlock {
|
||||
string toString() { result = "NodeRegion" }
|
||||
|
||||
predicate contains(Node n) { this = n.getBasicBlock() }
|
||||
|
||||
int totalOrder() {
|
||||
this =
|
||||
rank[result](IRBlock b, int startline, int startcolumn |
|
||||
b.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
||||
|
|
||||
b order by startline, startcolumn
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate isUnreachableInCall(NodeRegion block, DataFlowCall call) {
|
||||
exists(
|
||||
InstructionDirectParameterNode paramNode, ConstantIntegralTypeArgumentNode arg,
|
||||
IntegerConstantInstruction constant, int k, Operand left, Operand right, IRBlock block
|
||||
IntegerConstantInstruction constant, int k, Operand left, Operand right
|
||||
|
|
||||
// arg flows into `paramNode`
|
||||
DataFlowImplCommon::viableParamArg(call, paramNode, arg) and
|
||||
left = constant.getAUse() and
|
||||
right = valueNumber(paramNode.getInstruction()).getAUse() and
|
||||
block = n.getBasicBlock()
|
||||
right = valueNumber(paramNode.getInstruction()).getAUse()
|
||||
|
|
||||
// and there's a guard condition which ensures that the result of `left == right + k` is `areEqual`
|
||||
exists(boolean areEqual |
|
||||
|
||||
@@ -2380,16 +2380,31 @@ predicate expectsContent(Node n, ContentSet c) {
|
||||
n.asExpr() instanceof SpreadElementExpr and c instanceof ElementContent
|
||||
}
|
||||
|
||||
class NodeRegion instanceof ControlFlow::BasicBlock {
|
||||
string toString() { result = "NodeRegion" }
|
||||
|
||||
predicate contains(Node n) { this = n.getControlFlowNode().getBasicBlock() }
|
||||
|
||||
int totalOrder() {
|
||||
this =
|
||||
rank[result](ControlFlow::BasicBlock b, int startline, int startcolumn |
|
||||
b.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
||||
|
|
||||
b order by startline, startcolumn
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the node `n` is unreachable when the call context is `call`.
|
||||
* Holds if the nodes in `nr` are unreachable when the call context is `call`.
|
||||
*/
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) {
|
||||
predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call) {
|
||||
exists(
|
||||
ExplicitParameterNode paramNode, Guard guard, ControlFlow::SuccessorTypes::BooleanSuccessor bs
|
||||
|
|
||||
viableConstantBooleanParamArg(paramNode, bs.getValue().booleanNot(), call) and
|
||||
paramNode.getSsaDefinition().getARead() = guard and
|
||||
guard.controlsBlock(n.getControlFlowNode().getBasicBlock(), bs, _)
|
||||
guard.controlsBlock(nr, bs, _)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -371,11 +371,26 @@ private ControlFlow::ConditionGuardNode getAFalsifiedGuard(DataFlowCall call) {
|
||||
)
|
||||
}
|
||||
|
||||
class NodeRegion instanceof BasicBlock {
|
||||
string toString() { result = "NodeRegion" }
|
||||
|
||||
predicate contains(Node n) { n.getBasicBlock() = this }
|
||||
|
||||
int totalOrder() {
|
||||
this =
|
||||
rank[result](BasicBlock b, int startline, int startcolumn |
|
||||
b.hasLocationInfo(_, startline, startcolumn, _, _)
|
||||
|
|
||||
b order by startline, startcolumn
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the node `n` is unreachable when the call context is `call`.
|
||||
* Holds if the nodes in `nr` are unreachable when the call context is `call`.
|
||||
*/
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) {
|
||||
getAFalsifiedGuard(call).dominates(n.getBasicBlock())
|
||||
predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call) {
|
||||
getAFalsifiedGuard(call).dominates(nr)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -502,6 +502,18 @@ class SummaryCall extends DataFlowCall, TSummaryCall {
|
||||
override Location getLocation() { result = c.getLocation() }
|
||||
}
|
||||
|
||||
private predicate id(BasicBlock x, BasicBlock y) { x = y }
|
||||
|
||||
private predicate idOf(BasicBlock x, int y) = equivalenceRelation(id/2)(x, y)
|
||||
|
||||
class NodeRegion instanceof BasicBlock {
|
||||
string toString() { result = "NodeRegion" }
|
||||
|
||||
predicate contains(Node n) { n.asExpr().getBasicBlock() = this }
|
||||
|
||||
int totalOrder() { idOf(this, result) }
|
||||
}
|
||||
|
||||
/** Holds if `e` is an expression that always has the same Boolean value `val`. */
|
||||
private predicate constantBooleanExpr(Expr e, boolean val) {
|
||||
e.(CompileTimeConstantExpr).getBooleanValue() = val
|
||||
@@ -522,9 +534,9 @@ private class ConstantBooleanArgumentNode extends ArgumentNode, ExprNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the node `n` is unreachable when the call context is `call`.
|
||||
* Holds if the nodes in `nr` are unreachable when the call context is `call`.
|
||||
*/
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) {
|
||||
predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call) {
|
||||
exists(
|
||||
ExplicitParameterNode paramNode, ConstantBooleanArgumentNode arg, SsaImplicitInit param,
|
||||
Guard guard
|
||||
@@ -537,7 +549,7 @@ predicate isUnreachableInCall(Node n, DataFlowCall call) {
|
||||
param.getAUse() = guard and
|
||||
// which controls `n` with the opposite value of `arg`
|
||||
guard
|
||||
.controls(n.asExpr().getBasicBlock(),
|
||||
.controls(nr,
|
||||
pragma[only_bind_into](pragma[only_bind_out](arg.getBooleanValue()).booleanNot()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1023,13 +1023,21 @@ predicate attributeClearStep(Node n, AttributeContent c) {
|
||||
exists(PostUpdateNode post | post.getPreUpdateNode() = n | attributeStoreStep(_, c, post))
|
||||
}
|
||||
|
||||
class NodeRegion instanceof Unit {
|
||||
string toString() { result = "NodeRegion" }
|
||||
|
||||
predicate contains(Node n) { none() }
|
||||
|
||||
int totalOrder() { result = 1 }
|
||||
}
|
||||
|
||||
//--------
|
||||
// Fancy context-sensitive guards
|
||||
//--------
|
||||
/**
|
||||
* Holds if the node `n` is unreachable when the call context is `call`.
|
||||
* Holds if the nodes in `nr` are unreachable when the call context is `call`.
|
||||
*/
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() }
|
||||
predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call) { none() }
|
||||
|
||||
/**
|
||||
* Holds if access paths with `c` at their head always should be tracked at high
|
||||
|
||||
@@ -2170,10 +2170,18 @@ class DataFlowExpr = CfgNodes::ExprCfgNode;
|
||||
*/
|
||||
predicate forceHighPrecision(Content c) { c instanceof Content::ElementContent }
|
||||
|
||||
class NodeRegion instanceof Unit {
|
||||
string toString() { result = "NodeRegion" }
|
||||
|
||||
predicate contains(Node n) { none() }
|
||||
|
||||
int totalOrder() { result = 1 }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the node `n` is unreachable when the call context is `call`.
|
||||
* Holds if the nodes in `nr` are unreachable when the call context is `call`.
|
||||
*/
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() }
|
||||
predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call) { none() }
|
||||
|
||||
newtype LambdaCallKind =
|
||||
TYieldCallKind() or
|
||||
|
||||
@@ -251,10 +251,18 @@ signature module InputSig<LocationSig Location> {
|
||||
*/
|
||||
predicate expectsContent(Node n, ContentSet c);
|
||||
|
||||
/** A set of `Node`s in a `DataFlowCallable`. */
|
||||
class NodeRegion {
|
||||
/** Holds if this region contains `n`. */
|
||||
predicate contains(Node n);
|
||||
|
||||
int totalOrder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the node `n` is unreachable when the call context is `call`.
|
||||
* Holds if the nodes in `nr` are unreachable when the call context is `call`.
|
||||
*/
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call);
|
||||
predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call);
|
||||
|
||||
default int accessPathLimit() { result = 5 }
|
||||
|
||||
|
||||
@@ -350,7 +350,10 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate isUnreachableInCall1(NodeEx n, LocalCallContextSpecificCall cc) {
|
||||
isUnreachableInCallCached(n.asNode(), cc.getCall())
|
||||
exists(NodeRegion nr |
|
||||
nr.contains(n.asNode()) and
|
||||
isUnreachableInCallCached(nr, cc.getCall())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5245,7 +5248,10 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap,
|
||||
boolean isStoreStep
|
||||
) {
|
||||
not isUnreachableInCallCached(node.asNode(), cc.(CallContextSpecificCall).getCall()) and
|
||||
not exists(NodeRegion nr |
|
||||
nr.contains(node.asNode()) and
|
||||
isUnreachableInCallCached(nr, cc.(CallContextSpecificCall).getCall())
|
||||
) and
|
||||
(
|
||||
localFlowStepEx(mid.getNodeEx(), node, _) and
|
||||
state = mid.getState() and
|
||||
|
||||
@@ -465,10 +465,10 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable callable) {
|
||||
exists(Node n |
|
||||
exists(NodeRegion nr |
|
||||
relevantCallEdgeIn(call, callable) and
|
||||
getNodeEnclosingCallable(n) = callable and
|
||||
isUnreachableInCallCached(n, call)
|
||||
getNodeRegionEnclosingCallable(nr) = callable and
|
||||
isUnreachableInCallCached(nr, call)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -659,7 +659,9 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) }
|
||||
|
||||
cached
|
||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||
predicate isUnreachableInCallCached(NodeRegion nr, DataFlowCall call) {
|
||||
isUnreachableInCall(nr, call)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate outNodeExt(Node n) {
|
||||
@@ -1823,8 +1825,14 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
override predicate relevantFor(DataFlowCallable callable) { relevantLocalCCtx(call, callable) }
|
||||
}
|
||||
|
||||
private DataFlowCallable getNodeRegionEnclosingCallable(NodeRegion nr) {
|
||||
exists(Node n | nr.contains(n) | getNodeEnclosingCallable(n) = result)
|
||||
}
|
||||
|
||||
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCallCached(n, call))
|
||||
exists(NodeRegion nr |
|
||||
getNodeRegionEnclosingCallable(nr) = callable and isUnreachableInCallCached(nr, call)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -187,8 +187,9 @@ module MakeConsistency<
|
||||
}
|
||||
|
||||
query predicate unreachableNodeCCtx(Node n, DataFlowCall call, string msg) {
|
||||
isUnreachableInCall(n, call) and
|
||||
exists(DataFlowCallable c |
|
||||
exists(DataFlowCallable c, NodeRegion nr |
|
||||
isUnreachableInCall(nr, call) and
|
||||
nr.contains(n) and
|
||||
c = nodeGetEnclosingCallable(n) and
|
||||
not viableCallable(call) = c
|
||||
) and
|
||||
|
||||
@@ -1371,10 +1371,18 @@ class DataFlowExpr = Expr;
|
||||
*/
|
||||
predicate forceHighPrecision(Content c) { c instanceof Content::CollectionContent }
|
||||
|
||||
class NodeRegion instanceof Unit {
|
||||
string toString() { result = "NodeRegion" }
|
||||
|
||||
predicate contains(Node n) { none() }
|
||||
|
||||
int totalOrder() { result = 1 }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the node `n` is unreachable when the call context is `call`.
|
||||
* Holds if the nodes in `nr` are unreachable when the call context is `call`.
|
||||
*/
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() }
|
||||
predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call) { none() }
|
||||
|
||||
newtype LambdaCallKind = TLambdaCallKind()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user