Skip to content

Commit 28f4dff

Browse files
committed
Python: sync
1 parent b6231e8 commit 28f4dff

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ private module Cached {
1414
ReturnStep() or
1515
StoreStep(TypeTrackerContent content) { basicStoreStep(_, _, content) } or
1616
LoadStep(TypeTrackerContent content) { basicLoadStep(_, _, content) } or
17+
LoadStoreStep(TypeTrackerContent load, TypeTrackerContent store) {
18+
basicLoadStoreStep(_, _, load, store)
19+
} or
20+
WithContent(ContentFilter filter) { basicWithContentStep(_, _, filter) } or
21+
WithoutContent(ContentFilter filter) { basicWithoutContentStep(_, _, filter) } or
1722
JumpStep()
1823

1924
cached
@@ -61,6 +66,14 @@ private module Cached {
6166
or
6267
step = JumpStep() and
6368
result = MkTypeTracker(false, currentContents)
69+
or
70+
exists(ContentFilter filter | result = tt |
71+
step = WithContent(filter) and
72+
currentContents = filter.getAMatchingContent()
73+
or
74+
step = WithoutContent(filter) and
75+
not currentContents = filter.getAMatchingContent()
76+
)
6477
)
6578
or
6679
exists(TypeTrackerContent storeContents, boolean hasCall |
@@ -75,6 +88,16 @@ private module Cached {
7588
tt = noContentTypeTracker(hasCall) and
7689
result = MkTypeTracker(hasCall, storeContents)
7790
)
91+
or
92+
exists(
93+
TypeTrackerContent currentContent, TypeTrackerContent store, TypeTrackerContent load,
94+
boolean hasCall
95+
|
96+
step = LoadStoreStep(pragma[only_bind_into](load), pragma[only_bind_into](store)) and
97+
compatibleContents(pragma[only_bind_into](currentContent), load) and
98+
tt = MkTypeTracker(pragma[only_bind_into](hasCall), currentContent) and
99+
result = MkTypeTracker(pragma[only_bind_out](hasCall), store)
100+
)
78101
}
79102

80103
pragma[nomagic]
@@ -96,6 +119,14 @@ private module Cached {
96119
or
97120
step = JumpStep() and
98121
result = MkTypeBackTracker(false, content)
122+
or
123+
exists(ContentFilter filter | result = tbt |
124+
step = WithContent(filter) and
125+
content = filter.getAMatchingContent()
126+
or
127+
step = WithoutContent(filter) and
128+
not content = filter.getAMatchingContent()
129+
)
99130
)
100131
or
101132
exists(TypeTrackerContent loadContents, boolean hasReturn |
@@ -110,6 +141,16 @@ private module Cached {
110141
tbt = noContentTypeBackTracker(hasReturn) and
111142
result = MkTypeBackTracker(hasReturn, loadContents)
112143
)
144+
or
145+
exists(
146+
TypeTrackerContent currentContent, TypeTrackerContent store, TypeTrackerContent load,
147+
boolean hasCall
148+
|
149+
step = LoadStoreStep(pragma[only_bind_into](load), pragma[only_bind_into](store)) and
150+
compatibleContents(store, pragma[only_bind_into](currentContent)) and
151+
tbt = MkTypeBackTracker(pragma[only_bind_into](hasCall), currentContent) and
152+
result = MkTypeBackTracker(pragma[only_bind_out](hasCall), load)
153+
)
113154
}
114155

115156
/**
@@ -146,6 +187,19 @@ private module Cached {
146187
or
147188
basicLoadStep(nodeFrom, nodeTo, content) and summary = LoadStep(content)
148189
)
190+
or
191+
exists(TypeTrackerContent loadContent, TypeTrackerContent storeContent |
192+
flowsToLoadStoreStep(nodeFrom, nodeTo, loadContent, storeContent) and
193+
summary = LoadStoreStep(loadContent, storeContent)
194+
)
195+
or
196+
exists(ContentFilter filter |
197+
basicWithContentStep(nodeFrom, nodeTo, filter) and
198+
summary = WithContent(filter)
199+
or
200+
basicWithoutContentStep(nodeFrom, nodeTo, filter) and
201+
summary = WithoutContent(filter)
202+
)
149203
}
150204

151205
cached
@@ -190,6 +244,18 @@ private predicate flowsToStoreStep(
190244
exists(Node obj | nodeTo.flowsTo(obj) and basicStoreStep(nodeFrom, obj, content))
191245
}
192246

247+
/**
248+
* Holds if `loadContent` is loaded from `nodeFrom` and written to `storeContent` of `nodeTo`.
249+
*/
250+
predicate flowsToLoadStoreStep(
251+
Node nodeFrom, TypeTrackingNode nodeTo, TypeTrackerContent loadContent,
252+
TypeTrackerContent storeContent
253+
) {
254+
exists(Node obj |
255+
nodeTo.flowsTo(obj) and basicLoadStoreStep(nodeFrom, obj, loadContent, storeContent)
256+
)
257+
}
258+
193259
/**
194260
* INTERNAL: Use `TypeTracker` or `TypeBackTracker` instead.
195261
*
@@ -208,6 +274,11 @@ class StepSummary extends TStepSummary {
208274
or
209275
exists(TypeTrackerContent content | this = LoadStep(content) | result = "load " + content)
210276
or
277+
exists(TypeTrackerContent load, TypeTrackerContent store |
278+
this = LoadStoreStep(load, store) and
279+
result = "load-store " + load + " -> " + store
280+
)
281+
or
211282
this instanceof JumpStep and result = "jump"
212283
}
213284
}

python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ class TypeTrackerContent extends OptionalTypeTrackerContent {
2828
/** Gets the content string representing no value. */
2929
OptionalTypeTrackerContent noContent() { result = "" }
3030

31+
/**
32+
* A label to use for `WithContent` and `WithoutContent` steps, restricting
33+
* which `ContentSet` may pass through. Not currently used in Python.
34+
*/
35+
class ContentFilter extends Unit {
36+
TypeTrackerContent getAMatchingContent() { none() }
37+
}
38+
3139
pragma[inline]
3240
predicate compatibleContents(TypeTrackerContent storeContent, TypeTrackerContent loadContent) {
3341
storeContent = loadContent
@@ -110,6 +118,23 @@ predicate basicLoadStep(Node nodeFrom, Node nodeTo, string content) {
110118
)
111119
}
112120

121+
/**
122+
* Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`.
123+
*/
124+
predicate basicLoadStoreStep(Node nodeFrom, Node nodeTo, string loadContent, string storeContent) {
125+
none()
126+
}
127+
128+
/**
129+
* Holds if type-tracking should step from `nodeFrom` to `nodeTo` but block flow of contents matched by `filter` through here.
130+
*/
131+
predicate basicWithoutContentStep(Node nodeFrom, Node nodeTo, ContentFilter filter) { none() }
132+
133+
/**
134+
* Holds if type-tracking should step from `nodeFrom` to `nodeTo` if inside a content matched by `filter`.
135+
*/
136+
predicate basicWithContentStep(Node nodeFrom, Node nodeTo, ContentFilter filter) { none() }
137+
113138
/**
114139
* A utility class that is equivalent to `boolean` but does not require type joining.
115140
*/

0 commit comments

Comments
 (0)