Skip to content

Commit 79c6834

Browse files
authored
Merge pull request #16374 from michaelnebel/java/narrowsuperimpl
Java: Improve finding best type for models and lifting.
2 parents e65a62c + 64145cf commit 79c6834

File tree

10 files changed

+209
-91
lines changed

10 files changed

+209
-91
lines changed

csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ private import CaptureModelsSpecific
77
private import CaptureModelsPrinting
88

99
class DataFlowTargetApi extends TargetApiSpecific {
10-
DataFlowTargetApi() { isRelevantForDataFlowModels(this) }
10+
DataFlowTargetApi() { not isUninterestingForDataFlowModels(this) }
1111
}
1212

1313
private module Printing implements PrintingSig {

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

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,18 @@ private predicate isRelevantForModels(CS::Callable api) {
5151
}
5252

5353
/**
54-
* Holds if it is relevant to generate models for `api` based on data flow analysis.
54+
* Holds if it is irrelevant to generate models for `api` based on data flow analysis.
55+
*
56+
* This serves as an extra filter for the `relevant` predicate.
5557
*/
56-
predicate isRelevantForDataFlowModels(CS::Callable api) {
57-
isRelevantForModels(api) and not isHigherOrder(api)
58-
}
58+
predicate isUninterestingForDataFlowModels(CS::Callable api) { isHigherOrder(api) }
5959

6060
/**
61-
* Holds if it is relevant to generate models for `api` based on its type.
61+
* Holds if it is irrelevant to generate models for `api` based on type-based analysis.
62+
*
63+
* This serves as an extra filter for the `relevant` predicate.
6264
*/
63-
predicate isRelevantForTypeBasedFlowModels = isRelevantForModels/1;
65+
predicate isUninterestingForTypeBasedFlowModels(CS::Callable api) { none() }
6466

6567
/**
6668
* A class of callables that are relevant generating summary, source and sinks models for.
@@ -71,7 +73,8 @@ predicate isRelevantForTypeBasedFlowModels = isRelevantForModels/1;
7173
class TargetApiSpecific extends CS::Callable {
7274
TargetApiSpecific() {
7375
this.fromSource() and
74-
this.isUnboundDeclaration()
76+
this.isUnboundDeclaration() and
77+
isRelevantForModels(this)
7578
}
7679
}
7780

csharp/ql/src/utils/modelgenerator/internal/CaptureTypeBasedSummaryModels.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ private module ModelPrinting = PrintingImpl<Printing>;
190190
* on the Theorems for Free approach.
191191
*/
192192
class TypeBasedFlowTargetApi extends Specific::TargetApiSpecific {
193-
TypeBasedFlowTargetApi() { Specific::isRelevantForTypeBasedFlowModels(this) }
193+
TypeBasedFlowTargetApi() { not Specific::isUninterestingForTypeBasedFlowModels(this) }
194194

195195
/**
196196
* Gets the string representation of all type based summaries for `this`

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ private import CaptureModelsSpecific
77
private import CaptureModelsPrinting
88

99
class DataFlowTargetApi extends TargetApiSpecific {
10-
DataFlowTargetApi() { isRelevantForDataFlowModels(this) }
10+
DataFlowTargetApi() { not isUninterestingForDataFlowModels(this) }
1111
}
1212

1313
private module Printing implements PrintingSig {

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

Lines changed: 86 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -24,38 +24,59 @@ 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
/**
51-
* Holds if it is relevant to generate models for `api` based on data flow analysis.
66+
* Holds if it is irrelevant to generate models for `api` based on data flow analysis.
67+
*
68+
* This serves as an extra filter for the `relevant` predicate.
5269
*/
53-
predicate isRelevantForDataFlowModels(Callable api) {
54-
isRelevantForModels(api) and
55-
(not api.getDeclaringType() instanceof J::Interface or exists(api.getBody()))
70+
predicate isUninterestingForDataFlowModels(Callable api) {
71+
api.getDeclaringType() instanceof J::Interface and not exists(api.getBody())
5672
}
5773

58-
predicate isRelevantForTypeBasedFlowModels = isRelevantForModels/1;
74+
/**
75+
* Holds if it is irrelevant to generate models for `api` based on type-based analysis.
76+
*
77+
* This serves as an extra filter for the `relevant` predicate.
78+
*/
79+
predicate isUninterestingForTypeBasedFlowModels(Callable api) { none() }
5980

6081
/**
6182
* A class of Callables that are relevant for generating summary, source and sinks models for.
@@ -64,63 +85,54 @@ predicate isRelevantForTypeBasedFlowModels = isRelevantForModels/1;
6485
* from outside the library itself.
6586
*/
6687
class TargetApiSpecific extends Callable {
88+
private Callable lift;
89+
6790
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)
91+
lift = liftedImpl(this) and
92+
not hasManualModel(lift)
7593
}
7694

7795
/**
78-
* Gets the callable that a model will be lifted to, if any.
96+
* Gets the callable that a model will be lifted to.
7997
*/
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-
}
98+
Callable lift() { result = lift }
8599
}
86100

87-
private string isExtensible(J::RefType ref) {
88-
if ref.isFinal() then result = "false" else result = "true"
89-
}
90-
91-
private string typeAsModel(J::RefType type) {
92-
result =
93-
type.getCompilationUnit().getPackage().getName() + ";" +
94-
type.getErasure().(J::RefType).nestedName()
95-
}
96-
97-
private J::RefType bestTypeForModel(TargetApiSpecific api) {
98-
result = api.lift().getDeclaringType()
101+
private string isExtensible(Callable c) {
102+
if c.getDeclaringType().isFinal() then result = "false" else result = "true"
99103
}
100104

101105
/**
102-
* Returns the appropriate type name for the model. Either the type
103-
* declaring the method or the supertype introducing the method.
106+
* Returns the appropriate type name for the model.
104107
*/
105-
private string typeAsSummaryModel(TargetApiSpecific api) {
106-
result = typeAsModel(bestTypeForModel(api))
108+
private string typeAsModel(Callable c) {
109+
exists(RefType type | type = c.getDeclaringType() |
110+
result =
111+
type.getCompilationUnit().getPackage().getName() + ";" +
112+
type.getErasure().(J::RefType).nestedName()
113+
)
107114
}
108115

109-
private predicate partialModel(TargetApiSpecific api, string type, string name, string parameters) {
110-
type = typeAsSummaryModel(api) and
111-
name = api.getName() and
112-
parameters = ExternalFlow::paramsString(api)
116+
private predicate partialLiftedModel(
117+
TargetApiSpecific api, string type, string extensible, string name, string parameters
118+
) {
119+
exists(Callable c | c = api.lift() |
120+
type = typeAsModel(c) and
121+
extensible = isExtensible(c) and
122+
name = c.getName() and
123+
parameters = ExternalFlow::paramsString(c)
124+
)
113125
}
114126

115127
/**
116128
* Computes the first 6 columns for MaD rows.
117129
*/
118130
string asPartialModel(TargetApiSpecific api) {
119-
exists(string type, string name, string parameters |
120-
partialModel(api, type, name, parameters) and
131+
exists(string type, string extensible, string name, string parameters |
132+
partialLiftedModel(api, type, extensible, name, parameters) and
121133
result =
122134
type + ";" //
123-
+ isExtensible(bestTypeForModel(api)) + ";" //
135+
+ extensible + ";" //
124136
+ name + ";" //
125137
+ parameters + ";" //
126138
+ /* ext + */ ";" //
@@ -132,7 +144,7 @@ string asPartialModel(TargetApiSpecific api) {
132144
*/
133145
string asPartialNeutralModel(TargetApiSpecific api) {
134146
exists(string type, string name, string parameters |
135-
partialModel(api, type, name, parameters) and
147+
partialLiftedModel(api, type, _, name, parameters) and
136148
result =
137149
type + ";" //
138150
+ name + ";" //
@@ -228,6 +240,15 @@ predicate sinkModelSanitizer(DataFlow::Node node) {
228240
)
229241
}
230242

243+
private class ManualNeutralSinkCallable extends Callable {
244+
ManualNeutralSinkCallable() {
245+
this =
246+
any(FlowSummaryImpl::Public::NeutralCallable nc |
247+
nc.hasManualModel() and nc.getKind() = "sink"
248+
).asCallable()
249+
}
250+
}
251+
231252
/**
232253
* Holds if `source` is an api entrypoint relevant for creating sink models.
233254
*/
@@ -236,14 +257,15 @@ predicate apiSource(DataFlow::Node source) {
236257
source.asExpr().(J::FieldAccess).isOwnFieldAccess() or
237258
source instanceof DataFlow::ParameterNode
238259
) 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()))
260+
exists(Callable enclosing | enclosing = source.getEnclosingCallable() |
261+
exists(liftedImpl(enclosing)) and
262+
not enclosing instanceof ManualNeutralSinkCallable and
263+
exists(J::RefType t |
264+
t = enclosing.getDeclaringType().getAnAncestor() and
265+
not t instanceof J::TypeObject and
266+
t.isPublic()
267+
)
268+
)
247269
}
248270

249271
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ private module ModelPrinting = PrintingImpl<Printing>;
296296
* on the Theorems for Free approach.
297297
*/
298298
class TypeBasedFlowTargetApi extends Specific::TargetApiSpecific {
299-
TypeBasedFlowTargetApi() { Specific::isRelevantForTypeBasedFlowModels(this) }
299+
TypeBasedFlowTargetApi() { not Specific::isUninterestingForTypeBasedFlowModels(this) }
300300

301301
/**
302302
* Gets the string representation of all type based summaries for `this`

java/ql/test/utils/modelgenerator/dataflow/p/AbstractImplOfExternalSPI.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55

66
public abstract class AbstractImplOfExternalSPI implements FileFilter {
77

8-
@Override
9-
public boolean accept(File pathname) {
10-
return false;
11-
}
12-
13-
}
8+
// neutral=p;AbstractImplOfExternalSPI;accept;(File);summary;df-generated
9+
@Override
10+
public boolean accept(File pathname) {
11+
return false;
12+
}
13+
}

java/ql/test/utils/modelgenerator/dataflow/p/ImplOfExternalSPI.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66

77
public class ImplOfExternalSPI extends AbstractImplOfExternalSPI {
88

9-
@Override
10-
public boolean accept(File pathname) {
11-
try {
12-
Files.createFile(pathname.toPath());
13-
} catch (IOException e) {
14-
e.printStackTrace();
15-
}
16-
return false;
9+
// sink=p;AbstractImplOfExternalSPI;true;accept;(File);;Argument[0];path-injection;df-generated
10+
// neutral=p;AbstractImplOfExternalSPI;accept;(File);summary;df-generated
11+
@Override
12+
public boolean accept(File pathname) {
13+
try {
14+
Files.createFile(pathname.toPath());
15+
} catch (IOException e) {
16+
e.printStackTrace();
1717
}
18-
19-
}
18+
return false;
19+
}
20+
}

0 commit comments

Comments
 (0)