Skip to content

Commit 6520f9d

Browse files
committed
C++: Add basic std::set models.
1 parent 5bc7d3a commit 6520f9d

File tree

7 files changed

+407
-58
lines changed

7 files changed

+407
-58
lines changed

cpp/ql/src/semmle/code/cpp/models/Models.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ private import implementations.Strftime
1717
private import implementations.StdContainer
1818
private import implementations.StdPair
1919
private import implementations.StdMap
20+
private import implementations.StdSet
2021
private import implementations.StdString
2122
private import implementations.Swap
2223
private import implementations.GetDelim
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* Provides models for C++ containers `std::set` and `std::unordered_set`.
3+
*/
4+
5+
import semmle.code.cpp.models.interfaces.Taint
6+
import semmle.code.cpp.models.implementations.Iterator
7+
8+
/**
9+
* The standard set `insert` and `insert_or_assign` functions.
10+
*/
11+
class StdSetInsert extends TaintFunction {
12+
StdSetInsert() {
13+
this.hasQualifiedName("std", ["set", "unordered_set"], "insert")
14+
}
15+
16+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
17+
// flow from last parameter to qualifier and return value
18+
// (where the return value is a pair, this should really flow just to the first part of it)
19+
input.isParameterDeref(getNumberOfParameters() - 1) and
20+
(
21+
output.isQualifierObject() or
22+
output.isReturnValue()
23+
)
24+
}
25+
}
26+
27+
/**
28+
* The standard set `begin` and `end` functions and their
29+
* variants.
30+
*/
31+
class StdSetBeginEnd extends TaintFunction {
32+
StdSetBeginEnd() {
33+
this.hasQualifiedName("std", ["set", "unordered_set"], ["begin", "end", "cbegin", "cend"])
34+
or
35+
this.hasQualifiedName("std", "set", ["rbegin", "crbegin", "rend", "crend"])
36+
}
37+
38+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
39+
input.isQualifierObject() and
40+
output.isReturnValue()
41+
}
42+
}
43+
44+
/**
45+
* The standard set `swap` functions.
46+
*/
47+
class StdSetSwap extends TaintFunction {
48+
StdSetSwap() { this.hasQualifiedName("std", ["set", "unordered_set"], "swap") }
49+
50+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
51+
// container1.swap(container2)
52+
input.isQualifierObject() and
53+
output.isParameterDeref(0)
54+
or
55+
input.isParameterDeref(0) and
56+
output.isQualifierObject()
57+
}
58+
}
59+
60+
/**
61+
* The standard set `find` function.
62+
*/
63+
class StdSetFind extends TaintFunction {
64+
StdSetFind() { this.hasQualifiedName("std", ["set", "unordered_set"], "find") }
65+
66+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
67+
input.isQualifierObject() and
68+
output.isReturnValue()
69+
}
70+
}
71+
72+
/**
73+
* The standard set `erase` function.
74+
*/
75+
class StdSetErase extends TaintFunction {
76+
StdSetErase() { this.hasQualifiedName("std", ["set", "unordered_set"], "erase") }
77+
78+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
79+
// flow from qualifier to iterator return value
80+
getType().getUnderlyingType() instanceof Iterator and
81+
input.isQualifierObject() and
82+
output.isReturnValue()
83+
}
84+
}

cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected

Lines changed: 128 additions & 0 deletions
Large diffs are not rendered by default.

cpp/ql/test/library-tests/dataflow/taint-tests/set.cpp

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -17,38 +17,38 @@ void test_set()
1717
std::set<char *> s1, s2, s3, s4, s5, s6;
1818

1919
sink(s1.insert("abc").first);
20-
sink(s2.insert(source()).first); // tainted [NOT DETECTED]
20+
sink(s2.insert(source()).first); // tainted
2121
sink(s3.insert(s3.begin(), "abc"));
22-
sink(s4.insert(s4.begin(), source())); // tainted [NOT DETECTED]
22+
sink(s4.insert(s4.begin(), source())); // tainted
2323
s5.insert(s1.begin(), s1.end());
2424
s6.insert(s2.begin(), s2.end());
2525
sink(s1);
26-
sink(s2); // tainted [NOT DETECTED]
26+
sink(s2); // tainted
2727
sink(s3);
28-
sink(s4); // tainted [NOT DETECTED]
28+
sink(s4); // tainted
2929
sink(s5);
30-
sink(s6); // tainted [NOT DETECTED]
30+
sink(s6); // tainted
3131
sink(s1.find("abc"));
32-
sink(s2.find("abc")); // tainted [NOT DETECTED]
32+
sink(s2.find("abc")); // tainted
3333
sink(s3.find("abc"));
34-
sink(s4.find("abc")); // tainted [NOT DETECTED]
34+
sink(s4.find("abc")); // tainted
3535
sink(s5.find("abc"));
36-
sink(s6.find("abc")); // tainted [NOT DETECTED]
36+
sink(s6.find("abc")); // tainted
3737

3838
// copy constructors and assignment
3939
std::set<char *> s7(s2);
4040
std::set<char *> s8 = s2;
4141
std::set<char *> s9(s2.begin(), s2.end());
4242
std::set<char *> s10;
4343
s10 = s2;
44-
sink(s7); // tainted [NOT DETECTED]
45-
sink(s8); // tainted [NOT DETECTED]
44+
sink(s7); // tainted
45+
sink(s8); // tainted
4646
sink(s9); // tainted [NOT DETECTED]
47-
sink(s10); // tainted [NOT DETECTED]
48-
sink(s7.find("abc")); // tainted [NOT DETECTED]
49-
sink(s8.find("abc")); // tainted [NOT DETECTED]
47+
sink(s10); // tainted
48+
sink(s7.find("abc")); // tainted
49+
sink(s8.find("abc")); // tainted
5050
sink(s9.find("abc")); // tainted [NOT DETECTED]
51-
sink(s10.find("abc")); // tainted [NOT DETECTED]
51+
sink(s10.find("abc")); // tainted
5252

5353
// iterators
5454
std::set<char *>::iterator i1, i2;
@@ -58,7 +58,7 @@ void test_set()
5858
}
5959
for (i2 = s2.begin(); i2 != s2.end(); i2++)
6060
{
61-
sink(*i2); // tainted [NOT DETECTED]
61+
sink(*i2); // tainted
6262
}
6363

6464
// ranges
@@ -75,43 +75,43 @@ void test_set()
7575
std::set<char *> s12, s13, s14, s15;
7676
s12.insert(source());
7777
s15.insert(source());
78-
sink(s12); // tainted [NOT DETECTED]
78+
sink(s12); // tainted
7979
sink(s13);
8080
sink(s14);
81-
sink(s15); // tainted [NOT DETECTED]
81+
sink(s15); // tainted
8282
s12.swap(s13);
8383
s14.swap(s15);
84-
sink(s12);
85-
sink(s13); // tainted [NOT DETECTED]
86-
sink(s14); // tainted [NOT DETECTED]
87-
sink(s15);
84+
sink(s12); // [FALSE POSITIVE]
85+
sink(s13); // tainted
86+
sink(s14); // tainted
87+
sink(s15); // [FALSE POSITIVE]
8888

8989
// merge
9090
std::set<char *> s16, s17, s18, s19;
9191
s16.insert(source());
9292
s17.insert("abc");
9393
s18.insert("def");
9494
s19.insert(source());
95-
sink(s16); // tainted [NOT DETECTED]
95+
sink(s16); // tainted
9696
sink(s17);
9797
sink(s18);
98-
sink(s19); // tainted [NOT DETECTED]
98+
sink(s19); // tainted
9999
s16.merge(s17);
100100
s18.merge(s19);
101-
sink(s16); // tainted [NOT DETECTED]
101+
sink(s16); // tainted
102102
sink(s17); // tainted [NOT DETECTED]
103103
sink(s18); // tainted [NOT DETECTED]
104-
sink(s19); // tainted [NOT DETECTED]
104+
sink(s19); // tainted
105105

106106
// erase, clear
107107
std::set<char *> s20;
108108
s20.insert(source());
109109
s20.insert(source());
110-
sink(s20); // tainted [NOT DETECTED]
111-
sink(s20.erase(s20.begin())); // tainted [NOT DETECTED]
112-
sink(s20); // tainted [NOT DETECTED]
110+
sink(s20); // tainted
111+
sink(s20.erase(s20.begin())); // tainted
112+
sink(s20); // tainted
113113
s20.clear();
114-
sink(s20);
114+
sink(s20); // [FALSE POSITIVE]
115115

116116
// emplace, emplace_hint
117117
std::set<char *> s21, s22;
@@ -131,38 +131,38 @@ void test_unordered_set()
131131
std::unordered_set<char *> s1, s2, s3, s4, s5, s6;
132132

133133
sink(s1.insert("abc").first);
134-
sink(s2.insert(source()).first); // tainted [NOT DETECTED]
134+
sink(s2.insert(source()).first); // tainted
135135
sink(s3.insert(s3.begin(), "abc"));
136-
sink(s4.insert(s4.begin(), source())); // tainted [NOT DETECTED]
136+
sink(s4.insert(s4.begin(), source())); // tainted
137137
s5.insert(s1.begin(), s1.end());
138138
s6.insert(s2.begin(), s2.end());
139139
sink(s1);
140-
sink(s2); // tainted [NOT DETECTED]
140+
sink(s2); // tainted
141141
sink(s3);
142-
sink(s4); // tainted [NOT DETECTED]
142+
sink(s4); // tainted
143143
sink(s5);
144-
sink(s6); // tainted [NOT DETECTED]
144+
sink(s6); // tainted
145145
sink(s1.find("abc"));
146-
sink(s2.find("abc")); // tainted [NOT DETECTED]
146+
sink(s2.find("abc")); // tainted
147147
sink(s3.find("abc"));
148-
sink(s4.find("abc")); // tainted [NOT DETECTED]
148+
sink(s4.find("abc")); // tainted
149149
sink(s5.find("abc"));
150-
sink(s6.find("abc")); // tainted [NOT DETECTED]
150+
sink(s6.find("abc")); // tainted
151151

152152
// copy constructors and assignment
153153
std::unordered_set<char *> s7(s2);
154154
std::unordered_set<char *> s8 = s2;
155155
std::unordered_set<char *> s9(s2.begin(), s2.end());
156156
std::unordered_set<char *> s10;
157157
s10 = s2;
158-
sink(s7); // tainted [NOT DETECTED]
159-
sink(s8); // tainted [NOT DETECTED]
158+
sink(s7); // tainted
159+
sink(s8); // tainted
160160
sink(s9); // tainted [NOT DETECTED]
161-
sink(s10); // tainted [NOT DETECTED]
162-
sink(s7.find("abc")); // tainted [NOT DETECTED]
163-
sink(s8.find("abc")); // tainted [NOT DETECTED]
161+
sink(s10); // tainted
162+
sink(s7.find("abc")); // tainted
163+
sink(s8.find("abc")); // tainted
164164
sink(s9.find("abc")); // tainted [NOT DETECTED]
165-
sink(s10.find("abc")); // tainted [NOT DETECTED]
165+
sink(s10.find("abc")); // tainted
166166

167167
// iterators
168168
std::unordered_set<char *>::iterator i1, i2;
@@ -172,7 +172,7 @@ void test_unordered_set()
172172
}
173173
for (i2 = s2.begin(); i2 != s2.end(); i2++)
174174
{
175-
sink(*i2); // tainted [NOT DETECTED]
175+
sink(*i2); // tainted
176176
}
177177

178178
// ranges
@@ -187,43 +187,43 @@ void test_unordered_set()
187187
std::unordered_set<char *> s12, s13, s14, s15;
188188
s12.insert(source());
189189
s15.insert(source());
190-
sink(s12); // tainted [NOT DETECTED]
190+
sink(s12); // tainted
191191
sink(s13);
192192
sink(s14);
193-
sink(s15); // tainted [NOT DETECTED]
193+
sink(s15); // tainted
194194
s12.swap(s13);
195195
s14.swap(s15);
196-
sink(s12);
197-
sink(s13); // tainted [NOT DETECTED]
198-
sink(s14); // tainted [NOT DETECTED]
199-
sink(s15);
196+
sink(s12); // [FALSE POSITIVE]
197+
sink(s13); // tainted
198+
sink(s14); // tainted
199+
sink(s15); // [FALSE POSITIVE]
200200

201201
// merge
202202
std::unordered_set<char *> s16, s17, s18, s19;
203203
s16.insert(source());
204204
s17.insert("abc");
205205
s18.insert("def");
206206
s19.insert(source());
207-
sink(s16); // tainted [NOT DETECTED]
207+
sink(s16); // tainted
208208
sink(s17);
209209
sink(s18);
210-
sink(s19); // tainted [NOT DETECTED]
210+
sink(s19); // tainted
211211
s16.merge(s17);
212212
s18.merge(s19);
213-
sink(s16); // tainted [NOT DETECTED]
213+
sink(s16); // tainted
214214
sink(s17); // tainted [NOT DETECTED]
215215
sink(s18); // tainted [NOT DETECTED]
216-
sink(s19); // tainted [NOT DETECTED]
216+
sink(s19); // tainted
217217

218218
// erase, clear
219219
std::unordered_set<char *> s20;
220220
s20.insert(source());
221221
s20.insert(source());
222-
sink(s20); // tainted [NOT DETECTED]
223-
sink(s20.erase(s20.begin())); // tainted [NOT DETECTED]
224-
sink(s20); // tainted [NOT DETECTED]
222+
sink(s20); // tainted
223+
sink(s20.erase(s20.begin())); // tainted
224+
sink(s20); // tainted
225225
s20.clear();
226-
sink(s20);
226+
sink(s20); // [FALSE POSITIVE]
227227

228228
// emplace, emplace_hint
229229
std::unordered_set<char *> s21, s22;

0 commit comments

Comments
 (0)