Skip to content

Commit a8feda2

Browse files
committed
C#: Introduce lifting of callables in the model generator.
1 parent 0d397ce commit a8feda2

File tree

2 files changed

+68
-26
lines changed

2 files changed

+68
-26
lines changed

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

Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ private import semmle.code.csharp.commons.Collections as Collections
88
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
99
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
1010
private import semmle.code.csharp.frameworks.system.linq.Expressions
11+
private import semmle.code.csharp.frameworks.System
1112
import semmle.code.csharp.dataflow.internal.ExternalFlow as ExternalFlow
1213
import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
1314
import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
@@ -35,12 +36,23 @@ private predicate irrelevantAccessor(CS::Accessor a) {
3536
}
3637

3738
private predicate isUninterestingForModels(Callable api) {
38-
api.getDeclaringType().getNamespace().getFullName() = "" or
39-
api instanceof CS::ConversionOperator or
40-
api instanceof Util::MainMethod or
41-
api instanceof CS::Destructor or
42-
api instanceof CS::AnonymousFunctionExpr or
43-
api.(CS::Constructor).isParameterless() or
39+
api.getDeclaringType().getNamespace().getFullName() = ""
40+
or
41+
api instanceof CS::ConversionOperator
42+
or
43+
api instanceof Util::MainMethod
44+
or
45+
api instanceof CS::Destructor
46+
or
47+
api instanceof CS::AnonymousFunctionExpr
48+
or
49+
api.(CS::Constructor).isParameterless()
50+
or
51+
exists(Type decl | decl = api.getDeclaringType() |
52+
decl instanceof SystemObjectClass or
53+
decl instanceof SystemValueTypeClass
54+
)
55+
or
4456
// Disregard properties that have both a get and a set accessor,
4557
// which implicitly means auto implemented properties.
4658
irrelevantAccessor(api)
@@ -53,18 +65,26 @@ private predicate relevant(Callable api) {
5365
not isUninterestingForModels(api)
5466
}
5567

56-
private predicate hasManualModel(Callable api) {
57-
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()) or
58-
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel())
68+
private Callable getARelevantOverrideeOrImplementee(Overridable m) {
69+
m.overridesOrImplements(result) and relevant(result)
5970
}
6071

6172
/**
62-
* Holds if it is relevant to generate models for `api`.
73+
* Gets the super implementation of `m` if it is relevant.
74+
* If such a super implementation does not exist, returns `m` if it is relevant.
6375
*/
64-
private predicate isRelevantForModels(Callable api) {
65-
relevant(api) and
66-
// Disregard all APIs that have a manual model.
67-
not hasManualModel(api)
76+
private Callable liftedImpl(Callable api) {
77+
(
78+
result = getARelevantOverrideeOrImplementee(api)
79+
or
80+
result = api and relevant(api)
81+
) and
82+
not exists(getARelevantOverrideeOrImplementee(result))
83+
}
84+
85+
private predicate hasManualModel(Callable api) {
86+
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()) or
87+
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel())
6888
}
6989

7090
/**
@@ -82,19 +102,37 @@ predicate isUninterestingForDataFlowModels(CS::Callable api) { isHigherOrder(api
82102
predicate isUninterestingForTypeBasedFlowModels(CS::Callable api) { none() }
83103

84104
/**
85-
* A class of callables that are relevant generating summary, source and sinks models for.
105+
* A class of callables that are potentially relevant for generating summary, source, sink
106+
* and neutral models.
86107
*
87-
* In the Standard library and 3rd party libraries it the callables that can be called
88-
* from outside the library itself.
108+
* In the Standard library and 3rd party libraries it is the callables (or callables that have a
109+
* super implementation) that can be called from outside the library itself.
89110
*/
90-
class TargetApiSpecific extends CS::Callable {
91-
TargetApiSpecific() { isRelevantForModels(this) }
111+
class TargetApiSpecific extends Callable {
112+
private Callable lift;
113+
114+
TargetApiSpecific() {
115+
lift = liftedImpl(this) and
116+
not hasManualModel(lift)
117+
}
118+
119+
/**
120+
* Gets the callable that a model will be lifted to.
121+
*
122+
* The lifted callable is relevant in terms of model
123+
* generation (this is ensured by `liftedImpl`).
124+
*/
125+
Callable lift() { result = lift }
126+
127+
/**
128+
* Holds if `this` is relevant in terms of model generation.
129+
*/
130+
predicate isRelevant() { relevant(this) }
92131
}
93132

94-
predicate asPartialModel = ExternalFlow::asPartialModel/1;
133+
string asPartialModel(TargetApiSpecific api) { result = ExternalFlow::asPartialModel(api.lift()) }
95134

96-
/** Computes the first 4 columns for neutral CSV rows of `c`. */
97-
predicate asPartialNeutralModel = ExternalFlow::getSignature/1;
135+
string asPartialNeutralModel(TargetApiSpecific api) { result = ExternalFlow::getSignature(api) }
98136

99137
/**
100138
* Holds if `t` is a type that is generally used for bulk data in collection types.
@@ -193,7 +231,8 @@ predicate sinkModelSanitizer(DataFlow::Node node) { none() }
193231
*/
194232
predicate apiSource(DataFlow::Node source) {
195233
(isRelevantMemberAccess(source) or source instanceof DataFlow::ParameterNode) and
196-
isRelevantForModels(source.getEnclosingCallable())
234+
relevant(source.getEnclosingCallable()) and
235+
not hasManualModel(source.getEnclosingCallable())
197236
}
198237

199238
/**

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,13 @@ string captureFlow(DataFlowTargetApi api) {
8181
}
8282

8383
/**
84-
* Gets the neutral model for `api`, if any.
85-
* A neutral model is generated, if there does not exist summary model.
84+
* Gets the neutral summary model for `api`, if any.
85+
* A neutral summary model is generated, if we are not generating
86+
* a summary model that applies to `api` and if it relevant to generate
87+
* a model for `api`.
8688
*/
8789
string captureNoFlow(DataFlowTargetApi api) {
88-
not exists(captureFlow(api)) and
90+
not exists(DataFlowTargetApi api0 | exists(captureFlow(api0)) and api0.lift() = api.lift()) and
91+
api.isRelevant() and
8992
result = ModelPrinting::asNeutralSummaryModel(api)
9093
}

0 commit comments

Comments
 (0)