Skip to content

Commit d287f0c

Browse files
authored
Merge pull request #21987 from hvitved/type-flow-ranking
Java: Fix performance issue in type flow library
2 parents 01454d7 + f143dad commit d287f0c

5 files changed

Lines changed: 77 additions & 3 deletions

File tree

java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,35 @@ module FlowStepsInput implements UniversalFlow::UniversalFlowInput<Location> {
7272
}
7373
}
7474

75+
private class FlowNodeElement extends Element {
76+
FlowNodeElement() {
77+
this instanceof Field or
78+
this instanceof Expr or
79+
this instanceof Method
80+
}
81+
}
82+
83+
private predicate id(FlowNodeElement x, FlowNodeElement y) { x = y }
84+
85+
private predicate idOf(FlowNodeElement x, int y) = equivalenceRelation(id/2)(x, y)
86+
87+
int getFlowNodeId(FlowNode n) {
88+
n =
89+
rank[result](FlowNode n0, int a, int b |
90+
a = 0 and
91+
idOf(n0.asField(), b)
92+
or
93+
// no case for `n0.asSsa()`; here we rely on the built-in location-based ranking
94+
a = 1 and
95+
idOf(n0.asExpr(), b)
96+
or
97+
a = 2 and
98+
idOf(n0.asMethod(), b)
99+
|
100+
n0 order by a, b
101+
)
102+
}
103+
75104
private SrcCallable viableCallable_v1(Call c) {
76105
result = viableImpl_v1(c)
77106
or
@@ -165,6 +194,8 @@ private module Input implements TypeFlowInput<Location> {
165194

166195
class TypeFlowNode = FlowNode;
167196

197+
predicate getTypeFlowNodeId = FlowStepsInput::getFlowNodeId/1;
198+
168199
predicate isExcludedFromNullAnalysis = FlowStepsInput::isExcludedFromNullAnalysis/1;
169200

170201
class Type = RefType;

java/ql/lib/semmle/code/java/security/ListOfConstantsSanitizer.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ private class EmptyCollectionConstructor extends Constructor {
170170
private module CollectionFlowStepsInput implements UniversalFlow::UniversalFlowInput<Location> {
171171
import FlowStepsInput
172172

173+
predicate getFlowNodeId = FlowStepsInput::getFlowNodeId/1;
174+
173175
/**
174176
* Holds if `n2` is a collection/array/constant whose value(s) are
175177
* determined completely from the range of `n1` nodes.

shared/typeflow/codeql/typeflow/TypeFlow.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ signature module TypeFlowInput<LocationSig Location> {
2929
Location getLocation();
3030
}
3131

32+
/**
33+
* Gets an identifier for node `n`, if any. When no identifier is provided for `n`,
34+
* the library falls back to location-based ranking.
35+
*/
36+
default int getTypeFlowNodeId(TypeFlowNode n) { none() }
37+
3238
/**
3339
* Holds if data can flow from `n1` to `n2` in one step.
3440
*

shared/typeflow/codeql/typeflow/UniversalFlow.qll

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ signature module UniversalFlowInput<LocationSig Location> {
4545
Location getLocation();
4646
}
4747

48+
/**
49+
* Gets an identifier for node `n`, if any. When no identifier is provided for `n`,
50+
* the library falls back to location-based ranking.
51+
*/
52+
default int getFlowNodeId(FlowNode n) { none() }
53+
4854
/**
4955
* Holds if data can flow from `n1` to `n2` in one step.
5056
*
@@ -149,17 +155,44 @@ module Make<LocationSig Location, UniversalFlowInput<Location> I> {
149155
private module RankEdge<Edge E> implements RankedEdge<E::Node> {
150156
private import E
151157

158+
private predicate needsNodeId(FlowNode n) { edge(n, _) }
159+
160+
private int getFlowNodeIdByLoc(FlowNode n) {
161+
n =
162+
rank[result](FlowNode n0, string filePath, int startline, int startcolumn |
163+
needsNodeId(n0) and
164+
not exists(getFlowNodeId(n0)) and
165+
n0.getLocation().hasLocationInfo(filePath, startline, startcolumn, _, _)
166+
|
167+
n0 order by filePath, startline, startcolumn
168+
)
169+
}
170+
171+
private int getFlowNodeIdExt(FlowNode n) {
172+
n =
173+
rank[result](FlowNode n0, int a, int b |
174+
needsNodeId(n0) and
175+
a = 0 and
176+
b = getFlowNodeId(n0)
177+
or
178+
a = 1 and
179+
b = getFlowNodeIdByLoc(n0)
180+
|
181+
n0 order by a, b
182+
)
183+
}
184+
152185
/**
153186
* Holds if `r` is a ranking of the incoming edges `(n1,n2)` to `n2`. The used
154187
* ordering is not necessarily total, so the ranking may have gaps.
155188
*/
156189
private predicate edgeRank1(int r, FlowNode n1, Node n2) {
157190
n1 =
158-
rank[r](FlowNode n, int startline, int startcolumn |
191+
rank[r](FlowNode n, int id |
159192
edge(n, n2) and
160-
n.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
193+
id = getFlowNodeIdExt(n)
161194
|
162-
n order by startline, startcolumn
195+
n order by id
163196
)
164197
}
165198

shared/typeflow/codeql/typeflow/internal/TypeFlowImpl.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ module TypeFlow<LocationSig Location, TypeFlowInput<Location> I> {
1212
private module UfInput implements UniversalFlow::UniversalFlowInput<Location> {
1313
class FlowNode = TypeFlowNode;
1414

15+
predicate getFlowNodeId = I::getTypeFlowNodeId/1;
16+
1517
predicate step = I::step/2;
1618

1719
predicate isNullValue = I::isNullValue/1;

0 commit comments

Comments
 (0)