Skip to content

Commit db56223

Browse files
committed
Python: sync
1 parent 31378ec commit db56223

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
pragma[nomagic]
@@ -35,6 +40,14 @@ private module Cached {
3540
or
3641
step = JumpStep() and
3742
result = MkTypeTracker(false, currentContents)
43+
or
44+
exists(ContentFilter filter | result = tt |
45+
step = WithContent(filter) and
46+
currentContents = filter.getAMatchingContent()
47+
or
48+
step = WithoutContent(filter) and
49+
not currentContents = filter.getAMatchingContent()
50+
)
3851
)
3952
or
4053
exists(TypeTrackerContent storeContents, boolean hasCall |
@@ -49,6 +62,16 @@ private module Cached {
4962
tt = noContentTypeTracker(hasCall) and
5063
result = MkTypeTracker(hasCall, storeContents)
5164
)
65+
or
66+
exists(
67+
TypeTrackerContent currentContent, TypeTrackerContent store, TypeTrackerContent load,
68+
boolean hasCall
69+
|
70+
step = LoadStoreStep(pragma[only_bind_into](load), pragma[only_bind_into](store)) and
71+
compatibleContents(pragma[only_bind_into](currentContent), load) and
72+
tt = MkTypeTracker(pragma[only_bind_into](hasCall), currentContent) and
73+
result = MkTypeTracker(pragma[only_bind_out](hasCall), store)
74+
)
5275
}
5376

5477
pragma[nomagic]
@@ -70,6 +93,14 @@ private module Cached {
7093
or
7194
step = JumpStep() and
7295
result = MkTypeBackTracker(false, content)
96+
or
97+
exists(ContentFilter filter | result = tbt |
98+
step = WithContent(filter) and
99+
content = filter.getAMatchingContent()
100+
or
101+
step = WithoutContent(filter) and
102+
not content = filter.getAMatchingContent()
103+
)
73104
)
74105
or
75106
exists(TypeTrackerContent loadContents, boolean hasReturn |
@@ -84,6 +115,16 @@ private module Cached {
84115
tbt = noContentTypeBackTracker(hasReturn) and
85116
result = MkTypeBackTracker(hasReturn, loadContents)
86117
)
118+
or
119+
exists(
120+
TypeTrackerContent currentContent, TypeTrackerContent store, TypeTrackerContent load,
121+
boolean hasCall
122+
|
123+
step = LoadStoreStep(pragma[only_bind_into](load), pragma[only_bind_into](store)) and
124+
compatibleContents(store, pragma[only_bind_into](currentContent)) and
125+
tbt = MkTypeBackTracker(pragma[only_bind_into](hasCall), currentContent) and
126+
result = MkTypeBackTracker(pragma[only_bind_out](hasCall), load)
127+
)
87128
}
88129

89130
/**
@@ -127,6 +168,11 @@ class StepSummary extends TStepSummary {
127168
or
128169
exists(TypeTrackerContent content | this = LoadStep(content) | result = "load " + content)
129170
or
171+
exists(TypeTrackerContent load, TypeTrackerContent store |
172+
this = LoadStoreStep(load, store) and
173+
result = "load-store " + load + " -> " + store
174+
)
175+
or
130176
this instanceof JumpStep and result = "jump"
131177
}
132178
}
@@ -145,6 +191,19 @@ private predicate smallstepNoCall(Node nodeFrom, TypeTrackingNode nodeTo, StepSu
145191
or
146192
basicLoadStep(nodeFrom, nodeTo, content) and summary = LoadStep(content)
147193
)
194+
or
195+
exists(TypeTrackerContent loadContent, TypeTrackerContent storeContent |
196+
StepSummary::localSourceLoadStoreStep(nodeFrom, nodeTo, loadContent, storeContent) and
197+
summary = LoadStoreStep(loadContent, storeContent)
198+
)
199+
or
200+
exists(ContentFilter filter |
201+
basicWithContentStep(nodeFrom, nodeTo, filter) and
202+
summary = WithContent(filter)
203+
or
204+
basicWithoutContentStep(nodeFrom, nodeTo, filter) and
205+
summary = WithoutContent(filter)
206+
)
148207
}
149208

150209
pragma[noinline]
@@ -216,6 +275,18 @@ module StepSummary {
216275
predicate localSourceStoreStep(Node nodeFrom, TypeTrackingNode nodeTo, TypeTrackerContent content) {
217276
exists(Node obj | nodeTo.flowsTo(obj) and basicStoreStep(nodeFrom, obj, content))
218277
}
278+
279+
/**
280+
* Holds if `loadContent` is loaded from `nodeFrom` and written to `storeContent` of `nodeTo`.
281+
*/
282+
predicate localSourceLoadStoreStep(
283+
Node nodeFrom, TypeTrackingNode nodeTo, TypeTrackerContent loadContent,
284+
TypeTrackerContent storeContent
285+
) {
286+
exists(Node obj |
287+
nodeTo.flowsTo(obj) and basicLoadStoreStep(nodeFrom, obj, loadContent, storeContent)
288+
)
289+
}
219290
}
220291

221292
private newtype TTypeTracker =

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)