Skip to content

Commit be95d57

Browse files
committed
Data flow: Track call contexts in parameterFlow
1 parent f75615b commit be95d57

File tree

1 file changed

+88
-40
lines changed

1 file changed

+88
-40
lines changed

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

Lines changed: 88 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,8 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
628628
override string toString() {
629629
exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")")
630630
}
631+
632+
predicate isReturn(DataFlowCallable c, DataFlowCall call) { this = TReturn(c, call) }
631633
}
632634

633635
pragma[nomagic]
@@ -676,8 +678,12 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
676678
cc = ccSomeCall()
677679
}
678680

681+
class CcAny = CallContextAny;
682+
679683
class CcNoCall = CallContextNoCall;
680684

685+
class CcReturn = CallContextReturn;
686+
681687
Cc ccNone() { result instanceof CallContextAny }
682688

683689
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
@@ -1348,8 +1354,12 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
13481354
* If a read step was taken, then `read` captures the `Content`, the
13491355
* container type, and the content type.
13501356
*/
1351-
predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read, string model) {
1352-
parameterValueFlow0(p, node, read, model) and
1357+
predicate parameterValueFlow(
1358+
ParamNode p, Node node, ReadStepTypesOption read, string model,
1359+
CachedCallContextSensitivity::CcNoCall ctx
1360+
) {
1361+
parameterValueFlow0(p, node, read, model, ctx) and
1362+
Cand::cand(p, node) and
13531363
if node instanceof CastingNode
13541364
then
13551365
// normal flow through
@@ -1369,67 +1379,115 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
13691379

13701380
pragma[nomagic]
13711381
private predicate parameterValueFlow0(
1372-
ParamNode p, Node node, ReadStepTypesOption read, string model
1382+
ParamNode p, Node node, ReadStepTypesOption read, string model,
1383+
CachedCallContextSensitivity::CcNoCall ctx
13731384
) {
13741385
p = node and
13751386
Cand::cand(p, _) and
13761387
read = TReadStepTypesNone() and
1377-
model = ""
1388+
model = "" and
1389+
ctx instanceof CachedCallContextSensitivity::CcAny
13781390
or
13791391
// local flow
13801392
exists(Node mid, string model1, string model2 |
1381-
parameterValueFlow(p, mid, read, model1) and
1393+
parameterValueFlow(p, mid, read, model1, ctx) and
13821394
simpleLocalFlowStep(mid, node, model2) and
13831395
validParameterAliasStep(mid, node) and
13841396
model = mergeModels(model1, model2)
13851397
)
13861398
or
13871399
// read
13881400
exists(Node mid |
1389-
parameterValueFlow(p, mid, TReadStepTypesNone(), model) and
1401+
parameterValueFlow(p, mid, TReadStepTypesNone(), model, ctx) and
13901402
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
13911403
read.getContentType()) and
13921404
Cand::parameterValueFlowReturnCand(p, _, true) and
13931405
compatibleTypesFilter(getNodeDataFlowType(p), read.getContainerType())
13941406
)
13951407
or
1396-
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read, model)
1408+
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read, model, ctx)
13971409
}
13981410

13991411
pragma[nomagic]
14001412
private predicate parameterValueFlow0_0(
14011413
ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read,
1402-
string model
1414+
string model, CachedCallContextSensitivity::CcNoCall ctx
14031415
) {
1404-
// flow through: no prior read
1405-
exists(ArgNode arg, string model1, string model2 |
1406-
parameterValueFlowArg(p, arg, mustBeNone, model1) and
1407-
argumentValueFlowsThrough(arg, read, node, model2) and
1408-
model = mergeModels(model1, model2)
1409-
)
1410-
or
1411-
// flow through: no read inside method
1412-
exists(ArgNode arg, string model1, string model2 |
1413-
parameterValueFlowArg(p, arg, read, model1) and
1414-
argumentValueFlowsThrough(arg, mustBeNone, node, model2) and
1415-
model = mergeModels(model1, model2)
1416+
exists(
1417+
DataFlowCall call, DataFlowCallable callable, ArgNode arg, string model1, string model2,
1418+
CachedCallContextSensitivity::CcNoCall prevCtx
1419+
|
1420+
model = mergeModels(model1, model2) and
1421+
(
1422+
ctx.(CachedCallContextSensitivity::CcReturn).isReturn(callable, call) and
1423+
(
1424+
CachedCallContextSensitivity::viableImplNotCallContextReducedReverse(prevCtx)
1425+
or
1426+
// check that `prevCtx` is compatible with `ctx` for at least some outer call
1427+
exists(DataFlowCall someOuterCall |
1428+
someOuterCall =
1429+
CachedCallContextSensitivity::viableImplCallContextReducedReverse(callable,
1430+
prevCtx) and
1431+
someOuterCall =
1432+
CachedCallContextSensitivity::viableImplCallContextReducedReverse(callable, ctx)
1433+
)
1434+
)
1435+
or
1436+
not exists(CachedCallContextSensitivity::CcReturn ret | ret.isReturn(callable, call)) and
1437+
ctx = prevCtx
1438+
)
1439+
|
1440+
// flow through: no prior read
1441+
parameterValueFlowArg(p, arg, mustBeNone, model1, prevCtx) and
1442+
argumentValueFlowsThrough(call, callable, arg, read, node, model2)
1443+
or
1444+
// flow through: no read inside method
1445+
parameterValueFlowArg(p, arg, read, model1, prevCtx) and
1446+
argumentValueFlowsThrough(call, callable, arg, mustBeNone, node, model2)
14161447
)
14171448
}
14181449

14191450
pragma[nomagic]
14201451
private predicate parameterValueFlowArg(
1421-
ParamNode p, ArgNode arg, ReadStepTypesOption read, string model
1452+
ParamNode p, ArgNode arg, ReadStepTypesOption read, string model,
1453+
CachedCallContextSensitivity::CcNoCall ctx
14221454
) {
1423-
parameterValueFlow(p, arg, read, model) and
1455+
parameterValueFlow(p, arg, read, model, ctx) and
14241456
Cand::argumentValueFlowsThroughCand(arg, _, _)
14251457
}
14261458

14271459
pragma[nomagic]
14281460
private predicate argumentValueFlowsThrough0(
1429-
DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read, string model
1461+
DataFlowCall call, DataFlowCallable callable, ArgNode arg, ReturnKind kind,
1462+
ReadStepTypesOption read, string model
14301463
) {
1431-
exists(ParamNode param | viableParamArg(call, param, arg) |
1432-
parameterValueFlowReturn(param, kind, read, model)
1464+
exists(ParamNode param, CachedCallContextSensitivity::CcNoCall ctx |
1465+
viableParamArg(call, param, arg) and
1466+
parameterValueFlowReturn(param, kind, read, model, ctx) and
1467+
callable = nodeGetEnclosingCallable(param)
1468+
|
1469+
CachedCallContextSensitivity::viableImplNotCallContextReducedReverse(ctx)
1470+
or
1471+
call = CachedCallContextSensitivity::viableImplCallContextReducedReverse(callable, ctx)
1472+
)
1473+
}
1474+
1475+
pragma[nomagic]
1476+
private predicate argumentValueFlowsThrough(
1477+
DataFlowCall call, DataFlowCallable callable, ArgNode arg, ReadStepTypesOption read,
1478+
Node out, string model
1479+
) {
1480+
exists(ReturnKind kind |
1481+
argumentValueFlowsThrough0(call, callable, arg, kind, read, model) and
1482+
out = getAnOutNode(call, kind)
1483+
|
1484+
// normal flow through
1485+
read = TReadStepTypesNone() and
1486+
compatibleTypesFilter(getNodeDataFlowType(arg), getNodeDataFlowType(out))
1487+
or
1488+
// getter
1489+
compatibleTypesFilter(getNodeDataFlowType(arg), read.getContainerType()) and
1490+
compatibleTypesFilter(read.getContentType(), getNodeDataFlowType(out))
14331491
)
14341492
}
14351493

@@ -1445,18 +1503,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
14451503
predicate argumentValueFlowsThrough(
14461504
ArgNode arg, ReadStepTypesOption read, Node out, string model
14471505
) {
1448-
exists(DataFlowCall call, ReturnKind kind |
1449-
argumentValueFlowsThrough0(call, arg, kind, read, model) and
1450-
out = getAnOutNode(call, kind)
1451-
|
1452-
// normal flow through
1453-
read = TReadStepTypesNone() and
1454-
compatibleTypesFilter(getNodeDataFlowType(arg), getNodeDataFlowType(out))
1455-
or
1456-
// getter
1457-
compatibleTypesFilter(getNodeDataFlowType(arg), read.getContainerType()) and
1458-
compatibleTypesFilter(read.getContentType(), getNodeDataFlowType(out))
1459-
)
1506+
argumentValueFlowsThrough(_, _, arg, read, out, model)
14601507
}
14611508

14621509
/**
@@ -1479,10 +1526,11 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
14791526
* container type, and the content type.
14801527
*/
14811528
private predicate parameterValueFlowReturn(
1482-
ParamNode p, ReturnKind kind, ReadStepTypesOption read, string model
1529+
ParamNode p, ReturnKind kind, ReadStepTypesOption read, string model,
1530+
CachedCallContextSensitivity::CcNoCall ctx
14831531
) {
14841532
exists(ReturnNode ret |
1485-
parameterValueFlow(p, ret, read, model) and
1533+
parameterValueFlow(p, ret, read, model, ctx) and
14861534
kind = ret.getKind()
14871535
)
14881536
}
@@ -1498,7 +1546,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
14981546
* node `n`, in the same callable, using only value-preserving steps.
14991547
*/
15001548
private predicate parameterValueFlowsToPreUpdate(ParamNode p, PostUpdateNode n) {
1501-
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone(), _)
1549+
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone(), _, _)
15021550
}
15031551

15041552
cached

0 commit comments

Comments
 (0)