Skip to content

Commit bdfd86b

Browse files
committed
C++ WIP: Count return dispatch based on 2nd level scopes.
1 parent a6419dc commit bdfd86b

File tree

4 files changed

+84
-6
lines changed

4 files changed

+84
-6
lines changed

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplSpecific.qll

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ module CppDataFlow implements InputSig {
2121

2222
predicate getAdditionalFlowIntoCallNodeTerm = Private::getAdditionalFlowIntoCallNodeTerm/2;
2323

24+
predicate getSecondLevelScope = Private::getSecondLevelScope/1;
25+
2426
predicate validParameterAliasStep = Private::validParameterAliasStep/2;
2527

2628
predicate mayBenefitFromCallContext = Private::mayBenefitFromCallContext/1;

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

+51
Original file line numberDiff line numberDiff line change
@@ -1259,3 +1259,54 @@ predicate validParameterAliasStep(Node node1, Node node2) {
12591259
)
12601260
)
12611261
}
1262+
1263+
private predicate isTopLevel(Cpp::Stmt s) { any(Function f).getBlock().getAStmt() = s }
1264+
1265+
private Cpp::Stmt getAChainedBranch(Cpp::IfStmt s) {
1266+
result = s.getThen()
1267+
or
1268+
exists(Cpp::Stmt elseBranch | s.getElse() = elseBranch |
1269+
result = getAChainedBranch(elseBranch)
1270+
or
1271+
result = elseBranch and not elseBranch instanceof Cpp::IfStmt
1272+
)
1273+
}
1274+
1275+
private Instruction getInstruction(Node n) {
1276+
result = n.asInstruction() or
1277+
result = n.asOperand().getUse() or
1278+
result = n.(SsaPhiNode).getPhiNode().getBasicBlock().getFirstInstruction() or
1279+
n.(IndirectInstruction).hasInstructionAndIndirectionIndex(result, _) or
1280+
result = getInstruction(n.(PostUpdateNode).getPreUpdateNode())
1281+
}
1282+
1283+
private newtype TDataFlowSecondLevelScope =
1284+
TTopLevelIfBranch(Cpp::Stmt s) {
1285+
exists(Cpp::IfStmt ifstmt | s = getAChainedBranch(ifstmt) and isTopLevel(ifstmt))
1286+
} or
1287+
TTopLevelSwitchCase(Cpp::SwitchCase s) {
1288+
exists(Cpp::SwitchStmt switchstmt | s = switchstmt.getASwitchCase() and isTopLevel(switchstmt))
1289+
}
1290+
1291+
class DataFlowSecondLevelScope extends TDataFlowSecondLevelScope {
1292+
string toString() {
1293+
exists(Cpp::Stmt s | this = TTopLevelIfBranch(s) | result = s.toString()) or
1294+
exists(Cpp::SwitchCase s | this = TTopLevelSwitchCase(s) | result = s.toString())
1295+
}
1296+
1297+
Cpp::Location getLocation() {
1298+
exists(Cpp::Stmt s | this = TTopLevelIfBranch(s) | result = s.getLocation()) or
1299+
exists(Cpp::SwitchCase s | this = TTopLevelSwitchCase(s) | result = s.getLocation())
1300+
}
1301+
1302+
private Cpp::Stmt getAStmt() {
1303+
exists(Cpp::Stmt s | this = TTopLevelIfBranch(s) | result = s) or
1304+
exists(Cpp::SwitchCase s | this = TTopLevelSwitchCase(s) | result = s.getAStmt())
1305+
}
1306+
1307+
Node getANode() {
1308+
getInstruction(result).getAst().(Cpp::ControlFlowNode).getEnclosingStmt().getParentStmt*() = this.getAStmt()
1309+
}
1310+
}
1311+
1312+
DataFlowSecondLevelScope getSecondLevelScope(Node n) { result.getANode() = n }

shared/dataflow/codeql/dataflow/DataFlow.qll

+7
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,13 @@ signature module InputSig {
267267
*/
268268
default int getAdditionalFlowIntoCallNodeTerm(ArgumentNode arg, ParameterNode p) { none() }
269269

270+
class DataFlowSecondLevelScope {
271+
/** Gets a textual representation of this element. */
272+
string toString();
273+
}
274+
275+
default DataFlowSecondLevelScope getSecondLevelScope(Node n) { none() }
276+
270277
bindingset[call, p, arg]
271278
default predicate golangSpecificParamArgFilter(
272279
DataFlowCall call, ParameterNode p, ArgumentNode arg

shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll

+24-6
Original file line numberDiff line numberDiff line change
@@ -1076,28 +1076,46 @@ module MakeImpl<InputSig Lang> {
10761076
result = getAdditionalFlowIntoCallNodeTerm(arg.projectToNode(), p.projectToNode())
10771077
}
10781078

1079+
private module SndLevelScopeOption = Option<DataFlowSecondLevelScope>;
1080+
1081+
private class SndLevelScopeOption = SndLevelScopeOption::Option;
1082+
1083+
pragma[nomagic]
1084+
private SndLevelScopeOption getScope(RetNodeEx ret) {
1085+
result = SndLevelScopeOption::some(getSecondLevelScope(ret.asNode()))
1086+
or
1087+
result instanceof SndLevelScopeOption::None and not exists(getSecondLevelScope(ret.asNode()))
1088+
}
1089+
10791090
pragma[nomagic]
1080-
private predicate returnCallEdge1(DataFlowCallable c, DataFlowCall call, NodeEx out) {
1091+
private predicate returnCallEdge1(
1092+
DataFlowCallable c, SndLevelScopeOption scope, DataFlowCall call, NodeEx out
1093+
) {
10811094
exists(RetNodeEx ret |
1082-
flowOutOfCallNodeCand1(call, ret, _, out) and c = ret.getEnclosingCallable()
1095+
flowOutOfCallNodeCand1(call, ret, _, out) and
1096+
c = ret.getEnclosingCallable() and
1097+
scope = getScope(ret)
10831098
)
10841099
}
10851100

10861101
private int simpleDispatchFanoutOnReturn(DataFlowCall call, NodeEx out) {
1087-
result = strictcount(DataFlowCallable c | returnCallEdge1(c, call, out))
1102+
result =
1103+
strictcount(DataFlowCallable c, SndLevelScopeOption scope |
1104+
returnCallEdge1(c, scope, call, out)
1105+
)
10881106
}
10891107

10901108
private int ctxDispatchFanoutOnReturn(NodeEx out, DataFlowCall ctx) {
10911109
exists(DataFlowCall call, DataFlowCallable c |
10921110
simpleDispatchFanoutOnReturn(call, out) > 1 and
10931111
not Stage1::revFlow(out, false) and
10941112
call.getEnclosingCallable() = c and
1095-
returnCallEdge1(c, ctx, _) and
1113+
returnCallEdge1(c, _, ctx, _) and
10961114
mayBenefitFromCallContextExt(call, _) and
10971115
result =
1098-
count(DataFlowCallable tgt |
1116+
count(DataFlowCallable tgt, SndLevelScopeOption scope |
10991117
tgt = viableImplInCallContextExt(call, ctx) and
1100-
returnCallEdge1(tgt, call, out)
1118+
returnCallEdge1(tgt, scope, call, out)
11011119
)
11021120
)
11031121
}

0 commit comments

Comments
 (0)