@@ -249,6 +249,60 @@ module API {
249
249
*/
250
250
Node getASubscript ( ) { result = this .getASuccessor ( Label:: subscript ( ) ) }
251
251
252
+ /**
253
+ * Gets a node representing an index of a subscript of this node.
254
+ * For example, in `obj[x]`, `x` is an index of `obj`.
255
+ */
256
+ Node getIndex ( ) { result = this .getASuccessor ( Label:: index ( ) ) }
257
+
258
+ /**
259
+ * Gets a node representing a subscript of this node at (string) index `key`.
260
+ * This requires that the index can be statically determined.
261
+ *
262
+ * For example, the subscripts of `a` and `b` below would be found using
263
+ * the index `foo`:
264
+ * ```py
265
+ * a["foo"]
266
+ * x = "foo" if cond else "bar"
267
+ * b[x]
268
+ * ```
269
+ */
270
+ Node getSubscript ( string key ) {
271
+ exists ( API:: Node index | result = this .getSubscriptAt ( index ) |
272
+ key = index .getAValueReachingSink ( ) .asExpr ( ) .( PY:: StrConst ) .getText ( )
273
+ )
274
+ }
275
+
276
+ /**
277
+ * Gets a node representing a subscript of this node at index `index`.
278
+ */
279
+ Node getSubscriptAt ( API:: Node index ) {
280
+ result = this .getASubscript ( ) and
281
+ index = this .getIndex ( ) and
282
+ (
283
+ // subscripting
284
+ exists ( PY:: SubscriptNode subscript |
285
+ subscript .getObject ( ) = this .getAValueReachableFromSource ( ) .asCfgNode ( ) and
286
+ subscript .getIndex ( ) = index .asSink ( ) .asCfgNode ( )
287
+ |
288
+ // reading
289
+ subscript = result .asSource ( ) .asCfgNode ( )
290
+ or
291
+ // writing
292
+ subscript .( PY:: DefinitionNode ) .getValue ( ) = result .asSink ( ) .asCfgNode ( )
293
+ )
294
+ or
295
+ // dictionary literals
296
+ exists ( PY:: Dict dict , PY:: KeyValuePair item |
297
+ dict = this .getAValueReachingSink ( ) .asExpr ( ) and
298
+ dict .getItem ( _) = item and
299
+ item .getKey ( ) = index .asSink ( ) .asExpr ( )
300
+ |
301
+ item .getValue ( ) = result .asSink ( ) .asExpr ( )
302
+ )
303
+ )
304
+ }
305
+
252
306
/**
253
307
* Gets a string representation of the lexicographically least among all shortest access paths
254
308
* from the root to this node.
@@ -405,7 +459,7 @@ module API {
405
459
Node builtin ( string n ) { result = moduleImport ( "builtins" ) .getMember ( n ) }
406
460
407
461
/**
408
- * An `CallCfgNode` that is connected to the API graph.
462
+ * A `CallCfgNode` that is connected to the API graph.
409
463
*
410
464
* Can be used to reason about calls to an external API in which the correlation between
411
465
* parameters and/or return values must be retained.
@@ -694,12 +748,24 @@ module API {
694
748
rhs = aw .getValue ( )
695
749
)
696
750
or
697
- // TODO: I had expected `DataFlow::AttrWrite` to contain the attribute writes from a dict, that's how JS works.
751
+ // dictionary literals
698
752
exists ( PY:: Dict dict , PY:: KeyValuePair item |
699
753
dict = pred .( DataFlow:: ExprNode ) .getNode ( ) .getNode ( ) and
700
- dict .getItem ( _) = item and
701
- lbl = Label:: member ( item .getKey ( ) .( PY:: StrConst ) .getS ( ) ) and
702
- rhs .( DataFlow:: ExprNode ) .getNode ( ) .getNode ( ) = item .getValue ( )
754
+ dict .getItem ( _) = item
755
+ |
756
+ // from `x` to `{ "key": x }`
757
+ rhs .( DataFlow:: ExprNode ) .getNode ( ) .getNode ( ) = item .getValue ( ) and
758
+ lbl = Label:: subscript ( )
759
+ or
760
+ // from `"key"` to `{ "key": x }`
761
+ rhs .( DataFlow:: ExprNode ) .getNode ( ) .getNode ( ) = item .getKey ( ) and
762
+ lbl = Label:: index ( )
763
+ )
764
+ or
765
+ // list literals, from `x` to `[x]`
766
+ exists ( PY:: List list | list = pred .( DataFlow:: ExprNode ) .getNode ( ) .getNode ( ) |
767
+ rhs .( DataFlow:: ExprNode ) .getNode ( ) .getNode ( ) = list .getAnElt ( ) and
768
+ lbl = Label:: subscript ( )
703
769
)
704
770
or
705
771
exists ( PY:: CallableExpr fn | fn = pred .( DataFlow:: ExprNode ) .getNode ( ) .getNode ( ) |
@@ -720,6 +786,20 @@ module API {
720
786
lbl = Label:: memberFromRef ( aw )
721
787
)
722
788
or
789
+ // subscripting
790
+ exists ( DataFlow:: LocalSourceNode src , DataFlow:: Node subscript , DataFlow:: Node index |
791
+ use ( base , src ) and
792
+ subscript = trackUseNode ( src ) .getSubscript ( index )
793
+ |
794
+ // from `x` to a definition of `x[...]`
795
+ rhs .asCfgNode ( ) = subscript .asCfgNode ( ) .( PY:: DefinitionNode ) .getValue ( ) and
796
+ lbl = Label:: subscript ( )
797
+ or
798
+ // from `x` to `"key"` in `x["key"]`
799
+ rhs = index and
800
+ lbl = Label:: index ( )
801
+ )
802
+ or
723
803
exists ( EntryPoint entry |
724
804
base = root ( ) and
725
805
lbl = Label:: entryPoint ( entry ) and
@@ -757,7 +837,8 @@ module API {
757
837
or
758
838
// Subscripting a node that is a use of `base`
759
839
lbl = Label:: subscript ( ) and
760
- ref = pred .getASubscript ( )
840
+ ref = pred .getSubscript ( _) and
841
+ ref .asCfgNode ( ) .isLoad ( )
761
842
or
762
843
// Subclassing a node
763
844
lbl = Label:: subclass ( ) and
@@ -973,8 +1054,7 @@ module API {
973
1054
member = any ( DataFlow:: AttrRef pr ) .getAttributeName ( ) or
974
1055
exists ( Builtins:: likelyBuiltin ( member ) ) or
975
1056
ImportStar:: namePossiblyDefinedInImportStar ( _, member , _) or
976
- Impl:: prefix_member ( _, member , _) or
977
- member = any ( PY:: Dict d ) .getAnItem ( ) .( PY:: KeyValuePair ) .getKey ( ) .( PY:: StrConst ) .getS ( )
1057
+ Impl:: prefix_member ( _, member , _)
978
1058
} or
979
1059
MkLabelUnknownMember ( ) or
980
1060
MkLabelParameter ( int i ) {
@@ -992,6 +1072,7 @@ module API {
992
1072
MkLabelSubclass ( ) or
993
1073
MkLabelAwait ( ) or
994
1074
MkLabelSubscript ( ) or
1075
+ MkLabelIndex ( ) or
995
1076
MkLabelEntryPoint ( EntryPoint ep )
996
1077
997
1078
/** A label for a module. */
@@ -1072,6 +1153,11 @@ module API {
1072
1153
override string toString ( ) { result = "getASubscript()" }
1073
1154
}
1074
1155
1156
+ /** A label that gets the index of a subscript. */
1157
+ class LabelIndex extends ApiLabel , MkLabelIndex {
1158
+ override string toString ( ) { result = "getIndex()" }
1159
+ }
1160
+
1075
1161
/** A label for entry points. */
1076
1162
class LabelEntryPoint extends ApiLabel , MkLabelEntryPoint {
1077
1163
private EntryPoint entry ;
@@ -1120,6 +1206,9 @@ module API {
1120
1206
/** Gets the `subscript` edge label. */
1121
1207
LabelSubscript subscript ( ) { any ( ) }
1122
1208
1209
+ /** Gets the `subscript` edge label. */
1210
+ LabelIndex index ( ) { any ( ) }
1211
+
1123
1212
/** Gets the label going from the root node to the nodes associated with the given entry point. */
1124
1213
LabelEntryPoint entryPoint ( EntryPoint ep ) { result = MkLabelEntryPoint ( ep ) }
1125
1214
}
0 commit comments