Skip to content

Commit 144df9a

Browse files
committed
python: remove explicit dataflow steps
1 parent 8d4f944 commit 144df9a

File tree

5 files changed

+17
-68
lines changed

5 files changed

+17
-68
lines changed

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

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -792,14 +792,10 @@ predicate defaultValueFlowStep(CfgNode nodeFrom, CfgNode nodeTo) {
792792
predicate readStep(Node nodeFrom, Content c, Node nodeTo) {
793793
subscriptReadStep(nodeFrom, c, nodeTo)
794794
or
795-
dictReadStep(nodeFrom, c, nodeTo)
796-
or
797795
iterableUnpackingReadStep(nodeFrom, c, nodeTo)
798796
or
799797
matchReadStep(nodeFrom, c, nodeTo)
800798
or
801-
popReadStep(nodeFrom, c, nodeTo)
802-
or
803799
forReadStep(nodeFrom, c, nodeTo)
804800
or
805801
attributeReadStep(nodeFrom, c, nodeTo)
@@ -832,51 +828,6 @@ predicate subscriptReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
832828
)
833829
}
834830

835-
predicate dictReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
836-
// see
837-
// - https://docs.python.org/3.10/library/stdtypes.html#dict.get
838-
// - https://docs.python.org/3.10/library/stdtypes.html#dict.setdefault
839-
exists(MethodCallNode call |
840-
call.calls(nodeFrom, ["get", "setdefault"]) and
841-
call.getArg(0).asExpr().(StrConst).getText() = c.(DictionaryElementContent).getKey() and
842-
nodeTo = call
843-
)
844-
}
845-
846-
/** Data flows from a sequence to a call to `pop` on the sequence. */
847-
predicate popReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
848-
// set.pop or list.pop
849-
// `s.pop()`
850-
// nodeFrom is `s`, cfg node
851-
// nodeTo is `s.pop()`, cfg node
852-
// c denotes element of list or set
853-
exists(CallNode call, AttrNode a |
854-
call.getFunction() = a and
855-
a.getName() = "pop" and // Should match appropriate call since we tracked a sequence here.
856-
not exists(call.getAnArg()) and
857-
nodeFrom.getNode() = a.getObject() and
858-
nodeTo.getNode() = call and
859-
(
860-
c instanceof ListElementContent
861-
or
862-
c instanceof SetElementContent
863-
)
864-
)
865-
or
866-
// dict.pop
867-
// `d.pop("key")`
868-
// nodeFrom is `d`, cfg node
869-
// nodeTo is `d.pop("key")`, cfg node
870-
// c denotes the key `"key"`
871-
exists(CallNode call, AttrNode a |
872-
call.getFunction() = a and
873-
a.getName() = "pop" and // Should match appropriate call since we tracked a dictionary here.
874-
nodeFrom.getNode() = a.getObject() and
875-
nodeTo.getNode() = call and
876-
c.(DictionaryElementContent).getKey() = call.getArg(0).getNode().(StrConst).getS()
877-
)
878-
}
879-
880831
predicate forReadStep(CfgNode nodeFrom, Content c, Node nodeTo) {
881832
exists(ForTarget target |
882833
nodeFrom.asExpr() = target.getSource() and

python/ql/test/experimental/dataflow/coverage/test.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,23 +123,23 @@ def test_nested_list_display():
123123
# 6.2.6. Set displays
124124
def test_set_display():
125125
x = {SOURCE}
126-
SINK(x.pop()) #$ flow="SOURCE, l:-1 -> x.pop()"
126+
SINK(x.pop()) #$ MISSING:flow="SOURCE, l:-1 -> x.pop()"
127127

128128

129129
def test_set_comprehension():
130130
x = {SOURCE for y in [NONSOURCE]}
131-
SINK(x.pop()) #$ flow="SOURCE, l:-1 -> x.pop()"
131+
SINK(x.pop()) #$ MISSING:flow="SOURCE, l:-1 -> x.pop()"
132132

133133

134134
def test_set_comprehension_flow():
135135
x = {y for y in [SOURCE]}
136-
SINK(x.pop()) #$ flow="SOURCE, l:-1 -> x.pop()"
136+
SINK(x.pop()) #$ MISSING:flow="SOURCE, l:-1 -> x.pop()"
137137

138138

139139
def test_set_comprehension_inflow():
140140
l = {SOURCE}
141141
x = {y for y in l}
142-
SINK(x.pop()) #$ flow="SOURCE, l:-2 -> x.pop()"
142+
SINK(x.pop()) #$ MISSING:flow="SOURCE, l:-2 -> x.pop()"
143143

144144

145145
def test_nested_set_display():
@@ -155,7 +155,7 @@ def test_dict_display():
155155

156156
def test_dict_display_pop():
157157
x = {"s": SOURCE}
158-
SINK(x.pop("s")) #$ flow="SOURCE, l:-1 -> x.pop(..)"
158+
SINK(x.pop("s")) #$ MISSING:flow="SOURCE, l:-1 -> x.pop(..)"
159159

160160

161161
def test_dict_comprehension():

python/ql/test/experimental/dataflow/coverage/test_builtins.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,19 +100,19 @@ def test_set_from_list():
100100
l = [SOURCE]
101101
s = set(l)
102102
v = s.pop()
103-
SINK(v) #$ flow="SOURCE, l:-3 -> v"
103+
SINK(v) #$ MISSING:flow="SOURCE, l:-3 -> v"
104104

105105
def test_set_from_tuple():
106106
t = (SOURCE,)
107107
s = set(t)
108108
v = s.pop()
109-
SINK(v) #$ flow="SOURCE, l:-3 -> v"
109+
SINK(v) #$ MISSING:flow="SOURCE, l:-3 -> v"
110110

111111
def test_set_from_set():
112112
s0 = {SOURCE}
113113
s = set(s0)
114114
v = s.pop()
115-
SINK(v) #$ flow="SOURCE, l:-3 -> v"
115+
SINK(v) #$ MISSING:flow="SOURCE, l:-3 -> v"
116116

117117
def test_set_from_dict():
118118
d = {SOURCE: "val"}
@@ -149,7 +149,7 @@ def test_dict_from_dict():
149149
def test_list_pop():
150150
l = [SOURCE]
151151
v = l.pop()
152-
SINK(v) #$ flow="SOURCE, l:-2 -> v"
152+
SINK(v) #$ MISSING:flow="SOURCE, l:-2 -> v"
153153

154154
def test_list_pop_index():
155155
l = [SOURCE]
@@ -178,7 +178,7 @@ def test_list_append():
178178
def test_set_pop():
179179
s = {SOURCE}
180180
v = s.pop()
181-
SINK(v) #$ flow="SOURCE, l:-2 -> v"
181+
SINK(v) #$ MISSING:flow="SOURCE, l:-2 -> v"
182182

183183
def test_set_copy():
184184
s0 = {SOURCE}
@@ -218,17 +218,17 @@ def test_dict_items():
218218
def test_dict_pop():
219219
d = {'k': SOURCE}
220220
v = d.pop("k")
221-
SINK(v) #$ flow="SOURCE, l:-2 -> v"
221+
SINK(v) #$ MISSING:flow="SOURCE, l:-2 -> v"
222222
v1 = d.pop("k", NONSOURCE)
223-
SINK_F(v1) #$ SPURIOUS: flow="SOURCE, l:-4 -> v1"
223+
SINK_F(v1)
224224
v2 = d.pop("non-existing", SOURCE)
225225
SINK(v2) #$ MISSING: flow="SOURCE, l:-1 -> v2"
226226

227227
@expects(2)
228228
def test_dict_get():
229229
d = {'k': SOURCE}
230230
v = d.get("k")
231-
SINK(v) #$ flow="SOURCE, l:-2 -> v"
231+
SINK(v) #$ MISSING:flow="SOURCE, l:-2 -> v"
232232
v1 = d.get("non-existing", SOURCE)
233233
SINK(v1) #$ MISSING: flow="SOURCE, l:-1 -> v1"
234234

python/ql/test/experimental/dataflow/fieldflow/test_dict.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,23 @@ def SINK_F(x):
3535
def test_dict_literal():
3636
d = {"key": SOURCE}
3737
SINK(d["key"]) # $ flow="SOURCE, l:-1 -> d['key']"
38-
SINK(d.get("key")) # $ flow="SOURCE, l:-2 -> d.get(..)"
38+
SINK(d.get("key")) # $ MISSING:flow="SOURCE, l:-2 -> d.get(..)"
3939

4040

4141
@expects(2) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
4242
def test_dict_update():
4343
d = {}
4444
d["key"] = SOURCE
4545
SINK(d["key"]) # $ flow="SOURCE, l:-1 -> d['key']"
46-
SINK(d.get("key")) # $ flow="SOURCE, l:-2 -> d.get(..)"
46+
SINK(d.get("key")) # $ MISSING:flow="SOURCE, l:-2 -> d.get(..)"
4747

4848
@expects(3) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
4949
def test_dict_setdefault():
5050
d = {}
5151
x = d.setdefault("key", SOURCE)
5252
SINK(x) # $ flow="SOURCE, l:-1 -> x"
5353
SINK(d["key"]) # $ flow="SOURCE, l:-2 -> d['key']"
54-
SINK(d.setdefault("key", NONSOURCE)) # $ flow="SOURCE, l:-3 -> d.setdefault(..)"
54+
SINK(d.setdefault("key", NONSOURCE)) # $ MISSING:flow="SOURCE, l:-3 -> d.setdefault(..)"
5555

5656
@expects(2) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
5757
def test_dict_override():

python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.expected

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ edges
22
| UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | UnsafeUnpack.py:5:26:5:32 | GSSA Variable request |
33
| UnsafeUnpack.py:5:26:5:32 | GSSA Variable request | UnsafeUnpack.py:11:18:11:24 | ControlFlowNode for request |
44
| UnsafeUnpack.py:11:18:11:24 | ControlFlowNode for request | UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute |
5-
| UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute | UnsafeUnpack.py:11:18:11:49 | ControlFlowNode for Attribute() |
6-
| UnsafeUnpack.py:11:18:11:49 | ControlFlowNode for Attribute() | UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute |
5+
| UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute | UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute |
76
| UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute | UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath |
87
| UnsafeUnpack.py:33:50:33:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:34:23:34:38 | ControlFlowNode for local_ziped_path |
98
| UnsafeUnpack.py:47:20:47:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:48:23:48:37 | ControlFlowNode for compressed_file |
@@ -31,7 +30,6 @@ nodes
3130
| UnsafeUnpack.py:5:26:5:32 | GSSA Variable request | semmle.label | GSSA Variable request |
3231
| UnsafeUnpack.py:11:18:11:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
3332
| UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
34-
| UnsafeUnpack.py:11:18:11:49 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
3533
| UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
3634
| UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath |
3735
| UnsafeUnpack.py:33:50:33:65 | ControlFlowNode for local_ziped_path | semmle.label | ControlFlowNode for local_ziped_path |

0 commit comments

Comments
 (0)