@@ -3900,6 +3900,176 @@ private module StdlibPrivate {
39003900 }
39013901 }
39023902
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+
39034073 /**
39044074 * A flow summary for `dict.setdefault`.
39054075 *
@@ -3923,6 +4093,40 @@ private module StdlibPrivate {
39234093 preservesValue = true
39244094 }
39254095 }
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+ }
39264130}
39274131
39284132// ---------------------------------------------------------------------------
0 commit comments