@@ -3900,6 +3900,176 @@ private module StdlibPrivate {
3900
3900
}
3901
3901
}
3902
3902
3903
+ // ---------------------------------------------------------------------------
3904
+ // Flow summaries for container methods
3905
+ // ---------------------------------------------------------------------------
3906
+ /** A flow summary for `copy`. */
3907
+ class CopySummary extends SummarizedCallable {
3908
+ CopySummary ( ) { this = "collection.copy" }
3909
+
3910
+ override DataFlow:: CallCfgNode getACall ( ) {
3911
+ result .( DataFlow:: MethodCallNode ) .getMethodName ( ) = "copy"
3912
+ }
3913
+
3914
+ override DataFlow:: ArgumentNode getACallback ( ) { none ( ) }
3915
+
3916
+ override predicate propagatesFlowExt ( string input , string output , boolean preservesValue ) {
3917
+ exists ( string content |
3918
+ content = "ListElement"
3919
+ or
3920
+ content = "SetElement"
3921
+ or
3922
+ exists ( DataFlow:: TupleElementContent tc , int i | i = tc .getIndex ( ) |
3923
+ content = "TupleElement[" + i .toString ( ) + "]"
3924
+ )
3925
+ or
3926
+ exists ( DataFlow:: DictionaryElementContent dc , string key | key = dc .getKey ( ) |
3927
+ content = "DictionaryElement[" + key + "]"
3928
+ )
3929
+ |
3930
+ input = "Argument[self]." + content and
3931
+ output = "ReturnValue." + content and
3932
+ preservesValue = true
3933
+ )
3934
+ or
3935
+ input = "Argument[self]" and
3936
+ output = "ReturnValue" and
3937
+ preservesValue = true
3938
+ }
3939
+ }
3940
+
3941
+ /**
3942
+ * A flow summary for `pop` either for list or set.
3943
+ * This ignores the index if given, since content is
3944
+ * imprecise anyway.
3945
+ *
3946
+ * I also handles the default value when `pop` is called
3947
+ * on a dictionary, since that also does not depend on the key.
3948
+ */
3949
+ class PopSummary extends SummarizedCallable {
3950
+ PopSummary ( ) { this = "collection.pop" }
3951
+
3952
+ override DataFlow:: CallCfgNode getACall ( ) {
3953
+ result .( DataFlow:: MethodCallNode ) .getMethodName ( ) = "pop"
3954
+ }
3955
+
3956
+ override DataFlow:: ArgumentNode getACallback ( ) { none ( ) }
3957
+
3958
+ override predicate propagatesFlowExt ( string input , string output , boolean preservesValue ) {
3959
+ input = "Argument[self].ListElement" and
3960
+ output = "ReturnValue" and
3961
+ preservesValue = true
3962
+ or
3963
+ input = "Argument[self].SetElement" and
3964
+ output = "ReturnValue" and
3965
+ preservesValue = true
3966
+ or
3967
+ // default value for dictionary
3968
+ input = "Argument[1]" and
3969
+ output = "ReturnValue" and
3970
+ preservesValue = true
3971
+ or
3972
+ // transfer taint on self to return value
3973
+ input = "Argument[self]" and
3974
+ output = "ReturnValue" and
3975
+ preservesValue = false
3976
+ }
3977
+ }
3978
+
3979
+ /** A flow summary for `dict.pop` */
3980
+ class DictPopSummary extends SummarizedCallable {
3981
+ string key ;
3982
+
3983
+ DictPopSummary ( ) {
3984
+ this = "dict.pop(" + key + ")" and
3985
+ exists ( DataFlow:: DictionaryElementContent dc | key = dc .getKey ( ) )
3986
+ }
3987
+
3988
+ override DataFlow:: CallCfgNode getACall ( ) {
3989
+ result .( DataFlow:: MethodCallNode ) .getMethodName ( ) = "pop" and
3990
+ result .getArg ( 0 ) .getALocalSource ( ) .asExpr ( ) .( StrConst ) .getText ( ) = key
3991
+ }
3992
+
3993
+ override DataFlow:: ArgumentNode getACallback ( ) { none ( ) }
3994
+
3995
+ override predicate propagatesFlowExt ( string input , string output , boolean preservesValue ) {
3996
+ input = "Argument[self].DictionaryElement[" + key + "]" and
3997
+ output = "ReturnValue" and
3998
+ preservesValue = true
3999
+ }
4000
+ }
4001
+
4002
+ /** A flow summary for `dict.get` at specific content. */
4003
+ class DictGetSummary extends SummarizedCallable {
4004
+ string key ;
4005
+
4006
+ DictGetSummary ( ) {
4007
+ this = "dict.get(" + key + ")" and
4008
+ exists ( DataFlow:: DictionaryElementContent dc | key = dc .getKey ( ) )
4009
+ }
4010
+
4011
+ override DataFlow:: CallCfgNode getACall ( ) {
4012
+ result .( DataFlow:: MethodCallNode ) .getMethodName ( ) = "get" and
4013
+ result .getArg ( 0 ) .getALocalSource ( ) .asExpr ( ) .( StrConst ) .getText ( ) = key
4014
+ }
4015
+
4016
+ override DataFlow:: ArgumentNode getACallback ( ) { none ( ) }
4017
+
4018
+ override predicate propagatesFlowExt ( string input , string output , boolean preservesValue ) {
4019
+ input = "Argument[self].DictionaryElement[" + key + "]" and
4020
+ output = "ReturnValue" and
4021
+ preservesValue = true
4022
+ or
4023
+ // optional default value
4024
+ input = "Argument[1]" and
4025
+ output = "ReturnValue" and
4026
+ preservesValue = true
4027
+ }
4028
+ }
4029
+
4030
+ /** A flow summary for `dict.get` disregarding content. */
4031
+ class DictGetAnySummary extends SummarizedCallable {
4032
+ DictGetAnySummary ( ) { this = "dict.get" }
4033
+
4034
+ override DataFlow:: CallCfgNode getACall ( ) {
4035
+ result .( DataFlow:: MethodCallNode ) .getMethodName ( ) = "get"
4036
+ }
4037
+
4038
+ override DataFlow:: ArgumentNode getACallback ( ) { none ( ) }
4039
+
4040
+ override predicate propagatesFlowExt ( string input , string output , boolean preservesValue ) {
4041
+ // default value
4042
+ input = "Argument[1]" and
4043
+ output = "ReturnValue" and
4044
+ preservesValue = true
4045
+ or
4046
+ // transfer taint from self to return value
4047
+ input = "Argument[self]" and
4048
+ output = "ReturnValue" and
4049
+ preservesValue = false
4050
+ }
4051
+ }
4052
+
4053
+ /** A flow summary for `dict.popitem` */
4054
+ class DictPopitemSummary extends SummarizedCallable {
4055
+ DictPopitemSummary ( ) { this = "dict.popitem" }
4056
+
4057
+ override DataFlow:: CallCfgNode getACall ( ) {
4058
+ result .( DataFlow:: MethodCallNode ) .getMethodName ( ) = "popitem"
4059
+ }
4060
+
4061
+ override DataFlow:: ArgumentNode getACallback ( ) { none ( ) }
4062
+
4063
+ override predicate propagatesFlowExt ( string input , string output , boolean preservesValue ) {
4064
+ exists ( DataFlow:: DictionaryElementContent dc , string key | key = dc .getKey ( ) |
4065
+ input = "Argument[self].DictionaryElement[" + key + "]" and
4066
+ output = "ReturnValue.TupleElement[1]" and
4067
+ preservesValue = true
4068
+ // TODO: put `key` into "ReturnValue.TupleElement[0]"
4069
+ )
4070
+ }
4071
+ }
4072
+
3903
4073
/**
3904
4074
* A flow summary for `dict.setdefault`.
3905
4075
*
@@ -3923,6 +4093,40 @@ private module StdlibPrivate {
3923
4093
preservesValue = true
3924
4094
}
3925
4095
}
4096
+
4097
+ /**
4098
+ * A flow summary for `dict.setdefault` at specific content.
4099
+ * See https://docs.python.org/3.10/library/stdtypes.html#dict.setdefault
4100
+ * This summary handles read and store steps. See `DictSetdefaultSummary`
4101
+ * for the dataflow steps.
4102
+ */
4103
+ class DictSetdefaultKeySummary extends SummarizedCallable {
4104
+ string key ;
4105
+
4106
+ DictSetdefaultKeySummary ( ) {
4107
+ this = "dict.setdefault(" + key + ")" and
4108
+ exists ( DataFlow:: DictionaryElementContent dc | key = dc .getKey ( ) )
4109
+ }
4110
+
4111
+ override DataFlow:: CallCfgNode getACall ( ) {
4112
+ result .( DataFlow:: MethodCallNode ) .getMethodName ( ) = "setdefault" and
4113
+ result .getArg ( 0 ) .getALocalSource ( ) .asExpr ( ) .( StrConst ) .getText ( ) = key
4114
+ }
4115
+
4116
+ override DataFlow:: ArgumentNode getACallback ( ) { none ( ) }
4117
+
4118
+ override predicate propagatesFlowExt ( string input , string output , boolean preservesValue ) {
4119
+ // If key is in the dictionary, return its value.
4120
+ input = "Argument[self].DictionaryElement[" + key + "]" and
4121
+ output = "ReturnValue" and
4122
+ preservesValue = true
4123
+ or
4124
+ // If not, insert key with a value of default.
4125
+ input = "Argument[1]" and
4126
+ output = "ReturnValue.DictionaryElement[" + key + "]" and
4127
+ preservesValue = true
4128
+ }
4129
+ }
3926
4130
}
3927
4131
3928
4132
// ---------------------------------------------------------------------------
0 commit comments