Skip to content

Commit 2c14b41

Browse files
committed
python: make content sets an IPA type
this should have no semantic consequences
1 parent 74669cb commit 2c14b41

File tree

6 files changed

+83
-63
lines changed

6 files changed

+83
-63
lines changed

python/ql/lib/semmle/python/dataflow/new/TypeTracking.qll

+5-3
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class TypeTracker extends Impl::TypeTracker {
4848
*/
4949
predicate startInAttr(string attrName) {
5050
exists(DataFlowPublic::AttributeContent content | content.getAttribute() = attrName |
51-
this.startInContent(content)
51+
this.startInContent(DataFlowPublic::TSingletonContent(content))
5252
)
5353
}
5454

@@ -58,8 +58,10 @@ class TypeTracker extends Impl::TypeTracker {
5858
* Gets the attribute associated with this type tracker.
5959
*/
6060
string getAttr() {
61-
if this.getContent().asSome() instanceof DataFlowPublic::AttributeContent
62-
then result = this.getContent().asSome().(DataFlowPublic::AttributeContent).getAttribute()
61+
if this.getContent().asSome().asSingleton() instanceof DataFlowPublic::AttributeContent
62+
then
63+
result =
64+
this.getContent().asSome().asSingleton().(DataFlowPublic::AttributeContent).getAttribute()
6365
else result = ""
6466
}
6567
}

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

+25-25
Original file line numberDiff line numberDiff line change
@@ -679,13 +679,13 @@ predicate jumpStepNotSharedWithTypeTracker(Node nodeFrom, Node nodeTo) {
679679
* no reason to include steps for list content right now.
680680
*/
681681
predicate storeStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) {
682-
tupleStoreStep(nodeFrom, c, nodeTo)
682+
tupleStoreStep(nodeFrom, c.asSingleton(), nodeTo)
683683
or
684-
dictStoreStep(nodeFrom, c, nodeTo)
684+
dictStoreStep(nodeFrom, c.asSingleton(), nodeTo)
685685
or
686-
moreDictStoreSteps(nodeFrom, c, nodeTo)
686+
moreDictStoreSteps(nodeFrom, c.asSingleton(), nodeTo)
687687
or
688-
iterableUnpackingStoreStep(nodeFrom, c, nodeTo)
688+
iterableUnpackingStoreStep(nodeFrom, c.asSingleton(), nodeTo)
689689
}
690690

691691
/**
@@ -695,26 +695,26 @@ predicate storeStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) {
695695
predicate storeStep(Node nodeFrom, ContentSet c, Node nodeTo) {
696696
storeStepCommon(nodeFrom, c, nodeTo)
697697
or
698-
listStoreStep(nodeFrom, c, nodeTo)
698+
listStoreStep(nodeFrom, c.asSingleton(), nodeTo)
699699
or
700-
setStoreStep(nodeFrom, c, nodeTo)
700+
setStoreStep(nodeFrom, c.asSingleton(), nodeTo)
701701
or
702-
attributeStoreStep(nodeFrom, c, nodeTo)
702+
attributeStoreStep(nodeFrom, c.asSingleton(), nodeTo)
703703
or
704-
matchStoreStep(nodeFrom, c, nodeTo)
704+
matchStoreStep(nodeFrom, c.asSingleton(), nodeTo)
705705
or
706-
any(Orm::AdditionalOrmSteps es).storeStep(nodeFrom, c, nodeTo)
706+
any(Orm::AdditionalOrmSteps es).storeStep(nodeFrom, c.asSingleton(), nodeTo)
707707
or
708708
FlowSummaryImpl::Private::Steps::summaryStoreStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), c,
709709
nodeTo.(FlowSummaryNode).getSummaryNode())
710710
or
711-
synthStarArgsElementParameterNodeStoreStep(nodeFrom, c, nodeTo)
711+
synthStarArgsElementParameterNodeStoreStep(nodeFrom, c.asSingleton(), nodeTo)
712712
or
713-
synthDictSplatArgumentNodeStoreStep(nodeFrom, c, nodeTo)
713+
synthDictSplatArgumentNodeStoreStep(nodeFrom, c.asSingleton(), nodeTo)
714714
or
715-
yieldStoreStep(nodeFrom, c, nodeTo)
715+
yieldStoreStep(nodeFrom, c.asSingleton(), nodeTo)
716716
or
717-
VariableCapture::storeStep(nodeFrom, c, nodeTo)
717+
VariableCapture::storeStep(nodeFrom, c.asSingleton(), nodeTo)
718718
}
719719

720720
/**
@@ -911,9 +911,9 @@ predicate attributeStoreStep(Node nodeFrom, AttributeContent c, Node nodeTo) {
911911
* Subset of `readStep` that should be shared with type-tracking.
912912
*/
913913
predicate readStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) {
914-
subscriptReadStep(nodeFrom, c, nodeTo)
914+
subscriptReadStep(nodeFrom, c.asSingleton(), nodeTo)
915915
or
916-
iterableUnpackingReadStep(nodeFrom, c, nodeTo)
916+
iterableUnpackingReadStep(nodeFrom, c.asSingleton(), nodeTo)
917917
}
918918

919919
/**
@@ -922,18 +922,18 @@ predicate readStepCommon(Node nodeFrom, ContentSet c, Node nodeTo) {
922922
predicate readStep(Node nodeFrom, ContentSet c, Node nodeTo) {
923923
readStepCommon(nodeFrom, c, nodeTo)
924924
or
925-
matchReadStep(nodeFrom, c, nodeTo)
925+
matchReadStep(nodeFrom, c.asSingleton(), nodeTo)
926926
or
927-
forReadStep(nodeFrom, c, nodeTo)
927+
forReadStep(nodeFrom, c.asSingleton(), nodeTo)
928928
or
929-
attributeReadStep(nodeFrom, c, nodeTo)
929+
attributeReadStep(nodeFrom, c.asSingleton(), nodeTo)
930930
or
931931
FlowSummaryImpl::Private::Steps::summaryReadStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), c,
932932
nodeTo.(FlowSummaryNode).getSummaryNode())
933933
or
934-
synthDictSplatParameterNodeReadStep(nodeFrom, c, nodeTo)
934+
synthDictSplatParameterNodeReadStep(nodeFrom, c.asSingleton(), nodeTo)
935935
or
936-
VariableCapture::readStep(nodeFrom, c, nodeTo)
936+
VariableCapture::readStep(nodeFrom, c.asSingleton(), nodeTo)
937937
}
938938

939939
/** Data flows from a sequence to a subscript of the sequence. */
@@ -995,17 +995,17 @@ predicate attributeReadStep(Node nodeFrom, AttributeContent c, AttrRead nodeTo)
995995
* in `x.f = newValue`.
996996
*/
997997
predicate clearsContent(Node n, ContentSet c) {
998-
matchClearStep(n, c)
998+
matchClearStep(n, c.asSingleton())
999999
or
1000-
attributeClearStep(n, c)
1000+
attributeClearStep(n, c.asSingleton())
10011001
or
1002-
dictClearStep(n, c)
1002+
dictClearStep(n, c.asSingleton())
10031003
or
10041004
FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c)
10051005
or
1006-
dictSplatParameterNodeClearStep(n, c)
1006+
dictSplatParameterNodeClearStep(n, c.asSingleton())
10071007
or
1008-
VariableCapture::clearsContent(n, c)
1008+
VariableCapture::clearsContent(n, c.asSingleton())
10091009
}
10101010

10111011
/**

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

+12-4
Original file line numberDiff line numberDiff line change
@@ -769,19 +769,27 @@ class CapturedVariableContent extends Content, TCapturedVariableContent {
769769
override string getMaDRepresentation() { none() }
770770
}
771771

772+
newtype TContentSet = TSingletonContent(Content c)
773+
772774
/**
773775
* An entity that represents a set of `Content`s.
774776
*
775777
* The set may be interpreted differently depending on whether it is
776778
* stored into (`getAStoreContent`) or read from (`getAReadContent`).
777779
*/
778-
class ContentSet instanceof Content {
780+
class ContentSet extends TContentSet {
781+
/** Holds if this content set is the singleton `{c}`. */
782+
predicate isSingleton(Content c) { this = TSingletonContent(c) }
783+
784+
/** Gets the singleton `Content` underlying this `ContentSet`, if any. */
785+
Content asSingleton() { this.isSingleton(result) }
786+
779787
/** Gets a content that may be stored into when storing into this set. */
780-
Content getAStoreContent() { result = this }
788+
Content getAStoreContent() { this.isSingleton(result) }
781789

782790
/** Gets a content that may be read from when reading from this set. */
783-
Content getAReadContent() { result = this }
791+
Content getAReadContent() { this.isSingleton(result) }
784792

785793
/** Gets a textual representation of this content set. */
786-
string toString() { result = super.toString() }
794+
string toString() { result = any(Content c | this.isSingleton(c)).toString() }
787795
}

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

+30-20
Original file line numberDiff line numberDiff line change
@@ -62,21 +62,23 @@ module Input implements InputSig<Location, DataFlowImplSpecific::PythonDataFlow>
6262
}
6363

6464
string encodeContent(ContentSet cs, string arg) {
65-
cs = TListElementContent() and result = "ListElement" and arg = ""
66-
or
67-
cs = TSetElementContent() and result = "SetElement" and arg = ""
68-
or
69-
exists(int index |
70-
cs = TTupleElementContent(index) and result = "TupleElement" and arg = index.toString()
71-
)
72-
or
73-
exists(string key |
74-
cs = TDictionaryElementContent(key) and result = "DictionaryElement" and arg = key
65+
exists(Content c | cs.isSingleton(c) |
66+
c = TListElementContent() and result = "ListElement" and arg = ""
67+
or
68+
c = TSetElementContent() and result = "SetElement" and arg = ""
69+
or
70+
exists(int index |
71+
c = TTupleElementContent(index) and result = "TupleElement" and arg = index.toString()
72+
)
73+
or
74+
exists(string key |
75+
c = TDictionaryElementContent(key) and result = "DictionaryElement" and arg = key
76+
)
77+
or
78+
c = TDictionaryElementAnyContent() and result = "DictionaryElementAny" and arg = ""
79+
or
80+
exists(string attr | c = TAttributeContent(attr) and result = "Attribute" and arg = attr)
7581
)
76-
or
77-
cs = TDictionaryElementAnyContent() and result = "DictionaryElementAny" and arg = ""
78-
or
79-
exists(string attr | cs = TAttributeContent(attr) and result = "Attribute" and arg = attr)
8082
}
8183

8284
bindingset[token]
@@ -132,27 +134,35 @@ module Private {
132134
predicate withContent = SC::withContent/1;
133135

134136
/** Gets a summary component that represents a list element. */
135-
SummaryComponent listElement() { result = content(any(ListElementContent c)) }
137+
SummaryComponent listElement() { result = content(TSingletonContent(TListElementContent())) }
136138

137139
/** Gets a summary component that represents a set element. */
138-
SummaryComponent setElement() { result = content(any(SetElementContent c)) }
140+
SummaryComponent setElement() { result = content(TSingletonContent(TSetElementContent())) }
139141

140142
/** Gets a summary component that represents a tuple element. */
141143
SummaryComponent tupleElement(int index) {
142-
exists(TupleElementContent c | c.getIndex() = index and result = content(c))
144+
exists(TupleElementContent c |
145+
c.getIndex() = index and result = content(TSingletonContent(c))
146+
)
143147
}
144148

145149
/** Gets a summary component that represents a dictionary element. */
146150
SummaryComponent dictionaryElement(string key) {
147-
exists(DictionaryElementContent c | c.getKey() = key and result = content(c))
151+
exists(DictionaryElementContent c |
152+
c.getKey() = key and result = content(TSingletonContent(c))
153+
)
148154
}
149155

150156
/** Gets a summary component that represents a dictionary element at any key. */
151-
SummaryComponent dictionaryElementAny() { result = content(any(DictionaryElementAnyContent c)) }
157+
SummaryComponent dictionaryElementAny() {
158+
result = content(TSingletonContent(TDictionaryElementAnyContent()))
159+
}
152160

153161
/** Gets a summary component that represents an attribute element. */
154162
SummaryComponent attribute(string attr) {
155-
exists(AttributeContent c | c.getAttribute() = attr and result = content(c))
163+
exists(AttributeContent c |
164+
c.getAttribute() = attr and result = content(TSingletonContent(c))
165+
)
156166
}
157167

158168
/** Gets a summary component that represents the return value of a call. */

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

+6-6
Original file line numberDiff line numberDiff line change
@@ -111,19 +111,19 @@ module TypeTrackingInput implements Shared::TypeTrackingInput<Location> {
111111

112112
class LocalSourceNode = DataFlowPublic::LocalSourceNode;
113113

114-
class Content extends DataFlowPublic::Content {
114+
class Content extends DataFlowPublic::ContentSet {
115115
Content() {
116116
// TODO: for now, it's not 100% clear if should support non-precise content in
117117
// type-tracking, or if it will lead to bad results. We start with only allowing
118118
// precise content, which should always be a good improvement! It also simplifies
119119
// the process of examining new results from non-precise content steps in the
120120
// future, since you will _only_ have to look over the results from the new
121121
// non-precise steps.
122-
this instanceof DataFlowPublic::AttributeContent
122+
this.asSingleton() instanceof DataFlowPublic::AttributeContent
123123
or
124-
this instanceof DataFlowPublic::DictionaryElementContent
124+
this.asSingleton() instanceof DataFlowPublic::DictionaryElementContent
125125
or
126-
this instanceof DataFlowPublic::TupleElementContent
126+
this.asSingleton() instanceof DataFlowPublic::TupleElementContent
127127
}
128128
}
129129

@@ -212,7 +212,7 @@ module TypeTrackingInput implements Shared::TypeTrackingInput<Location> {
212212
*/
213213
predicate storeStep(Node nodeFrom, Node nodeTo, Content content) {
214214
exists(DataFlowPublic::AttrWrite a, string attrName |
215-
content.(DataFlowPublic::AttributeContent).getAttribute() = attrName and
215+
content.asSingleton().(DataFlowPublic::AttributeContent).getAttribute() = attrName and
216216
a.mayHaveAttributeName(attrName) and
217217
nodeFrom = a.getValue() and
218218
nodeTo = a.getObject()
@@ -242,7 +242,7 @@ module TypeTrackingInput implements Shared::TypeTrackingInput<Location> {
242242
*/
243243
predicate loadStep(Node nodeFrom, LocalSourceNode nodeTo, Content content) {
244244
exists(DataFlowPublic::AttrRead a, string attrName |
245-
content.(DataFlowPublic::AttributeContent).getAttribute() = attrName and
245+
content.asSingleton().(DataFlowPublic::AttributeContent).getAttribute() = attrName and
246246
a.mayHaveAttributeName(attrName) and
247247
nodeFrom = a.getObject() and
248248
nodeTo = a

python/ql/src/Variables/LoopVariableCapture/LoopVariableCaptureQuery.qll

+5-5
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ module EscapingCaptureFlowConfig implements DataFlow::ConfigSig {
5858

5959
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet cs) {
6060
isSink(node) and
61-
(
62-
cs.(DataFlow::TupleElementContent).getIndex() in [0 .. 10] or
63-
cs instanceof DataFlow::ListElementContent or
64-
cs instanceof DataFlow::SetElementContent or
65-
cs instanceof DataFlow::DictionaryElementAnyContent
61+
exists(DataFlow::Content c | cs = DataFlow::TSingletonContent(c) |
62+
c.(DataFlow::TupleElementContent).getIndex() in [0 .. 10] or
63+
c instanceof DataFlow::ListElementContent or
64+
c instanceof DataFlow::SetElementContent or
65+
c instanceof DataFlow::DictionaryElementAnyContent
6666
)
6767
}
6868
}

0 commit comments

Comments
 (0)