Skip to content

Commit e5eed23

Browse files
committed
Data flow: Track call contexts in parameterFlow
1 parent 6a3e34c commit e5eed23

File tree

1 file changed

+100
-40
lines changed

1 file changed

+100
-40
lines changed

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

Lines changed: 100 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]
@@ -678,6 +680,8 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
678680

679681
class CcNoCall = CallContextNoCall;
680682

683+
class CcReturn = CallContextReturn;
684+
681685
Cc ccNone() { result instanceof CallContextAny }
682686

683687
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
@@ -1338,6 +1342,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
13381342
* or summarized as a single read step with before and after types recorded
13391343
* in the `ReadStepTypesOption` parameter.
13401344
* - Types are checked using the `compatibleTypes()` relation.
1345+
* - Call contexts are taken into account.
13411346
*/
13421347
private module Final {
13431348
/**
@@ -1348,8 +1353,12 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
13481353
* If a read step was taken, then `read` captures the `Content`, the
13491354
* container type, and the content type.
13501355
*/
1351-
predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read, string model) {
1352-
parameterValueFlow0(p, node, read, model) and
1356+
predicate parameterValueFlow(
1357+
ParamNode p, Node node, ReadStepTypesOption read, string model,
1358+
CachedCallContextSensitivity::CcNoCall ctx
1359+
) {
1360+
parameterValueFlow0(p, node, read, model, ctx) and
1361+
Cand::cand(p, node) and
13531362
if node instanceof CastingNode
13541363
then
13551364
// normal flow through
@@ -1369,67 +1378,128 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
13691378

13701379
pragma[nomagic]
13711380
private predicate parameterValueFlow0(
1372-
ParamNode p, Node node, ReadStepTypesOption read, string model
1381+
ParamNode p, Node node, ReadStepTypesOption read, string model,
1382+
CachedCallContextSensitivity::CcNoCall ctx
13731383
) {
13741384
p = node and
13751385
Cand::cand(p, _) and
13761386
read = TReadStepTypesNone() and
1377-
model = ""
1387+
model = "" and
1388+
CachedCallContextSensitivity::viableImplNotCallContextReducedReverse(ctx)
13781389
or
13791390
// local flow
13801391
exists(Node mid, string model1, string model2 |
1381-
parameterValueFlow(p, mid, read, model1) and
1392+
parameterValueFlow(p, mid, read, model1, ctx) and
13821393
simpleLocalFlowStep(mid, node, model2) and
13831394
validParameterAliasStep(mid, node) and
13841395
model = mergeModels(model1, model2)
13851396
)
13861397
or
13871398
// read
13881399
exists(Node mid |
1389-
parameterValueFlow(p, mid, TReadStepTypesNone(), model) and
1400+
parameterValueFlow(p, mid, TReadStepTypesNone(), model, ctx) and
13901401
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
13911402
read.getContentType()) and
13921403
Cand::parameterValueFlowReturnCand(p, _, true) and
13931404
compatibleTypesFilter(getNodeDataFlowType(p), read.getContainerType())
13941405
)
13951406
or
1396-
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read, model)
1407+
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read, model, ctx)
1408+
}
1409+
1410+
bindingset[ctx1, ctx2]
1411+
pragma[inline_late]
1412+
private CachedCallContextSensitivity::CcNoCall mergeContexts(
1413+
CachedCallContextSensitivity::CcNoCall ctx1, CachedCallContextSensitivity::CcNoCall ctx2
1414+
) {
1415+
if CachedCallContextSensitivity::viableImplNotCallContextReducedReverse(ctx1)
1416+
then result = ctx2
1417+
else
1418+
if CachedCallContextSensitivity::viableImplNotCallContextReducedReverse(ctx2)
1419+
then result = ctx1
1420+
else
1421+
// check that `ctx1` is compatible with `ctx2` for at least _some_ outer call,
1422+
// and then (arbitrarily) continue with `ctx2`
1423+
exists(DataFlowCall someOuterCall, DataFlowCallable callable |
1424+
someOuterCall =
1425+
CachedCallContextSensitivity::viableImplCallContextReducedReverse(callable, ctx1) and
1426+
someOuterCall =
1427+
CachedCallContextSensitivity::viableImplCallContextReducedReverse(callable, ctx2) and
1428+
result = ctx2
1429+
)
13971430
}
13981431

13991432
pragma[nomagic]
14001433
private predicate parameterValueFlow0_0(
14011434
ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read,
1402-
string model
1435+
string model, CachedCallContextSensitivity::CcNoCall ctx
14031436
) {
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)
1437+
exists(
1438+
DataFlowCall call, DataFlowCallable callable, ArgNode arg, string model1, string model2,
1439+
CachedCallContextSensitivity::CcNoCall ctx1, CachedCallContextSensitivity::CcNoCall ctx2
1440+
|
1441+
model = mergeModels(model1, model2) and
1442+
(
1443+
// call may restrict the set of call sites that can be returned to
1444+
ctx2.(CachedCallContextSensitivity::CcReturn).isReturn(callable, call)
1445+
or
1446+
// call does not restrict the set of call sites that can be returned to
1447+
not exists(CachedCallContextSensitivity::CcReturn ret | ret.isReturn(callable, call)) and
1448+
CachedCallContextSensitivity::viableImplNotCallContextReducedReverse(ctx2)
1449+
) and
1450+
ctx = mergeContexts(ctx1, ctx2)
1451+
|
1452+
// flow through: no prior read
1453+
parameterValueFlowArg(p, arg, mustBeNone, model1, ctx1) and
1454+
argumentValueFlowsThrough(call, callable, arg, read, node, model2)
1455+
or
1456+
// flow through: no read inside method
1457+
parameterValueFlowArg(p, arg, read, model1, ctx1) and
1458+
argumentValueFlowsThrough(call, callable, arg, mustBeNone, node, model2)
14161459
)
14171460
}
14181461

14191462
pragma[nomagic]
14201463
private predicate parameterValueFlowArg(
1421-
ParamNode p, ArgNode arg, ReadStepTypesOption read, string model
1464+
ParamNode p, ArgNode arg, ReadStepTypesOption read, string model,
1465+
CachedCallContextSensitivity::CcNoCall ctx
14221466
) {
1423-
parameterValueFlow(p, arg, read, model) and
1467+
parameterValueFlow(p, arg, read, model, ctx) and
14241468
Cand::argumentValueFlowsThroughCand(arg, _, _)
14251469
}
14261470

14271471
pragma[nomagic]
14281472
private predicate argumentValueFlowsThrough0(
1429-
DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read, string model
1473+
DataFlowCall call, DataFlowCallable callable, ArgNode arg, ReturnKind kind,
1474+
ReadStepTypesOption read, string model
14301475
) {
1431-
exists(ParamNode param | viableParamArg(call, param, arg) |
1432-
parameterValueFlowReturn(param, kind, read, model)
1476+
exists(ParamNode param, CachedCallContextSensitivity::CcNoCall ctx |
1477+
viableParamArg(call, param, arg) and
1478+
parameterValueFlowReturn(param, kind, read, model, ctx) and
1479+
callable = nodeGetEnclosingCallable(param)
1480+
|
1481+
CachedCallContextSensitivity::viableImplNotCallContextReducedReverse(ctx)
1482+
or
1483+
call = CachedCallContextSensitivity::viableImplCallContextReducedReverse(callable, ctx)
1484+
)
1485+
}
1486+
1487+
pragma[nomagic]
1488+
private predicate argumentValueFlowsThrough(
1489+
DataFlowCall call, DataFlowCallable callable, ArgNode arg, ReadStepTypesOption read,
1490+
Node out, string model
1491+
) {
1492+
exists(ReturnKind kind |
1493+
argumentValueFlowsThrough0(call, callable, arg, kind, read, model) and
1494+
out = getAnOutNode(call, kind)
1495+
|
1496+
// normal flow through
1497+
read = TReadStepTypesNone() and
1498+
compatibleTypesFilter(getNodeDataFlowType(arg), getNodeDataFlowType(out))
1499+
or
1500+
// getter
1501+
compatibleTypesFilter(getNodeDataFlowType(arg), read.getContainerType()) and
1502+
compatibleTypesFilter(read.getContentType(), getNodeDataFlowType(out))
14331503
)
14341504
}
14351505

@@ -1445,18 +1515,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
14451515
predicate argumentValueFlowsThrough(
14461516
ArgNode arg, ReadStepTypesOption read, Node out, string model
14471517
) {
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-
)
1518+
argumentValueFlowsThrough(_, _, arg, read, out, model)
14601519
}
14611520

14621521
/**
@@ -1479,10 +1538,11 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
14791538
* container type, and the content type.
14801539
*/
14811540
private predicate parameterValueFlowReturn(
1482-
ParamNode p, ReturnKind kind, ReadStepTypesOption read, string model
1541+
ParamNode p, ReturnKind kind, ReadStepTypesOption read, string model,
1542+
CachedCallContextSensitivity::CcNoCall ctx
14831543
) {
14841544
exists(ReturnNode ret |
1485-
parameterValueFlow(p, ret, read, model) and
1545+
parameterValueFlow(p, ret, read, model, ctx) and
14861546
kind = ret.getKind()
14871547
)
14881548
}
@@ -1498,7 +1558,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
14981558
* node `n`, in the same callable, using only value-preserving steps.
14991559
*/
15001560
private predicate parameterValueFlowsToPreUpdate(ParamNode p, PostUpdateNode n) {
1501-
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone(), _)
1561+
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone(), _, _)
15021562
}
15031563

15041564
cached

0 commit comments

Comments
 (0)