Skip to content

Commit 81ed3e7

Browse files
committed
Dataflow: Add subpaths query predicate.
1 parent 1dc712f commit 81ed3e7

File tree

1 file changed

+88
-2
lines changed

1 file changed

+88
-2
lines changed

java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
33133313
}
33143314

33153315
/** Holds if `n` can reach a sink. */
3316-
private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) }
3316+
private predicate directReach(PathNode n) {
3317+
n instanceof PathNodeSink or directReach(n.getASuccessor())
3318+
}
3319+
3320+
/** Holds if `n` can reach a sink or is used in a subpath. */
3321+
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
33173322

3318-
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
3323+
/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink or is used in a subpath. */
33193324
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) }
33203325

33213326
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3331,6 +3336,8 @@ module PathGraph {
33313336
query predicate nodes(PathNode n, string key, string val) {
33323337
reach(n) and key = "semmle.label" and val = n.toString()
33333338
}
3339+
3340+
query predicate subpaths = Subpaths::subpaths/4;
33343341
}
33353342

33363343
/**
@@ -3622,6 +3629,85 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
36223629
)
36233630
}
36243631

3632+
private module Subpaths {
3633+
/**
3634+
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
3635+
* `kind`, `sc`, `apout`, and `innercc`.
3636+
*/
3637+
pragma[nomagic]
3638+
private predicate subpaths01(
3639+
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
3640+
NodeEx out, AccessPath apout
3641+
) {
3642+
pathThroughCallable(arg, out, _, apout) and
3643+
pathIntoCallable(arg, par, _, innercc, sc, _) and
3644+
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
3645+
}
3646+
3647+
/**
3648+
* Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
3649+
* `kind`, `sc`, `apout`, and `innercc`.
3650+
*/
3651+
pragma[nomagic]
3652+
private predicate subpaths02(
3653+
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
3654+
NodeEx out, AccessPath apout
3655+
) {
3656+
subpaths01(arg, par, sc, innercc, kind, out, apout) and
3657+
out.asNode() = kind.getAnOutNode(_)
3658+
}
3659+
3660+
pragma[nomagic]
3661+
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
3662+
3663+
/**
3664+
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
3665+
*/
3666+
pragma[nomagic]
3667+
private predicate subpaths03(
3668+
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, AccessPath apout
3669+
) {
3670+
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
3671+
subpaths02(arg, par, sc, innercc, kind, out, apout) and
3672+
ret.getNodeEx() = retnode and
3673+
kind = retnode.getKind() and
3674+
innercc = ret.getCallContext() and
3675+
sc = ret.getSummaryCtx() and
3676+
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
3677+
apout = ret.getAp()
3678+
)
3679+
}
3680+
3681+
/**
3682+
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
3683+
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
3684+
* `ret -> out` is summarized as the edge `arg -> out`.
3685+
*/
3686+
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
3687+
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
3688+
arg.getASuccessor() = par and
3689+
arg.getASuccessor() = out and
3690+
subpaths03(arg, p, ret, o, apout) and
3691+
par.getNodeEx() = p and
3692+
out.getNodeEx() = o and
3693+
out.getAp() = apout
3694+
)
3695+
}
3696+
3697+
/**
3698+
* Holds if `n` can reach `ret` in a summarized subpath.
3699+
*/
3700+
predicate retReach(PathNode n) {
3701+
subpaths(_, _, n, _)
3702+
or
3703+
exists(PathNode mid |
3704+
retReach(mid) and
3705+
n.getASuccessor() = mid and
3706+
not subpaths(_, mid, _, _)
3707+
)
3708+
}
3709+
}
3710+
36253711
/**
36263712
* Holds if data can flow (inter-procedurally) from `source` to `sink`.
36273713
*

0 commit comments

Comments
 (0)