Skip to content

Commit de65f02

Browse files
authored
Merge pull request #2167 from aschackmull/java/dataflow-out-of-arg-refactor
Java/C++/C#: Refactor dataflow to simplify return flow.
2 parents 810a046 + 106b8cf commit de65f02

24 files changed

+1468
-2290
lines changed

cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll

Lines changed: 61 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,8 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi
258258
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
259259

260260
pragma[noinline]
261-
private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) {
262-
viableImpl(call) = result.getCallable() and
261+
private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
262+
viableCallable(call) = result.getCallable() and
263263
kind = result.getKind()
264264
}
265265

@@ -313,22 +313,23 @@ private predicate nodeCandFwd1(Node node, Configuration config) {
313313
viableParamArg(_, node, arg)
314314
)
315315
or
316-
// flow out of an argument
317-
exists(PostUpdateNode mid, ParameterNode p |
318-
nodeCandFwd1(mid, config) and
319-
parameterValueFlowsToUpdate(p, mid) and
320-
viableParamArg(_, p, node.(PostUpdateNode).getPreUpdateNode())
321-
)
322-
or
323316
// flow out of a callable
324-
exists(DataFlowCall call, ReturnNode ret, ReturnKind kind |
325-
nodeCandFwd1(ret, config) and
326-
getReturnPosition(ret) = viableReturnPos(call, kind) and
327-
node = getAnOutNode(call, kind)
317+
exists(DataFlowCall call, ReturnPosition pos, ReturnKindExt kind |
318+
nodeCandFwd1ReturnPosition(pos, config) and
319+
pos = viableReturnPos(call, kind) and
320+
node = kind.getAnOutNode(call)
328321
)
329322
)
330323
}
331324

325+
pragma[noinline]
326+
private predicate nodeCandFwd1ReturnPosition(ReturnPosition pos, Configuration config) {
327+
exists(ReturnNodeExt ret |
328+
nodeCandFwd1(ret, config) and
329+
getReturnPosition(ret) = pos
330+
)
331+
}
332+
332333
pragma[nomagic]
333334
private predicate nodeCandFwd1Read(Content f, Node node, Configuration config) {
334335
exists(Node mid |
@@ -403,22 +404,23 @@ private predicate nodeCand1(Node node, Configuration config) {
403404
nodeCand1(param, config)
404405
)
405406
or
406-
// flow out of an argument
407-
exists(PostUpdateNode mid, ParameterNode p |
408-
parameterValueFlowsToUpdate(p, node) and
409-
viableParamArg(_, p, mid.getPreUpdateNode()) and
410-
nodeCand1(mid, config)
411-
)
412-
or
413407
// flow out of a callable
414-
exists(DataFlowCall call, ReturnKind kind, OutNode out |
415-
nodeCand1(out, config) and
416-
getReturnPosition(node) = viableReturnPos(call, kind) and
417-
out = getAnOutNode(call, kind)
408+
exists(ReturnPosition pos |
409+
nodeCand1ReturnPosition(pos, config) and
410+
getReturnPosition(node) = pos
418411
)
419412
)
420413
}
421414

415+
pragma[noinline]
416+
private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) {
417+
exists(DataFlowCall call, ReturnKindExt kind, Node out |
418+
nodeCand1(out, config) and
419+
pos = viableReturnPos(call, kind) and
420+
out = kind.getAnOutNode(call)
421+
)
422+
}
423+
422424
/**
423425
* Holds if `f` is the target of a read in the flow covered by `nodeCand1`.
424426
*/
@@ -565,28 +567,24 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable(
565567
simpleArgumentFlowsThrough(node1, node2, _, config)
566568
}
567569

570+
pragma[noinline]
571+
private ReturnPosition getReturnPosition1(Node node, Configuration config) {
572+
result = getReturnPosition(node) and
573+
nodeCand1(node, config)
574+
}
575+
568576
/**
569577
* Holds if data can flow out of a callable from `node1` to `node2`, either
570578
* through a `ReturnNode` or through an argument that has been mutated, and
571579
* that this step is part of a path from a source to a sink.
572580
*/
573581
private predicate flowOutOfCallable(Node node1, Node node2, Configuration config) {
574-
nodeCand1(node1, unbind(config)) and
575582
nodeCand1(node2, config) and
576583
not outBarrier(node1, config) and
577584
not inBarrier(node2, config) and
578-
(
579-
// flow out of an argument
580-
exists(ParameterNode p |
581-
parameterValueFlowsToUpdate(p, node1) and
582-
viableParamArg(_, p, node2.(PostUpdateNode).getPreUpdateNode())
583-
)
584-
or
585-
// flow out of a callable
586-
exists(DataFlowCall call, ReturnKind kind |
587-
getReturnPosition(node1) = viableReturnPos(call, kind) and
588-
node2 = getAnOutNode(call, kind)
589-
)
585+
exists(DataFlowCall call, ReturnKindExt kind |
586+
getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and
587+
node2 = kind.getAnOutNode(call)
590588
)
591589
}
592590

@@ -1762,8 +1760,6 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat
17621760
or
17631761
exists(Content f, AccessPath ap0 | contentStoreStep(mid, node, ap0, f, cc) and push(ap0, f, ap))
17641762
or
1765-
pathOutOfArgument(mid, node, cc) and ap = mid.getAp()
1766-
or
17671763
pathIntoCallable(mid, node, _, cc, _) and ap = mid.getAp()
17681764
or
17691765
pathOutOfCallable(mid, node, cc) and ap = mid.getAp()
@@ -1797,9 +1793,9 @@ private predicate pathOutOfCallable0(PathNodeMid mid, ReturnPosition pos, CallCo
17971793
not innercc instanceof CallContextCall
17981794
}
17991795

1800-
pragma[noinline]
1796+
pragma[nomagic]
18011797
private predicate pathOutOfCallable1(
1802-
PathNodeMid mid, DataFlowCall call, ReturnKind kind, CallContext cc
1798+
PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc
18031799
) {
18041800
exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc |
18051801
pathOutOfCallable0(mid, pos, innercc) and
@@ -1816,29 +1812,9 @@ private predicate pathOutOfCallable1(
18161812
* is a return from a callable and is recorded by `cc`, if needed.
18171813
*/
18181814
pragma[noinline]
1819-
private predicate pathOutOfCallable(PathNodeMid mid, OutNode out, CallContext cc) {
1820-
exists(ReturnKind kind, DataFlowCall call | pathOutOfCallable1(mid, call, kind, cc) |
1821-
out = getAnOutNode(call, kind)
1822-
)
1823-
}
1824-
1825-
private predicate pathOutOfArgument(PathNodeMid mid, PostUpdateNode node, CallContext cc) {
1826-
exists(
1827-
PostUpdateNode n, ParameterNode p, DataFlowCallable callable, CallContext innercc, int i,
1828-
DataFlowCall call, ArgumentNode arg
1829-
|
1830-
mid.getNode() = n and
1831-
parameterValueFlowsToUpdate(p, n) and
1832-
innercc = mid.getCallContext() and
1833-
p.isParameterOf(callable, i) and
1834-
resolveReturn(innercc, callable, call) and
1835-
node.getPreUpdateNode() = arg and
1836-
arg.argumentOf(call, i) and
1837-
flow(node, unbind(mid.getConfiguration()))
1838-
|
1839-
if reducedViableImplInReturn(callable, call)
1840-
then cc = TReturn(callable, call)
1841-
else cc = TAnyCallContext()
1815+
private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) {
1816+
exists(ReturnKindExt kind, DataFlowCall call | pathOutOfCallable1(mid, call, kind, cc) |
1817+
out = kind.getAnOutNode(call)
18421818
)
18431819
}
18441820

@@ -1900,9 +1876,9 @@ private predicate pathIntoCallable(
19001876
/** Holds if data may flow from `p` to a return of kind `kind`. */
19011877
pragma[nomagic]
19021878
private predicate paramFlowsThrough(
1903-
ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config
1879+
ParameterNode p, ReturnKindExt kind, CallContextCall cc, AccessPathNil apnil, Configuration config
19041880
) {
1905-
exists(PathNodeMid mid, ReturnNode ret |
1881+
exists(PathNodeMid mid, ReturnNodeExt ret |
19061882
mid.getNode() = ret and
19071883
kind = ret.getKind() and
19081884
cc = mid.getCallContext() and
@@ -1917,14 +1893,14 @@ private predicate paramFlowsThrough(
19171893
)
19181894
}
19191895

1920-
pragma[noinline]
1896+
pragma[nomagic]
19211897
private predicate pathThroughCallable0(
1922-
DataFlowCall call, PathNodeMid mid, ReturnKind kind, CallContext cc, AccessPathNil apnil
1898+
DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPathNil apnil
19231899
) {
19241900
exists(ParameterNode p, CallContext innercc |
19251901
pathIntoCallable(mid, p, cc, innercc, call) and
19261902
paramFlowsThrough(p, kind, innercc, apnil, unbind(mid.getConfiguration())) and
1927-
not parameterValueFlowsThrough(p, kind, innercc) and
1903+
not parameterValueFlowsThrough(p, kind.(ValueReturnKind).getKind(), innercc) and
19281904
mid.getAp() instanceof AccessPathNil
19291905
)
19301906
}
@@ -1934,12 +1910,10 @@ private predicate pathThroughCallable0(
19341910
* The context `cc` is restored to its value prior to entering the callable.
19351911
*/
19361912
pragma[noinline]
1937-
private predicate pathThroughCallable(
1938-
PathNodeMid mid, OutNode out, CallContext cc, AccessPathNil apnil
1939-
) {
1940-
exists(DataFlowCall call, ReturnKind kind |
1913+
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPathNil apnil) {
1914+
exists(DataFlowCall call, ReturnKindExt kind |
19411915
pathThroughCallable0(call, mid, kind, cc, apnil) and
1942-
out = getAnOutNode(call, kind)
1916+
out = kind.getAnOutNode(call)
19431917
)
19441918
}
19451919

@@ -1996,16 +1970,10 @@ private module FlowExploration {
19961970
// flow into callable
19971971
viableParamArg(_, node2, node1)
19981972
or
1999-
// flow out of an argument
2000-
exists(ParameterNode p |
2001-
parameterValueFlowsToUpdate(p, node1) and
2002-
viableParamArg(_, p, node2.(PostUpdateNode).getPreUpdateNode())
2003-
)
2004-
or
20051973
// flow out of a callable
2006-
exists(DataFlowCall call, ReturnKind kind |
1974+
exists(DataFlowCall call, ReturnKindExt kind |
20071975
getReturnPosition(node1) = viableReturnPos(call, kind) and
2008-
node2 = getAnOutNode(call, kind)
1976+
node2 = kind.getAnOutNode(call)
20091977
)
20101978
|
20111979
c1 = node1.getEnclosingCallable() and
@@ -2250,8 +2218,6 @@ private module FlowExploration {
22502218
apConsFwd(ap, f, ap0, config)
22512219
)
22522220
or
2253-
partialPathOutOfArgument(mid, node, cc, ap, config)
2254-
or
22552221
partialPathIntoCallable(mid, node, _, cc, _, ap, config)
22562222
or
22572223
partialPathOutOfCallable(mid, node, cc, ap, config)
@@ -2310,7 +2276,7 @@ private module FlowExploration {
23102276

23112277
pragma[noinline]
23122278
private predicate partialPathOutOfCallable1(
2313-
PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc,
2279+
PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc,
23142280
PartialAccessPath ap, Configuration config
23152281
) {
23162282
exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc |
@@ -2324,36 +2290,12 @@ private module FlowExploration {
23242290
}
23252291

23262292
private predicate partialPathOutOfCallable(
2327-
PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config
2293+
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config
23282294
) {
2329-
exists(ReturnKind kind, DataFlowCall call |
2295+
exists(ReturnKindExt kind, DataFlowCall call |
23302296
partialPathOutOfCallable1(mid, call, kind, cc, ap, config)
23312297
|
2332-
out = getAnOutNode(call, kind)
2333-
)
2334-
}
2335-
2336-
private predicate partialPathOutOfArgument(
2337-
PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap,
2338-
Configuration config
2339-
) {
2340-
exists(
2341-
PostUpdateNode n, ParameterNode p, DataFlowCallable callable, CallContext innercc, int i,
2342-
DataFlowCall call, ArgumentNode arg
2343-
|
2344-
mid.getNode() = n and
2345-
parameterValueFlowsToUpdate(p, n) and
2346-
innercc = mid.getCallContext() and
2347-
p.isParameterOf(callable, i) and
2348-
resolveReturn(innercc, callable, call) and
2349-
node.getPreUpdateNode() = arg and
2350-
arg.argumentOf(call, i) and
2351-
ap = mid.getAp() and
2352-
config = mid.getConfiguration()
2353-
|
2354-
if reducedViableImplInReturn(callable, call)
2355-
then cc = TReturn(callable, call)
2356-
else cc = TAnyCallContext()
2298+
out = kind.getAnOutNode(call)
23572299
)
23582300
}
23592301

@@ -2400,10 +2342,10 @@ private module FlowExploration {
24002342

24012343
pragma[nomagic]
24022344
private predicate paramFlowsThroughInPartialPath(
2403-
ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil,
2345+
ParameterNode p, ReturnKindExt kind, CallContextCall cc, PartialAccessPathNil apnil,
24042346
Configuration config
24052347
) {
2406-
exists(PartialPathNodePriv mid, ReturnNode ret |
2348+
exists(PartialPathNodePriv mid, ReturnNodeExt ret |
24072349
mid.getNode() = ret and
24082350
kind = ret.getKind() and
24092351
cc = mid.getCallContext() and
@@ -2420,23 +2362,23 @@ private module FlowExploration {
24202362

24212363
pragma[noinline]
24222364
private predicate partialPathThroughCallable0(
2423-
DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc,
2365+
DataFlowCall call, PartialPathNodePriv mid, ReturnKindExt kind, CallContext cc,
24242366
PartialAccessPathNil apnil, Configuration config
24252367
) {
24262368
exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil |
24272369
partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and
24282370
paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and
2429-
not parameterValueFlowsThrough(p, kind, innercc)
2371+
not parameterValueFlowsThrough(p, kind.(ValueReturnKind).getKind(), innercc)
24302372
)
24312373
}
24322374

24332375
private predicate partialPathThroughCallable(
2434-
PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil,
2376+
PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPathNil apnil,
24352377
Configuration config
24362378
) {
2437-
exists(DataFlowCall call, ReturnKind kind |
2379+
exists(DataFlowCall call, ReturnKindExt kind |
24382380
partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and
2439-
out = getAnOutNode(call, kind)
2381+
out = kind.getAnOutNode(call)
24402382
)
24412383
}
24422384

0 commit comments

Comments
 (0)