Skip to content

Commit eeb84d4

Browse files
committed
C++: Add more test cases for the toctou query.
1 parent 089e4e2 commit eeb84d4

File tree

2 files changed

+259
-0
lines changed

2 files changed

+259
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
| test2.cpp:31:7:31:11 | call to fopen | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:31:13:31:16 | path | filename | test2.cpp:26:6:26:10 | call to fopen | checked |
2+
| test2.cpp:44:7:44:11 | call to fopen | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:44:13:44:16 | path | filename | test2.cpp:44:7:44:11 | call to fopen | checked |
3+
| test2.cpp:61:7:61:11 | call to fopen | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:61:13:61:16 | path | filename | test2.cpp:59:6:59:9 | call to stat | checked |
4+
| test2.cpp:90:7:90:11 | call to fopen | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:90:13:90:16 | path | filename | test2.cpp:88:15:88:17 | foo | checked |
5+
| test2.cpp:155:3:155:7 | call to chmod | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:155:9:155:12 | path | filename | test2.cpp:148:6:148:10 | call to fopen | checked |
6+
| test2.cpp:195:3:195:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:195:10:195:14 | path1 | filename | test2.cpp:193:7:193:12 | call to rename | checked |
7+
| test2.cpp:205:3:205:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:205:10:205:14 | path1 | filename | test2.cpp:201:6:201:11 | call to rename | checked |
8+
| test2.cpp:237:7:237:11 | call to fopen | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test2.cpp:237:13:237:16 | path | filename | test2.cpp:235:6:235:11 | call to access | checked |
19
| test.cpp:21:3:21:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:21:10:21:14 | file1 | filename | test.cpp:19:7:19:12 | call to rename | checked |
210
| test.cpp:35:3:35:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:35:10:35:14 | file1 | filename | test.cpp:32:7:32:12 | call to rename | checked |
311
| test.cpp:49:3:49:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:49:10:49:14 | file1 | filename | test.cpp:47:7:47:12 | call to rename | checked |
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
// More test cases. Some of these are inspired by real-world cases, others are synthetic or variations.
2+
3+
#define NULL 0
4+
5+
typedef struct {} FILE;
6+
typedef struct {
7+
int foo;
8+
} stat_data;
9+
10+
FILE *fopen(const char *filename, const char *mode);
11+
int fclose(FILE *stream);
12+
13+
bool stat(const char *path, stat_data *buf);
14+
void chmod(const char *path, int setting);
15+
bool rename(const char *from, const char *to);
16+
bool remove(const char *path);
17+
18+
bool access(const char *path);
19+
20+
// ---
21+
22+
void test1_1(const char *path)
23+
{
24+
FILE *f = NULL;
25+
26+
f = fopen(path, "r");
27+
28+
if (f == NULL)
29+
{
30+
// retry
31+
f = fopen(path, "r"); // GOOD (this is just trying again) [FALSE POSITIVE]
32+
}
33+
34+
// ...
35+
}
36+
37+
void test1_2(const char *path)
38+
{
39+
FILE *f = NULL;
40+
41+
// try until we succeed
42+
while (f == NULL)
43+
{
44+
f = fopen(path, "r"); // GOOD (this is just trying again) [FALSE POSITIVE]
45+
46+
// ...
47+
}
48+
49+
// ...
50+
}
51+
52+
// ---
53+
54+
void test2_1(const char *path)
55+
{
56+
FILE *f = NULL;
57+
stat_data buf;
58+
59+
if (stat(path, &buf))
60+
{
61+
f = fopen(path, "r"); // BAD
62+
}
63+
64+
// ...
65+
}
66+
67+
void test2_2(const char *path)
68+
{
69+
FILE *f = NULL;
70+
stat_data buf;
71+
72+
stat(path, &buf);
73+
if (buf.foo > 0)
74+
{
75+
f = fopen(path, "r"); // BAD [NOT DETECTED]
76+
}
77+
78+
// ...
79+
}
80+
81+
void test2_3(const char *path)
82+
{
83+
FILE *f = NULL;
84+
stat_data buf;
85+
stat_data *buf_ptr = &buf;
86+
87+
stat(path, buf_ptr);
88+
if (buf_ptr->foo > 0)
89+
{
90+
f = fopen(path, "r"); // BAD
91+
}
92+
93+
// ...
94+
}
95+
96+
bool stat_condition(const stat_data *buf);
97+
bool other_condition();
98+
99+
void test2_4(const char *path)
100+
{
101+
FILE *f = NULL;
102+
stat_data buf;
103+
104+
stat(path, &buf);
105+
if (stat_condition(&buf))
106+
{
107+
f = fopen(path, "r"); // BAD [NOT DETECTED]
108+
}
109+
110+
// ...
111+
}
112+
113+
void test2_5(const char *path)
114+
{
115+
FILE *f = NULL;
116+
stat_data buf;
117+
stat_data *buf_ptr = &buf;
118+
119+
stat(path, buf_ptr);
120+
if (stat_condition(buf_ptr))
121+
{
122+
f = fopen(path, "r"); // BAD [NOT DETECTED]
123+
}
124+
125+
// ...
126+
}
127+
128+
void test2_6(const char *path)
129+
{
130+
FILE *f = NULL;
131+
stat_data buf;
132+
133+
stat(path, &buf);
134+
if (other_condition())
135+
{
136+
f = fopen(path, "r"); // GOOD (does not depend on the result of stat)
137+
}
138+
139+
// ...
140+
}
141+
142+
// ---
143+
144+
void test3_1(const char *path)
145+
{
146+
FILE *f = NULL;
147+
148+
f = fopen(path, "w");
149+
if (f)
150+
{
151+
// ...
152+
153+
fclose(f);
154+
155+
chmod(path, 0); // BAD
156+
}
157+
}
158+
159+
void test3_2(const char *path)
160+
{
161+
FILE *f = NULL;
162+
163+
f = fopen(path, "w");
164+
if (f)
165+
{
166+
// ...
167+
168+
fclose(f);
169+
}
170+
171+
chmod(path, 0); // GOOD (doesn't depend on the fopen)
172+
}
173+
174+
void test3_3(const char *path1, const char *path2)
175+
{
176+
FILE *f = NULL;
177+
178+
f = fopen(path1, "w");
179+
if (f)
180+
{
181+
// ...
182+
183+
fclose(f);
184+
185+
chmod(path2, 0); // GOOD (different file)
186+
}
187+
}
188+
189+
// ---
190+
191+
void test4_1(const char *path1, const char *path2)
192+
{
193+
if (!rename(path1, path2))
194+
{
195+
remove(path1); // BAD
196+
}
197+
}
198+
199+
void test4_2(const char *path1, const char *path2)
200+
{
201+
if (rename(path1, path2))
202+
{
203+
// ...
204+
} else {
205+
remove(path1); // BAD
206+
}
207+
}
208+
209+
void test4_3(const char *path1, const char *path2)
210+
{
211+
if (rename(path1, path2))
212+
{
213+
// ...
214+
}
215+
216+
remove(path1); // GOOD (does not depend on the rename)
217+
}
218+
219+
void test4_4(const char *path1, const char *path2)
220+
{
221+
FILE *f = NULL;
222+
223+
if (rename(path1, path2))
224+
{
225+
f = fopen(path2, "r"); // BAD [NOT DETECTED]
226+
}
227+
}
228+
229+
// ---
230+
231+
void test5_1(const char *path)
232+
{
233+
FILE *f = NULL;
234+
235+
if (access(path))
236+
{
237+
f = fopen(path, "r"); // BAD
238+
}
239+
}
240+
241+
void test5_2(const char *path)
242+
{
243+
FILE *f = NULL;
244+
245+
if (access(path))
246+
{
247+
// ...
248+
}
249+
250+
f = fopen(path, "r"); // GOOD
251+
}

0 commit comments

Comments
 (0)