Skip to content

Commit d4ce42a

Browse files
authored
Merge pull request github#5416 from hvitved/csharp/rework-summaries
C#: Rework flow summary implementation
2 parents e93b72d + 57fd2e3 commit d4ce42a

32 files changed

+5578
-5569
lines changed

csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Provides a language-independant implementation of static single assignment
2+
* Provides a language-independent implementation of static single assignment
33
* (SSA) form.
44
*/
55

csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Provides a language-independant implementation of static single assignment
2+
* Provides a language-independent implementation of static single assignment
33
* (SSA) form.
44
*/
55

Lines changed: 70 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,181 +1,109 @@
1-
/**
2-
* Provides classes and predicates for definining flow summaries.
3-
*/
1+
/** Provides classes and predicates for defining flow summaries. */
42

53
import csharp
64
private import internal.FlowSummaryImpl as Impl
7-
private import internal.FlowSummarySpecific::Private
8-
private import internal.DataFlowPublic as DataFlowPublic
9-
// import all instances below
10-
private import semmle.code.csharp.dataflow.LibraryTypeDataFlow
11-
private import semmle.code.csharp.frameworks.EntityFramework
5+
private import internal.DataFlowDispatch
126

13-
class SummarizableCallable = Impl::Public::SummarizableCallable;
7+
// import all instances below
8+
private module Summaries {
9+
private import semmle.code.csharp.dataflow.LibraryTypeDataFlow
10+
private import semmle.code.csharp.frameworks.EntityFramework
11+
}
1412

15-
/** An unbound method. */
16-
class SummarizableMethod extends SummarizableCallable, Method { }
13+
class SummaryComponent = Impl::Public::SummaryComponent;
1714

18-
class ContentList = Impl::Public::ContentList;
15+
/** Provides predicates for constructing summary components. */
16+
module SummaryComponent {
17+
import Impl::Public::SummaryComponent
1918

20-
/** Provides predicates for constructing content lists. */
21-
module ContentList {
22-
import Impl::Public::ContentList
19+
/** Gets a summary component that represents a qualifier. */
20+
SummaryComponent qualifier() { result = argument(-1) }
2321

24-
/** Gets the singleton "element content" content list. */
25-
ContentList element() { result = singleton(any(DataFlowPublic::ElementContent c)) }
22+
/** Gets a summary component that represents an element in a collection. */
23+
SummaryComponent element() { result = content(any(DataFlow::ElementContent c)) }
2624

27-
/** Gets a singleton property content list. */
28-
ContentList property(Property p) {
29-
result =
30-
singleton(any(DataFlowPublic::PropertyContent c | c.getProperty() = p.getUnboundDeclaration()))
25+
/** Gets a summary component for property `p`. */
26+
SummaryComponent property(Property p) {
27+
result = content(any(DataFlow::PropertyContent c | c.getProperty() = p.getUnboundDeclaration()))
3128
}
3229

33-
/** Gets a singleton field content list. */
34-
ContentList field(Field f) {
35-
result =
36-
singleton(any(DataFlowPublic::FieldContent c | c.getField() = f.getUnboundDeclaration()))
30+
/** Gets a summary component for field `f`. */
31+
SummaryComponent field(Field f) {
32+
result = content(any(DataFlow::FieldContent c | c.getField() = f.getUnboundDeclaration()))
3733
}
38-
}
39-
40-
class SummaryInput = Impl::Public::SummaryInput;
4134

42-
/** Provides predicates for constructing flow-summary input specifications */
43-
module SummaryInput {
44-
private import semmle.code.csharp.frameworks.system.Collections
35+
/** Gets a summary component that represents the return value of a call. */
36+
SummaryComponent return() { result = return(any(NormalReturnKind rk)) }
4537

4638
/**
47-
* Gets an input specification that specifies the `i`th parameter as
48-
* the input.
39+
* Gets a summary component that represents the return value through the `i`th
40+
* `out` argument of a call.
4941
*/
50-
SummaryInput parameter(int i) { result = TParameterSummaryInput(i) }
51-
52-
private predicate isCollectionType(ValueOrRefType t) {
53-
t.getABaseType*() instanceof SystemCollectionsIEnumerableInterface and
54-
not t instanceof StringType
42+
SummaryComponent outArgument(int i) {
43+
result = return(any(OutReturnKind rk | rk.getPosition() = i))
5544
}
5645

5746
/**
58-
* Gets an input specification that specifies the `i`th parameter as
59-
* the input.
60-
*
61-
* `inputContents` is either empty or a singleton element content list,
62-
* depending on whether the type of the `i`th parameter of `c` is a
63-
* collection type.
47+
* Gets a summary component that represents the return value through the `i`th
48+
* `ref` argument of a call.
6449
*/
65-
SummaryInput parameter(SummarizableCallable c, int i, ContentList inputContents) {
66-
result = parameter(i) and
67-
exists(Parameter p |
68-
p = c.getParameter(i) and
69-
if isCollectionType(p.getType())
70-
then inputContents = ContentList::element()
71-
else inputContents = ContentList::empty()
72-
)
50+
SummaryComponent refArgument(int i) {
51+
result = return(any(RefReturnKind rk | rk.getPosition() = i))
7352
}
7453

75-
/**
76-
* Gets an input specification that specifies the implicit `this` parameter
77-
* as the input.
78-
*/
79-
SummaryInput thisParameter() { result = TParameterSummaryInput(-1) }
80-
81-
/**
82-
* Gets an input specification that specifies output from the delegate at
83-
* parameter `i` as the input.
84-
*/
85-
SummaryInput delegate(int i) { result = TDelegateSummaryInput(i) }
86-
87-
/**
88-
* Gets an input specification that specifies output from the delegate at
89-
* parameter `i` as the input.
90-
*
91-
* `c` must be a compatible callable, that is, a callable where the `i`th
92-
* parameter is a delegate.
93-
*/
94-
SummaryInput delegate(SummarizableCallable c, int i) {
95-
result = delegate(i) and
96-
hasDelegateArgumentPosition(c, i)
54+
/** Gets a summary component that represents a jump to `c`. */
55+
SummaryComponent jump(Callable c) {
56+
result =
57+
return(any(JumpReturnKind jrk |
58+
jrk.getTarget() = c.getUnboundDeclaration() and
59+
jrk.getTargetReturnKind() instanceof NormalReturnKind
60+
))
9761
}
9862
}
9963

100-
class SummaryOutput = Impl::Public::SummaryOutput;
64+
class SummaryComponentStack = Impl::Public::SummaryComponentStack;
10165

102-
/** Provides predicates for constructing flow-summary output specifications. */
103-
module SummaryOutput {
104-
/**
105-
* Gets an output specification that specifies the return value from a call as
106-
* the output.
107-
*/
108-
SummaryOutput return() { result = TReturnSummaryOutput() }
66+
/** Provides predicates for constructing stacks of summary components. */
67+
module SummaryComponentStack {
68+
import Impl::Public::SummaryComponentStack
10969

110-
/**
111-
* Gets an output specification that specifies the `i`th parameter as the
112-
* output.
113-
*/
114-
SummaryOutput parameter(int i) { result = TParameterSummaryOutput(i) }
70+
/** Gets a singleton stack representing a qualifier. */
71+
SummaryComponentStack qualifier() { result = singleton(SummaryComponent::qualifier()) }
11572

116-
/**
117-
* Gets an output specification that specifies the implicit `this` parameter
118-
* as the output.
119-
*/
120-
SummaryOutput thisParameter() { result = TParameterSummaryOutput(-1) }
73+
/** Gets a stack representing an element of `container`. */
74+
SummaryComponentStack elementOf(SummaryComponentStack container) {
75+
result = push(SummaryComponent::element(), container)
76+
}
12177

122-
/**
123-
* Gets an output specification that specifies parameter `j` of the delegate at
124-
* parameter `i` as the output.
125-
*/
126-
SummaryOutput delegate(int i, int j) { result = TDelegateSummaryOutput(i, j) }
78+
/** Gets a stack representing a propery `p` of `object`. */
79+
SummaryComponentStack propertyOf(Property p, SummaryComponentStack object) {
80+
result = push(SummaryComponent::property(p), object)
81+
}
82+
83+
/** Gets a stack representing a field `f` of `object`. */
84+
SummaryComponentStack fieldOf(Field f, SummaryComponentStack object) {
85+
result = push(SummaryComponent::field(f), object)
86+
}
87+
88+
/** Gets a singleton stack representing the return value of a call. */
89+
SummaryComponentStack return() { result = singleton(SummaryComponent::return()) }
12790

12891
/**
129-
* Gets an output specification that specifies parameter `j` of the delegate at
130-
* parameter `i` as the output.
131-
*
132-
* `c` must be a compatible callable, that is, a callable where the `i`th
133-
* parameter is a delegate with a parameter at position `j`.
92+
* Gets a singleton stack representing the return value through the `i`th
93+
* `out` argument of a call.
13494
*/
135-
SummaryOutput delegate(SummarizableCallable c, int i, int j) {
136-
result = TDelegateSummaryOutput(i, j) and
137-
hasDelegateArgumentPosition2(c, i, j)
138-
}
95+
SummaryComponentStack outArgument(int i) { result = singleton(SummaryComponent::outArgument(i)) }
13996

14097
/**
141-
* Gets an output specification that specifies the `output` of `target` as the
142-
* output. That is, data will flow into one callable and out of another callable
143-
* (`target`).
144-
*
145-
* `output` is limited to (this) parameters and ordinary returns.
98+
* Gets a singleton stack representing the return value through the `i`th
99+
* `ref` argument of a call.
146100
*/
147-
SummaryOutput jump(SummarizableCallable target, SummaryOutput output) {
148-
result = TJumpSummaryOutput(target, toReturnKind(output))
149-
}
101+
SummaryComponentStack refArgument(int i) { result = singleton(SummaryComponent::refArgument(i)) }
102+
103+
/** Gets a singleton stack representing a jump to `c`. */
104+
SummaryComponentStack jump(Callable c) { result = singleton(SummaryComponent::jump(c)) }
150105
}
151106

152107
class SummarizedCallable = Impl::Public::SummarizedCallable;
153108

154-
/** Provides a query predicate for outputting a set of relevant flow summaries. */
155-
module TestOutput {
156-
/** A flow summary to include in the `summary/3` query predicate. */
157-
abstract class RelevantSummarizedCallable extends SummarizedCallable { }
158-
159-
/** A query predicate for outputting flow summaries in QL tests. */
160-
query predicate summary(string callable, string flow, boolean preservesValue) {
161-
exists(
162-
RelevantSummarizedCallable c, SummaryInput input, ContentList inputContents,
163-
string inputContentsString, SummaryOutput output, ContentList outputContents,
164-
string outputContentsString
165-
|
166-
callable = c.getQualifiedNameWithTypes() and
167-
Impl::Private::summary(c, input, inputContents, output, outputContents, preservesValue) and
168-
(
169-
if inputContents.length() = 0
170-
then inputContentsString = ""
171-
else inputContentsString = " [" + inputContents + "]"
172-
) and
173-
(
174-
if outputContents.length() = 0
175-
then outputContentsString = ""
176-
else outputContentsString = " [" + outputContents + "]"
177-
) and
178-
flow = input + inputContentsString + " -> " + output + outputContentsString
179-
)
180-
}
181-
}
109+
class RequiredSummaryComponentStack = Impl::Public::RequiredSummaryComponentStack;

0 commit comments

Comments
 (0)