Skip to content

Commit 1692535

Browse files
committed
Data flow: Cache TNodeEx
1 parent f287216 commit 1692535

File tree

4 files changed

+161
-134
lines changed

4 files changed

+161
-134
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ module ProductFlow {
546546
Flow1::PathGraph::edges(pred1, succ1, _, _) and
547547
exists(ReturnKindExt returnKind |
548548
succ1.getNode() = returnKind.getAnOutNode(call) and
549-
paramReturnNode(_, pred1.asParameterReturnNode(), _, returnKind)
549+
returnKind = getParamReturnPosition(_, pred1.asParameterReturnNode()).getKind()
550550
)
551551
}
552552

@@ -574,7 +574,7 @@ module ProductFlow {
574574
Flow2::PathGraph::edges(pred2, succ2, _, _) and
575575
exists(ReturnKindExt returnKind |
576576
succ2.getNode() = returnKind.getAnOutNode(call) and
577-
paramReturnNode(_, pred2.asParameterReturnNode(), _, returnKind)
577+
returnKind = getParamReturnPosition(_, pred2.asParameterReturnNode()).getKind()
578578
)
579579
}
580580

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

Lines changed: 9 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -164,94 +164,19 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
164164
module Impl<FullStateConfigSig Config> {
165165
private class FlowState = Config::FlowState;
166166

167-
private newtype TNodeEx =
168-
TNodeNormal(Node n) or
169-
TNodeImplicitRead(Node n) { Config::allowImplicitRead(n, _) } or
170-
TParamReturnNode(ParameterNode p, SndLevelScopeOption scope) {
171-
paramReturnNode(_, p, scope, _)
172-
}
173-
174-
private class NodeEx extends TNodeEx {
175-
string toString() {
176-
result = this.asNode().toString()
167+
private class NodeEx extends NodeExImpl {
168+
NodeEx() {
169+
Config::allowImplicitRead(any(Node n | this.isImplicitReadNode(n)), _)
177170
or
178-
exists(Node n | this.isImplicitReadNode(n) | result = n.toString() + " [Ext]")
179-
or
180-
result = this.asParamReturnNode().toString() + " [Return]"
181-
}
182-
183-
Node asNode() { this = TNodeNormal(result) }
184-
185-
/** Gets the corresponding Node if this is a normal node or its post-implicit read node. */
186-
Node asNodeOrImplicitRead() { this = TNodeNormal(result) or this = TNodeImplicitRead(result) }
187-
188-
predicate isImplicitReadNode(Node n) { this = TNodeImplicitRead(n) }
189-
190-
ParameterNode asParamReturnNode() { this = TParamReturnNode(result, _) }
191-
192-
Node projectToNode() {
193-
this = TNodeNormal(result) or
194-
this = TNodeImplicitRead(result) or
195-
this = TParamReturnNode(result, _)
196-
}
197-
198-
pragma[nomagic]
199-
private DataFlowCallable getEnclosingCallable0() {
200-
nodeEnclosingCallable(this.projectToNode(), result)
201-
}
202-
203-
pragma[inline]
204-
DataFlowCallable getEnclosingCallable() {
205-
pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result)
206-
}
207-
208-
pragma[nomagic]
209-
private DataFlowType getDataFlowType0() {
210-
nodeDataFlowType(this.asNode(), result)
211-
or
212-
nodeDataFlowType(this.asParamReturnNode(), result)
213-
}
214-
215-
pragma[inline]
216-
DataFlowType getDataFlowType() {
217-
pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result)
171+
not this.isImplicitReadNode(_)
218172
}
219-
220-
Location getLocation() { result = this.projectToNode().getLocation() }
221-
}
222-
223-
private class ArgNodeEx extends NodeEx {
224-
ArgNodeEx() { this.asNode() instanceof ArgNode }
225-
226-
DataFlowCall getCall() { this.asNode().(ArgNode).argumentOf(result, _) }
227-
}
228-
229-
private class ParamNodeEx extends NodeEx {
230-
ParamNodeEx() { this.asNode() instanceof ParamNode }
231-
232-
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
233-
this.asNode().(ParamNode).isParameterOf(c, pos)
234-
}
235-
236-
ParameterPosition getPosition() { this.isParameterOf(_, result) }
237173
}
238174

239-
/**
240-
* A node from which flow can return to the caller. This is either a regular
241-
* `ReturnNode` or a synthesized node for flow out via a parameter.
242-
*/
243-
private class RetNodeEx extends NodeEx {
244-
private ReturnPosition pos;
175+
private class ArgNodeEx extends NodeEx, ArgNodeExImpl { }
245176

246-
RetNodeEx() {
247-
pos = getValueReturnPosition(this.asNode()) or
248-
pos = getParamReturnPosition(_, this.asParamReturnNode())
249-
}
177+
private class ParamNodeEx extends NodeEx, ParamNodeExImpl { }
250178

251-
ReturnPosition getReturnPosition() { result = pos }
252-
253-
ReturnKindExt getKind() { result = pos.getKind() }
254-
}
179+
private class RetNodeEx extends NodeEx, RetNodeExImpl { }
255180

256181
private module SourceSinkFiltering {
257182
private import codeql.util.AlertFiltering
@@ -428,20 +353,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
428353
* Holds if data can flow in one local step from `node1` to `node2`.
429354
*/
430355
private predicate localFlowStepEx(NodeEx node1, NodeEx node2, string model) {
431-
exists(Node n1, Node n2 |
432-
node1.asNode() = n1 and
433-
node2.asNode() = n2 and
434-
simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2), model) and
435-
stepFilter(node1, node2)
436-
)
437-
or
438-
exists(Node n1, Node n2, SndLevelScopeOption scope |
439-
node1.asNode() = n1 and
440-
node2 = TParamReturnNode(n2, scope) and
441-
paramReturnNode(pragma[only_bind_into](n1), pragma[only_bind_into](n2),
442-
pragma[only_bind_into](scope), _) and
443-
model = ""
444-
)
356+
localFlowStepExImpl(node1, node2, model) and
357+
stepFilter(node1, node2)
445358
}
446359

447360
/**

shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll

Lines changed: 149 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,85 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
850850

851851
class SndLevelScopeOption = SndLevelScopeOption::Option;
852852

853+
final class NodeExImpl extends TNodeEx {
854+
string toString() {
855+
result = this.asNode().toString()
856+
or
857+
exists(Node n | this.isImplicitReadNode(n) | result = n.toString() + " [Ext]")
858+
or
859+
result = this.asParamReturnNode().toString() + " [Return]"
860+
}
861+
862+
Node asNode() { this = TNodeNormal(result) }
863+
864+
/** Gets the corresponding Node if this is a normal node or its post-implicit read node. */
865+
Node asNodeOrImplicitRead() { this = TNodeNormal(result) or this = TNodeImplicitRead(result) }
866+
867+
predicate isImplicitReadNode(Node n) { this = TNodeImplicitRead(n) }
868+
869+
ParameterNode asParamReturnNode() { this = TParamReturnNode(result, _) }
870+
871+
Node projectToNode() {
872+
this = TNodeNormal(result) or
873+
this = TNodeImplicitRead(result) or
874+
this = TParamReturnNode(result, _)
875+
}
876+
877+
pragma[nomagic]
878+
private DataFlowCallable getEnclosingCallable0() {
879+
nodeEnclosingCallable(this.projectToNode(), result)
880+
}
881+
882+
pragma[inline]
883+
DataFlowCallable getEnclosingCallable() {
884+
pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result)
885+
}
886+
887+
pragma[nomagic]
888+
private DataFlowType getDataFlowType0() {
889+
nodeDataFlowType(this.asNode(), result)
890+
or
891+
nodeDataFlowType(this.asParamReturnNode(), result)
892+
}
893+
894+
pragma[inline]
895+
DataFlowType getDataFlowType() {
896+
pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result)
897+
}
898+
899+
Location getLocation() { result = this.projectToNode().getLocation() }
900+
}
901+
902+
final class ArgNodeExImpl extends NodeExImpl {
903+
ArgNodeExImpl() { this.asNode() instanceof ArgNode }
904+
905+
DataFlowCall getCall() { this.asNode().(ArgNode).argumentOf(result, _) }
906+
}
907+
908+
final class ParamNodeExImpl extends NodeExImpl {
909+
ParamNodeExImpl() { this.asNode() instanceof ParamNode }
910+
911+
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
912+
this.asNode().(ParamNode).isParameterOf(c, pos)
913+
}
914+
915+
ParameterPosition getPosition() { this.isParameterOf(_, result) }
916+
}
917+
918+
/**
919+
* A node from which flow can return to the caller. This is either a regular
920+
* `ReturnNode` or a synthesized node for flow out via a parameter.
921+
*/
922+
final class RetNodeExImpl extends NodeExImpl {
923+
private ReturnPosition pos;
924+
925+
RetNodeExImpl() { pos = getReturnPositionEx(this) }
926+
927+
ReturnPosition getReturnPosition() { result = pos }
928+
929+
ReturnKindExt getKind() { result = pos.getKind() }
930+
}
931+
853932
cached
854933
private module Cached {
855934
/**
@@ -927,11 +1006,8 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
9271006
)
9281007
}
9291008

930-
cached
931-
predicate valueReturnNode(ReturnNode n, ReturnKindExt k) { k = TValueReturn(n.getKind()) }
932-
933-
cached
934-
predicate paramReturnNode(
1009+
pragma[nomagic]
1010+
private predicate paramReturnNode(
9351011
PostUpdateNode n, ParamNode p, SndLevelScopeOption scope, ReturnKindExt k
9361012
) {
9371013
exists(ParameterPosition pos |
@@ -1541,6 +1617,20 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
15411617

15421618
class UnreachableSetOption = UnreachableSetOption::Option;
15431619

1620+
pragma[nomagic]
1621+
private predicate hasValueReturnKindIn(ReturnNode ret, ReturnKindExt kind, DataFlowCallable c) {
1622+
c = getNodeEnclosingCallable(ret) and
1623+
kind = TValueReturn(ret.getKind())
1624+
}
1625+
1626+
pragma[nomagic]
1627+
private predicate hasParamReturnKindIn(
1628+
PostUpdateNode n, ParamNode p, ReturnKindExt kind, DataFlowCallable c
1629+
) {
1630+
c = getNodeEnclosingCallable(n) and
1631+
paramReturnNode(n, p, _, kind)
1632+
}
1633+
15441634
cached
15451635
newtype TReturnPosition =
15461636
TReturnPosition0(DataFlowCallable c, ReturnKindExt kind) {
@@ -1549,6 +1639,22 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
15491639
hasParamReturnKindIn(_, _, kind, c)
15501640
}
15511641

1642+
cached
1643+
ReturnPosition getValueReturnPosition(ReturnNode ret) {
1644+
exists(ReturnKindExt kind, DataFlowCallable c |
1645+
hasValueReturnKindIn(ret, kind, c) and
1646+
result = TReturnPosition0(c, kind)
1647+
)
1648+
}
1649+
1650+
cached
1651+
ReturnPosition getParamReturnPosition(PostUpdateNode n, ParamNode p) {
1652+
exists(ReturnKindExt kind, DataFlowCallable c |
1653+
hasParamReturnKindIn(n, p, kind, c) and
1654+
result = TReturnPosition0(c, kind)
1655+
)
1656+
}
1657+
15521658
cached
15531659
newtype TLocalFlowCallContext =
15541660
TAnyLocalCall() or
@@ -1594,6 +1700,44 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
15941700
newtype TApproxAccessPathFrontOption =
15951701
TApproxAccessPathFrontNone() or
15961702
TApproxAccessPathFrontSome(ApproxAccessPathFront apf)
1703+
1704+
cached
1705+
newtype TNodeEx =
1706+
TNodeNormal(Node n) or
1707+
TNodeImplicitRead(Node n) or // will be restricted to nodes with actual implicit reads in `DataFlowImpl.qll`
1708+
TParamReturnNode(ParameterNode p, SndLevelScopeOption scope) {
1709+
paramReturnNode(_, p, scope, _)
1710+
}
1711+
1712+
/**
1713+
* Holds if data can flow in one local step from `node1` to `node2`.
1714+
*/
1715+
cached
1716+
predicate localFlowStepExImpl(NodeExImpl node1, NodeExImpl node2, string model) {
1717+
exists(Node n1, Node n2 |
1718+
node1.asNode() = n1 and
1719+
node2.asNode() = n2 and
1720+
simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2), model)
1721+
)
1722+
or
1723+
exists(Node n1, Node n2, SndLevelScopeOption scope |
1724+
node1.asNode() = n1 and
1725+
node2 = TParamReturnNode(n2, scope) and
1726+
paramReturnNode(pragma[only_bind_into](n1), pragma[only_bind_into](n2),
1727+
pragma[only_bind_into](scope), _) and
1728+
model = ""
1729+
)
1730+
}
1731+
1732+
cached
1733+
ReturnPosition getReturnPositionEx(NodeExImpl ret) {
1734+
result = getValueReturnPosition(ret.asNode())
1735+
or
1736+
exists(ParamNode p |
1737+
ret = TParamReturnNode(p, _) and
1738+
result = getParamReturnPosition(_, p)
1739+
)
1740+
}
15971741
}
15981742

15991743
bindingset[call, tgt]
@@ -2177,36 +2321,6 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
21772321
nodeDataFlowType(pragma[only_bind_out](n), pragma[only_bind_into](result))
21782322
}
21792323

2180-
pragma[nomagic]
2181-
private predicate hasValueReturnKindIn(ReturnNode ret, ReturnKindExt kind, DataFlowCallable c) {
2182-
c = getNodeEnclosingCallable(ret) and
2183-
valueReturnNode(ret, kind)
2184-
}
2185-
2186-
pragma[nomagic]
2187-
private predicate hasParamReturnKindIn(
2188-
PostUpdateNode n, ParamNode p, ReturnKindExt kind, DataFlowCallable c
2189-
) {
2190-
c = getNodeEnclosingCallable(n) and
2191-
paramReturnNode(n, p, _, kind)
2192-
}
2193-
2194-
pragma[nomagic]
2195-
ReturnPosition getValueReturnPosition(ReturnNode ret) {
2196-
exists(ReturnKindExt kind, DataFlowCallable c |
2197-
hasValueReturnKindIn(ret, kind, c) and
2198-
result = TReturnPosition0(c, kind)
2199-
)
2200-
}
2201-
2202-
pragma[nomagic]
2203-
ReturnPosition getParamReturnPosition(PostUpdateNode n, ParamNode p) {
2204-
exists(ReturnKindExt kind, DataFlowCallable c |
2205-
hasParamReturnKindIn(n, p, kind, c) and
2206-
result = TReturnPosition0(c, kind)
2207-
)
2208-
}
2209-
22102324
/** An optional Boolean value. */
22112325
class BooleanOption extends TBooleanOption {
22122326
string toString() {

shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1775,7 +1775,7 @@ module Make<
17751775
exists(ReturnNode ret, ValueReturnKind kind |
17761776
c = "ReturnValue" and
17771777
ret = node.asNode() and
1778-
valueReturnNode(ret, kind) and
1778+
kind.getKind() = ret.getKind() and
17791779
kind.getKind() = getStandardReturnValueKind() and
17801780
mid.asCallable() = getNodeEnclosingCallable(ret)
17811781
)

0 commit comments

Comments
 (0)