Skip to content

Commit e8120af

Browse files
committed
Java: Improve super implementation and ensure that lift produces a result.
1 parent 2a40a2a commit e8120af

File tree

1 file changed

+54
-37
lines changed

1 file changed

+54
-37
lines changed

java/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll

Lines changed: 54 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -24,38 +24,52 @@ class Unit = J::Unit;
2424

2525
class Callable = J::Callable;
2626

27-
private J::Method superImpl(J::Method m) {
28-
result = m.getAnOverride() and
29-
not exists(result.getAnOverride()) and
30-
not m instanceof J::ToStringMethod
31-
}
32-
3327
private predicate isInfrequentlyUsed(J::CompilationUnit cu) {
3428
cu.getPackage().getName().matches("javax.swing%") or
3529
cu.getPackage().getName().matches("java.awt%")
3630
}
3731

32+
private predicate relevant(Callable api) {
33+
api.isPublic() and
34+
api.getDeclaringType().isPublic() and
35+
api.fromSource() and
36+
not isUninterestingForModels(api) and
37+
not isInfrequentlyUsed(api.getCompilationUnit())
38+
}
39+
40+
private J::Method getARelevantOverride(J::Method m) {
41+
result = m.getAnOverride() and
42+
relevant(result) and
43+
// Other exclusions for overrides.
44+
not m instanceof J::ToStringMethod
45+
}
46+
3847
/**
39-
* Holds if it is relevant to generate models for `api`.
48+
* Gets the super implementation of `m` if it is relevant.
49+
* If such a super implementations does not exist, returns `m` if it is relevant.
4050
*/
41-
private predicate isRelevantForModels(Callable api) {
42-
not isUninterestingForModels(api) and
43-
not isInfrequentlyUsed(api.getCompilationUnit()) and
44-
// Disregard all APIs that have a manual model.
45-
not api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()).asCallable() and
46-
not api =
47-
any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel()).asCallable()
51+
private J::Callable liftedImpl(J::Callable m) {
52+
(
53+
result = getARelevantOverride(m)
54+
or
55+
result = m and relevant(m)
56+
) and
57+
not exists(getARelevantOverride(result))
58+
}
59+
60+
private predicate hasManualModel(Callable api) {
61+
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()).asCallable() or
62+
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel()).asCallable()
4863
}
4964

5065
/**
5166
* Holds if it is relevant to generate models for `api` based on data flow analysis.
5267
*/
5368
predicate isRelevantForDataFlowModels(Callable api) {
54-
isRelevantForModels(api) and
5569
(not api.getDeclaringType() instanceof J::Interface or exists(api.getBody()))
5670
}
5771

58-
predicate isRelevantForTypeBasedFlowModels = isRelevantForModels/1;
72+
predicate isRelevantForTypeBasedFlowModels(Callable api) { any() }
5973

6074
/**
6175
* A class of Callables that are relevant for generating summary, source and sinks models for.
@@ -64,24 +78,17 @@ predicate isRelevantForTypeBasedFlowModels = isRelevantForModels/1;
6478
* from outside the library itself.
6579
*/
6680
class TargetApiSpecific extends Callable {
81+
private Callable lift;
82+
6783
TargetApiSpecific() {
68-
this.isPublic() and
69-
this.fromSource() and
70-
(
71-
this.getDeclaringType().isPublic() or
72-
superImpl(this).getDeclaringType().isPublic()
73-
) and
74-
isRelevantForModels(this)
84+
lift = liftedImpl(this) and
85+
not hasManualModel(lift)
7586
}
7687

7788
/**
78-
* Gets the callable that a model will be lifted to, if any.
89+
* Gets the callable that a model will be lifted to.
7990
*/
80-
Callable lift() {
81-
exists(Method m | m = superImpl(this) and m.fromSource() | result = m)
82-
or
83-
not exists(superImpl(this)) and result = this
84-
}
91+
Callable lift() { result = lift }
8592
}
8693

8794
private string isExtensible(J::RefType ref) {
@@ -228,6 +235,15 @@ predicate sinkModelSanitizer(DataFlow::Node node) {
228235
)
229236
}
230237

238+
private class ManualNeutralSinkCallable extends Callable {
239+
ManualNeutralSinkCallable() {
240+
this =
241+
any(FlowSummaryImpl::Public::NeutralCallable nc |
242+
nc.hasManualModel() and nc.getKind() = "sink"
243+
).asCallable()
244+
}
245+
}
246+
231247
/**
232248
* Holds if `source` is an api entrypoint relevant for creating sink models.
233249
*/
@@ -236,14 +252,15 @@ predicate apiSource(DataFlow::Node source) {
236252
source.asExpr().(J::FieldAccess).isOwnFieldAccess() or
237253
source instanceof DataFlow::ParameterNode
238254
) and
239-
source.getEnclosingCallable().isPublic() and
240-
exists(J::RefType t |
241-
t = source.getEnclosingCallable().getDeclaringType().getAnAncestor() and
242-
not t instanceof J::TypeObject and
243-
t.isPublic()
244-
) and
245-
isRelevantForModels(source.getEnclosingCallable()) and
246-
exists(asPartialModel(source.getEnclosingCallable()))
255+
exists(Callable enclosing | enclosing = source.getEnclosingCallable() |
256+
exists(liftedImpl(enclosing)) and
257+
not enclosing instanceof ManualNeutralSinkCallable and
258+
exists(J::RefType t |
259+
t = enclosing.getDeclaringType().getAnAncestor() and
260+
not t instanceof J::TypeObject and
261+
t.isPublic()
262+
)
263+
)
247264
}
248265

249266
/**

0 commit comments

Comments
 (0)