Skip to content

Commit 7339bd8

Browse files
committed
Java: Add support for synthetic fields in csv rows.
1 parent d34e748 commit 7339bd8

File tree

3 files changed

+72
-36
lines changed

3 files changed

+72
-36
lines changed

java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,48 @@ Element interpretElement(
652652
)
653653
}
654654

655+
private predicate parseField(string c, FieldContent f) {
656+
specSplit(_, c, _) and
657+
exists(string fieldRegex, string package, string className, string fieldName |
658+
fieldRegex = "^Field\\[(.*)\\.([^.]+)\\.([^.]+)\\]$" and
659+
package = c.regexpCapture(fieldRegex, 1) and
660+
className = c.regexpCapture(fieldRegex, 2) and
661+
fieldName = c.regexpCapture(fieldRegex, 3) and
662+
f.getField().hasQualifiedName(package, className, fieldName)
663+
)
664+
}
665+
666+
/** A string representing a synthetic instance field. */
667+
class SyntheticField extends string {
668+
SyntheticField() { parseSynthField(_, this) }
669+
670+
/**
671+
* Gets the type of this field. The default type is `Object`, but this can be
672+
* overridden.
673+
*/
674+
Type getType() { result instanceof TypeObject }
675+
}
676+
677+
private predicate parseSynthField(string c, string f) {
678+
specSplit(_, c, _) and
679+
c.regexpCapture("SyntheticField\\[([.a-zA-Z0-9]+)\\]", 1) = f
680+
}
681+
682+
/** Holds if the specification component parses as a `Content`. */
683+
predicate parseContent(string component, Content content) {
684+
parseField(component, content)
685+
or
686+
parseSynthField(component, content.(SyntheticFieldContent).getField())
687+
or
688+
component = "ArrayElement" and content instanceof ArrayContent
689+
or
690+
component = "Element" and content instanceof CollectionContent
691+
or
692+
component = "MapKey" and content instanceof MapKeyContent
693+
or
694+
component = "MapValue" and content instanceof MapValueContent
695+
}
696+
655697
cached
656698
private module Cached {
657699
/**

java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,14 +162,18 @@ private newtype TContent =
162162
TArrayContent() or
163163
TCollectionContent() or
164164
TMapKeyContent() or
165-
TMapValueContent()
165+
TMapValueContent() or
166+
TSyntheticFieldContent(SyntheticField s)
166167

167168
/**
168169
* A description of the way data may be stored inside an object. Examples
169170
* include instance fields, the contents of a collection object, or the contents
170171
* of an array.
171172
*/
172173
class Content extends TContent {
174+
/** Gets the type of the contained data for the purpose of type pruning. */
175+
abstract DataFlowType getType();
176+
173177
/** Gets a textual representation of this element. */
174178
abstract string toString();
175179

@@ -193,6 +197,8 @@ class FieldContent extends Content, TFieldContent {
193197

194198
InstanceField getField() { result = f }
195199

200+
override DataFlowType getType() { result = getErasedRepr(f.getType()) }
201+
196202
override string toString() { result = f.toString() }
197203

198204
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
@@ -202,24 +208,45 @@ class FieldContent extends Content, TFieldContent {
202208

203209
/** A reference through an array. */
204210
class ArrayContent extends Content, TArrayContent {
211+
override DataFlowType getType() { result instanceof TypeObject }
212+
205213
override string toString() { result = "[]" }
206214
}
207215

208216
/** A reference through the contents of some collection-like container. */
209217
class CollectionContent extends Content, TCollectionContent {
218+
override DataFlowType getType() { result instanceof TypeObject }
219+
210220
override string toString() { result = "<element>" }
211221
}
212222

213223
/** A reference through a map key. */
214224
class MapKeyContent extends Content, TMapKeyContent {
225+
override DataFlowType getType() { result instanceof TypeObject }
226+
215227
override string toString() { result = "<map.key>" }
216228
}
217229

218230
/** A reference through a map value. */
219231
class MapValueContent extends Content, TMapValueContent {
232+
override DataFlowType getType() { result instanceof TypeObject }
233+
220234
override string toString() { result = "<map.value>" }
221235
}
222236

237+
/** A reference through a synthetic instance field. */
238+
class SyntheticFieldContent extends Content, TSyntheticFieldContent {
239+
SyntheticField s;
240+
241+
SyntheticFieldContent() { this = TSyntheticFieldContent(s) }
242+
243+
SyntheticField getField() { result = s }
244+
245+
override DataFlowType getType() { result = getErasedRepr(s.getType()) }
246+
247+
override string toString() { result = s.toString() }
248+
}
249+
223250
/**
224251
* A guard that validates some expression.
225252
*

java/ql/src/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,7 @@ Node summaryNode(SummarizedCallable c, SummaryNodeState state) { result = getSum
2323
DataFlowCall summaryDataFlowCall(Node receiver) { none() }
2424

2525
/** Gets the type of content `c`. */
26-
DataFlowType getContentType(Content c) {
27-
result = getErasedRepr(c.(FieldContent).getField().getType())
28-
or
29-
c instanceof CollectionContent and
30-
result instanceof TypeObject
31-
or
32-
c instanceof ArrayContent and
33-
result instanceof TypeObject
34-
or
35-
c instanceof MapKeyContent and
36-
result instanceof TypeObject
37-
or
38-
c instanceof MapValueContent and
39-
result instanceof TypeObject
40-
}
26+
DataFlowType getContentType(Content c) { result = c.getType() }
4127

4228
/** Gets the return type of kind `rk` for callable `c`. */
4329
DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) {
@@ -70,29 +56,10 @@ predicate summaryElement(DataFlowCallable c, string input, string output, string
7056
)
7157
}
7258

73-
private FieldContent parseField(string c) {
74-
External::specSplit(_, c, _) and
75-
exists(string fieldRegex, string package, string className, string fieldName |
76-
fieldRegex = "^Field\\[(.*)\\.([^.]+)\\.([^.]+)\\]$" and
77-
package = c.regexpCapture(fieldRegex, 1) and
78-
className = c.regexpCapture(fieldRegex, 2) and
79-
fieldName = c.regexpCapture(fieldRegex, 3) and
80-
result.getField().hasQualifiedName(package, className, fieldName)
81-
)
82-
}
83-
8459
/** Gets the summary component for specification component `c`, if any. */
8560
bindingset[c]
8661
SummaryComponent interpretComponentSpecific(string c) {
87-
result = SummaryComponent::content(parseField(c))
88-
or
89-
c = "ArrayElement" and result = SummaryComponent::content(any(ArrayContent c0))
90-
or
91-
c = "Element" and result = SummaryComponent::content(any(CollectionContent c0))
92-
or
93-
c = "MapKey" and result = SummaryComponent::content(any(MapKeyContent c0))
94-
or
95-
c = "MapValue" and result = SummaryComponent::content(any(MapValueContent c0))
62+
exists(Content content | parseContent(c, content) and result = SummaryComponent::content(content))
9663
}
9764

9865
class SourceOrSinkElement = Top;

0 commit comments

Comments
 (0)