Skip to content

Commit 6dc599c

Browse files
authored
Merge pull request #17876 from hvitved/dataflow/param-flow-call-ctx
Data flow: Track call contexts in `parameterValueFlow`
2 parents 932ced4 + 3f56fc9 commit 6dc599c

File tree

2 files changed

+95
-41
lines changed

2 files changed

+95
-41
lines changed
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
| A.java:5:12:5:15 | this | A.java:5:12:5:19 | this.foo | A.java:2:7:2:9 | foo |
22
| A.java:21:13:21:13 | a | A.java:21:13:21:22 | getFoo(...) | A.java:2:7:2:9 | foo |
33
| A.java:23:9:23:9 | a | A.java:23:9:23:19 | aGetter(...) | A.java:2:7:2:9 | foo |
4-
| A.java:24:9:24:10 | a2 | A.java:24:9:24:23 | notAGetter(...) | A.java:2:7:2:9 | foo |
54
| A.java:45:12:45:38 | maybeIdWrap(...) | A.java:45:12:45:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo |
65
| A.java:49:12:49:38 | maybeIdWrap(...) | A.java:49:12:49:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo |

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

Lines changed: 95 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,8 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
678678

679679
class CcNoCall = CallContextNoCall;
680680

681+
class CcReturn = CallContextReturn;
682+
681683
Cc ccNone() { result instanceof CallContextAny }
682684

683685
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
@@ -1338,6 +1340,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
13381340
* or summarized as a single read step with before and after types recorded
13391341
* in the `ReadStepTypesOption` parameter.
13401342
* - Types are checked using the `compatibleTypes()` relation.
1343+
* - Call contexts are taken into account.
13411344
*/
13421345
private module Final {
13431346
/**
@@ -1348,8 +1351,12 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
13481351
* If a read step was taken, then `read` captures the `Content`, the
13491352
* container type, and the content type.
13501353
*/
1351-
predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read, string model) {
1352-
parameterValueFlow0(p, node, read, model) and
1354+
predicate parameterValueFlow(
1355+
ParamNode p, Node node, ReadStepTypesOption read, string model,
1356+
CachedCallContextSensitivity::CcNoCall ctx
1357+
) {
1358+
parameterValueFlow0(p, node, read, model, ctx) and
1359+
Cand::cand(p, node) and
13531360
if node instanceof CastingNode
13541361
then
13551362
// normal flow through
@@ -1369,84 +1376,116 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
13691376

13701377
pragma[nomagic]
13711378
private predicate parameterValueFlow0(
1372-
ParamNode p, Node node, ReadStepTypesOption read, string model
1379+
ParamNode p, Node node, ReadStepTypesOption read, string model,
1380+
CachedCallContextSensitivity::CcNoCall ctx
13731381
) {
13741382
p = node and
13751383
Cand::cand(p, _) and
13761384
read = TReadStepTypesNone() and
1377-
model = ""
1385+
model = "" and
1386+
CachedCallContextSensitivity::viableImplNotCallContextReducedReverse(ctx)
13781387
or
13791388
// local flow
13801389
exists(Node mid, string model1, string model2 |
1381-
parameterValueFlow(p, mid, read, model1) and
1390+
parameterValueFlow(p, mid, read, model1, ctx) and
13821391
simpleLocalFlowStep(mid, node, model2) and
13831392
validParameterAliasStep(mid, node) and
13841393
model = mergeModels(model1, model2)
13851394
)
13861395
or
13871396
// read
13881397
exists(Node mid |
1389-
parameterValueFlow(p, mid, TReadStepTypesNone(), model) and
1398+
parameterValueFlow(p, mid, TReadStepTypesNone(), model, ctx) and
13901399
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
13911400
read.getContentType()) and
13921401
Cand::parameterValueFlowReturnCand(p, _, true) and
13931402
compatibleTypesFilter(getNodeDataFlowType(p), read.getContainerType())
13941403
)
13951404
or
1396-
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read, model)
1405+
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read, model, ctx)
1406+
}
1407+
1408+
bindingset[ctx1, ctx2]
1409+
pragma[inline_late]
1410+
private CachedCallContextSensitivity::CcNoCall mergeContexts(
1411+
CachedCallContextSensitivity::CcNoCall ctx1, CachedCallContextSensitivity::CcNoCall ctx2
1412+
) {
1413+
if CachedCallContextSensitivity::viableImplNotCallContextReducedReverse(ctx1)
1414+
then result = ctx2
1415+
else
1416+
if CachedCallContextSensitivity::viableImplNotCallContextReducedReverse(ctx2)
1417+
then result = ctx1
1418+
else
1419+
// check that `ctx1` is compatible with `ctx2` for at least _some_ outer call,
1420+
// and then (arbitrarily) continue with `ctx2`
1421+
exists(DataFlowCall someOuterCall, DataFlowCallable callable |
1422+
someOuterCall =
1423+
CachedCallContextSensitivity::viableImplCallContextReducedReverse(callable, ctx1) and
1424+
someOuterCall =
1425+
CachedCallContextSensitivity::viableImplCallContextReducedReverse(callable, ctx2) and
1426+
result = ctx2
1427+
)
13971428
}
13981429

13991430
pragma[nomagic]
14001431
private predicate parameterValueFlow0_0(
14011432
ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read,
1402-
string model
1433+
string model, CachedCallContextSensitivity::CcNoCall ctx
14031434
) {
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)
1435+
exists(
1436+
ArgNode arg, string model1, string model2, CachedCallContextSensitivity::CcNoCall ctx1,
1437+
CachedCallContextSensitivity::CcNoCall ctx2
1438+
|
1439+
model = mergeModels(model1, model2) and
1440+
ctx = mergeContexts(ctx1, ctx2)
1441+
|
1442+
// flow through: no prior read
1443+
parameterValueFlowArg(p, arg, mustBeNone, model1, ctx1) and
1444+
argumentValueFlowsThrough(arg, read, node, model2, ctx2)
1445+
or
1446+
// flow through: no read inside method
1447+
parameterValueFlowArg(p, arg, read, model1, ctx1) and
1448+
argumentValueFlowsThrough(arg, mustBeNone, node, model2, ctx2)
14161449
)
14171450
}
14181451

14191452
pragma[nomagic]
14201453
private predicate parameterValueFlowArg(
1421-
ParamNode p, ArgNode arg, ReadStepTypesOption read, string model
1454+
ParamNode p, ArgNode arg, ReadStepTypesOption read, string model,
1455+
CachedCallContextSensitivity::CcNoCall ctx
14221456
) {
1423-
parameterValueFlow(p, arg, read, model) and
1457+
parameterValueFlow(p, arg, read, model, ctx) and
14241458
Cand::argumentValueFlowsThroughCand(arg, _, _)
14251459
}
14261460

14271461
pragma[nomagic]
14281462
private predicate argumentValueFlowsThrough0(
1429-
DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read, string model
1463+
DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read, string model,
1464+
CachedCallContextSensitivity::CcNoCall outerCtx
14301465
) {
1431-
exists(ParamNode param | viableParamArg(call, param, arg) |
1432-
parameterValueFlowReturn(param, kind, read, model)
1466+
exists(
1467+
ParamNode param, DataFlowCallable callable,
1468+
CachedCallContextSensitivity::CcNoCall innerCtx
1469+
|
1470+
viableParamArg(call, param, arg) and
1471+
parameterValueFlowReturn(param, kind, read, model, innerCtx) and
1472+
callable = nodeGetEnclosingCallable(param) and
1473+
outerCtx = CachedCallContextSensitivity::getCallContextReturn(callable, call)
1474+
|
1475+
CachedCallContextSensitivity::viableImplNotCallContextReducedReverse(innerCtx)
1476+
or
1477+
call =
1478+
CachedCallContextSensitivity::viableImplCallContextReducedReverse(callable, innerCtx)
14331479
)
14341480
}
14351481

1436-
/**
1437-
* Holds if `arg` flows to `out` through a call using only
1438-
* value-preserving steps and possibly a single read step, not taking
1439-
* call contexts into account.
1440-
*
1441-
* If a read step was taken, then `read` captures the `Content`, the
1442-
* container type, and the content type.
1443-
*/
1444-
cached
1445-
predicate argumentValueFlowsThrough(
1446-
ArgNode arg, ReadStepTypesOption read, Node out, string model
1482+
pragma[nomagic]
1483+
private predicate argumentValueFlowsThrough(
1484+
ArgNode arg, ReadStepTypesOption read, Node out, string model,
1485+
CachedCallContextSensitivity::CcNoCall ctx
14471486
) {
14481487
exists(DataFlowCall call, ReturnKind kind |
1449-
argumentValueFlowsThrough0(call, arg, kind, read, model) and
1488+
argumentValueFlowsThrough0(call, arg, kind, read, model, ctx) and
14501489
out = getAnOutNode(call, kind)
14511490
|
14521491
// normal flow through
@@ -1459,6 +1498,21 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
14591498
)
14601499
}
14611500

1501+
/**
1502+
* Holds if `arg` flows to `out` through a call using only
1503+
* value-preserving steps and possibly a single read step, not taking
1504+
* call contexts into account.
1505+
*
1506+
* If a read step was taken, then `read` captures the `Content`, the
1507+
* container type, and the content type.
1508+
*/
1509+
cached
1510+
predicate argumentValueFlowsThrough(
1511+
ArgNode arg, ReadStepTypesOption read, Node out, string model
1512+
) {
1513+
argumentValueFlowsThrough(arg, read, out, model, _)
1514+
}
1515+
14621516
/**
14631517
* Holds if `arg` flows to `out` through a call using only
14641518
* value-preserving steps and a single read step, not taking call
@@ -1479,10 +1533,11 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
14791533
* container type, and the content type.
14801534
*/
14811535
private predicate parameterValueFlowReturn(
1482-
ParamNode p, ReturnKind kind, ReadStepTypesOption read, string model
1536+
ParamNode p, ReturnKind kind, ReadStepTypesOption read, string model,
1537+
CachedCallContextSensitivity::CcNoCall ctx
14831538
) {
14841539
exists(ReturnNode ret |
1485-
parameterValueFlow(p, ret, read, model) and
1540+
parameterValueFlow(p, ret, read, model, ctx) and
14861541
kind = ret.getKind()
14871542
)
14881543
}
@@ -1498,7 +1553,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
14981553
* node `n`, in the same callable, using only value-preserving steps.
14991554
*/
15001555
private predicate parameterValueFlowsToPreUpdate(ParamNode p, PostUpdateNode n) {
1501-
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone(), _)
1556+
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone(), _, _)
15021557
}
15031558

15041559
cached

0 commit comments

Comments
 (0)