1 // RUN: %clang_analyze_cc1 -verify %s \
2 // RUN: -triple x86_64-linux-gnu \
3 // RUN: -analyzer-checker=core,unix.Stream,optin.taint \
4 // RUN: -analyzer-checker=debug.ExprInspection
6 #include "Inputs/system-header-simulator-for-simple-stream.h"
10 void clang_analyzer_dump(int);
11 void clang_analyzer_dump_char(char);
12 void clang_analyzer_isTainted(int);
13 void clang_analyzer_warnIfReached(void);
15 // A stream is only tracked by StreamChecker if it results from a call to "fopen".
16 // Otherwise, there is no specific modelling of "fread".
17 void untracked_stream(FILE *fp
) {
19 if (1 == fread(&c
, 1, 1, fp
)) {
20 char p
= c
; // Unknown value but not garbage and not modeled by checker.
22 char p
= c
; // Possibly indeterminate value but not modeled by checker.
26 void fgetc_props_taint(void) {
27 FILE *fp
= fopen("/home/test", "rb+");
29 int c
= fgetc(fp
); // c is tainted.
31 clang_analyzer_isTainted(c
); // expected-warning{{YES}}
37 void fread_props_taint(void) {
38 FILE *fp
= fopen("/home/test", "rb+");
41 int c
= fread(buffer
, 1, 10, fp
); // c is tainted.
43 // If the read failed, then the number of bytes successfully read should be tainted.
44 clang_analyzer_isTainted(c
); // expected-warning{{YES}}
50 void read_one_byte1(void) {
51 FILE *fp
= fopen("/home/test", "rb+");
54 if (1 == fread(&c
, 1, 1, fp
)) {
55 char p
= c
; // Unknown value but not garbage.
56 clang_analyzer_isTainted(p
); // expected-warning{{YES}}
58 char p
= c
; // Possibly indeterminate value but not modeled by checker.
59 clang_analyzer_isTainted(p
); // expected-warning{{YES}}
65 void read_one_byte2(char *buffer
) {
66 FILE *fp
= fopen("/home/test", "rb+");
68 if (1 == fread(buffer
, 1, 1, fp
)) {
69 char p
= buffer
[0]; // Unknown value but not garbage.
70 clang_analyzer_isTainted(p
); // expected-warning{{YES}}
72 char p
= buffer
[0]; // Possibly indeterminate value but not modeled by checker.
73 clang_analyzer_isTainted(p
); // expected-warning{{YES}}
79 void read_one_byte3(char *buffer
) {
81 FILE *fp
= fopen("/home/test", "rb+");
83 // buffer[1] is not mutated by fread and remains not tainted.
84 fread(buffer
, 1, 1, fp
);
86 clang_analyzer_isTainted(p
); // expected-warning{{NO}}
87 clang_analyzer_dump(buffer
[1]); // expected-warning{{10 S32b}}
92 void read_many_bytes(char *buffer
) {
93 FILE *fp
= fopen("/home/test", "rb+");
95 if (42 == fread(buffer
, 1, 42, fp
)) {
96 char p
= buffer
[0]; // Unknown value but not garbage.
97 clang_analyzer_isTainted(p
); // expected-warning{{YES}}
99 char p
= buffer
[0]; // Possibly indeterminate value but not modeled.
100 clang_analyzer_isTainted(p
); // expected-warning{{YES}}
106 void random_access_read1(int index
) {
107 FILE *fp
= fopen("/home/test", "rb+");
110 int success
= 2 == fread(c
+ 1, sizeof(long), 2, fp
);
114 // c[0] is not mutated by fread.
116 char p
= c
[0]; // expected-warning {{Assigned value is garbage or undefined}} We kept the first byte intact.
118 char p
= c
[0]; // expected-warning {{Assigned value is garbage or undefined}} We kept the first byte intact.
124 // Unknown value but not garbage.
125 clang_analyzer_isTainted(c
[1]); // expected-warning {{YES}}
126 clang_analyzer_dump(c
[1]); // expected-warning {{conj_}}
128 // Possibly indeterminate value but not modeled.
129 clang_analyzer_isTainted(c
[1]); // expected-warning {{YES}}
130 clang_analyzer_dump(c
[1]); // expected-warning {{conj_}}
136 long p
= c
[2]; // Unknown value but not garbage.
137 // FIXME: Taint analysis only marks the first byte of a memory region. See getPointeeOf in GenericTaintChecker.cpp.
138 clang_analyzer_isTainted(c
[2]); // expected-warning {{NO}}
139 clang_analyzer_dump(c
[2]); // expected-warning {{conj_}}
141 // Possibly indeterminate value but not modeled.
142 clang_analyzer_isTainted(c
[2]); // expected-warning {{NO}} // FIXME: See above.
143 clang_analyzer_dump(c
[2]); // expected-warning {{conj_}}
148 // c[3] is not mutated by fread.
150 long p
= c
[3]; // expected-warning {{Assigned value is garbage or undefined}}
152 long p
= c
[3]; // expected-warning {{Assigned value is garbage or undefined}}
161 void random_access_read2(int b
) {
162 FILE *fp
= fopen("/home/test", "rb+");
165 int *ptr
= buffer
+ 2;
166 if (5 == fread(ptr
- 1, sizeof(int), 5, fp
)) {
168 int p
= buffer
[1]; // Unknown value but not garbage.
169 clang_analyzer_isTainted(p
); // expected-warning {{YES}}
170 clang_analyzer_dump(p
); // expected-warning {{conj_}}
172 int p
= buffer
[0]; // expected-warning {{Assigned value is garbage or undefined}}
175 int p
= buffer
[0]; // expected-warning {{Assigned value is garbage or undefined}}
181 void random_access_read_symbolic_count(size_t count
) {
182 // Cover a case that used to crash (symbolic count).
186 FILE *fp
= fopen("/home/test", "rb+");
189 fread(c
+ 1, sizeof(long), count
, fp
);
191 // c[0] and c[3] are never mutated by fread, but because "count" is a symbolic value, the checker doesn't know that.
193 clang_analyzer_isTainted(p
); // expected-warning {{NO}}
194 clang_analyzer_dump(p
); // expected-warning {{derived_}}
197 clang_analyzer_isTainted(p
); // expected-warning {{NO}}
198 clang_analyzer_dump(p
); // expected-warning {{derived_}}
201 clang_analyzer_isTainted(p
); // expected-warning {{YES}}
202 clang_analyzer_dump(p
); // expected-warning {{derived_}}
208 void dynamic_random_access_read(int startIndex
) {
209 FILE *fp
= fopen("/home/test", "rb+");
212 // Cannot reason about index.
213 size_t res
= fread(buffer
+ startIndex
, sizeof(long), 5, fp
);
214 long *p
= &buffer
[startIndex
];
217 // If all 5 elements were successfully read, then all 5 elements should be tainted and considered initialized.
219 // FIXME: These should be tainted.
220 clang_analyzer_isTainted((v
= p
[0])); // expected-warning {{NO}}
221 clang_analyzer_isTainted((v
= p
[1])); // expected-warning {{NO}}
222 clang_analyzer_isTainted((v
= p
[2])); // expected-warning {{NO}}
223 clang_analyzer_isTainted((v
= p
[3])); // expected-warning {{NO}}
224 clang_analyzer_isTainted((v
= p
[4])); // expected-warning {{NO}}
225 clang_analyzer_dump((v
= p
[0])); // expected-warning {{conj_}} ok
226 clang_analyzer_dump((v
= p
[1])); // expected-warning {{conj_}} ok
227 clang_analyzer_dump((v
= p
[2])); // expected-warning {{conj_}} ok
228 clang_analyzer_dump((v
= p
[3])); // expected-warning {{conj_}} ok
229 clang_analyzer_dump((v
= p
[4])); // expected-warning {{conj_}} ok
230 clang_analyzer_dump((v
= p
[5])); // expected-warning {{conj_}} FIXME: This should raise an uninit read.
231 } else if (res
== 4) {
232 // If only the first 4 elements were successfully read,
233 // then only the first 4 elements should be tainted and considered initialized.
234 // FIXME: These should be tainted.
235 clang_analyzer_isTainted((v
= p
[0])); // expected-warning {{NO}}
236 clang_analyzer_isTainted((v
= p
[1])); // expected-warning {{NO}}
237 clang_analyzer_isTainted((v
= p
[2])); // expected-warning {{NO}}
238 clang_analyzer_isTainted((v
= p
[3])); // expected-warning {{NO}}
239 clang_analyzer_dump((v
= p
[0])); // expected-warning {{conj_}} ok
240 clang_analyzer_dump((v
= p
[1])); // expected-warning {{conj_}} ok
241 clang_analyzer_dump((v
= p
[2])); // expected-warning {{conj_}} ok
242 clang_analyzer_dump((v
= p
[3])); // expected-warning {{conj_}} ok
243 clang_analyzer_dump((v
= p
[4])); // expected-warning {{conj_}} FIXME: This should raise an uninit read.
245 // Neither 5, or 4 elements were successfully read, so we must have read from 0 up to 3 elements.
246 // FIXME: These should be tainted.
247 clang_analyzer_isTainted((v
= p
[0])); // expected-warning {{NO}}
248 clang_analyzer_isTainted((v
= p
[1])); // expected-warning {{NO}}
249 clang_analyzer_isTainted((v
= p
[2])); // expected-warning {{NO}}
250 clang_analyzer_dump((v
= p
[0])); // expected-warning {{conj_}} ok
251 clang_analyzer_dump((v
= p
[1])); // expected-warning {{conj_}} ok
252 clang_analyzer_dump((v
= p
[2])); // expected-warning {{conj_}} ok
253 clang_analyzer_dump((v
= p
[3])); // expected-warning {{conj_}} FIXME: This should raise an uninit read.
264 void compound_read1(void) {
265 FILE *fp
= fopen("/home/test", "rb+");
267 struct S s
; // s.a is not touched by fread.
268 if (1 == fread(&s
.b
, sizeof(s
.b
), 1, fp
)) {
270 clang_analyzer_isTainted(p
); // expected-warning {{YES}}
271 clang_analyzer_dump(p
); // expected-warning {{conj_}}
274 clang_analyzer_isTainted(p
); // expected-warning {{YES}}
275 clang_analyzer_dump(p
); // expected-warning {{conj_}}
281 void compound_read2(void) {
282 FILE *fp
= fopen("/home/test", "rb+");
284 struct S s
; // s.a is not touched by fread.
285 if (1 == fread(&s
.b
, sizeof(s
.b
), 1, fp
)) {
286 long p
= s
.a
; // expected-warning {{Assigned value is garbage or undefined}}
288 long p
= s
.a
; // expected-warning {{Assigned value is garbage or undefined}}
294 void var_read(void) {
295 FILE *fp
= fopen("/home/test", "rb+");
297 int a
, b
; // 'a' is not touched by fread.
298 if (1 == fread(&b
, sizeof(b
), 1, fp
)) {
299 long p
= a
; // expected-warning{{Assigned value is garbage or undefined}}
301 long p
= a
; // expected-warning{{Assigned value is garbage or undefined}}
307 // When reading a lot of data, invalidating all elements is too time-consuming.
308 // Instead, the knowledge of the whole array is lost.
309 #define MaxInvalidatedElementRegion 64 // See StreamChecker::evalFreadFwrite in StreamChecker.cpp.
310 #define PastMaxComplexity MaxInvalidatedElementRegion + 1
311 void test_large_read(void) {
312 int buffer
[PastMaxComplexity
+ 1];
313 buffer
[PastMaxComplexity
] = 42;
314 FILE *fp
= fopen("/home/test", "rb+");
316 if (buffer
[PastMaxComplexity
] != 42) {
317 clang_analyzer_warnIfReached(); // Unreachable.
319 if (1 == fread(buffer
, sizeof(int), PastMaxComplexity
, fp
)) {
320 if (buffer
[PastMaxComplexity
] != 42) {
321 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
328 void test_small_read(void) {
331 FILE *fp
= fopen("/home/test", "rb+");
333 clang_analyzer_dump(buffer
[5]); // expected-warning{{42 S32b}}
334 if (1 == fread(buffer
, sizeof(int), 5, fp
)) {
335 clang_analyzer_dump(buffer
[5]); // expected-warning{{42 S32b}}
341 void test_partial_elements_read(void) {
342 clang_analyzer_dump(sizeof(int)); // expected-warning {{4 S32b}}
351 FILE *fp
= fopen("/home/test", "rb+");
353 // 3*5: 15 bytes read; which is not exactly 4 integers, but we still invalidate the first 4 ints.
354 if (5 == fread(buffer
+ 1, 3, 5, fp
)) {
355 clang_analyzer_dump(buffer
[0]); // expected-warning{{1 S32b}}
356 clang_analyzer_dump(buffer
[1]); // expected-warning{{conj_}}
357 clang_analyzer_dump(buffer
[2]); // expected-warning{{conj_}}
358 clang_analyzer_dump(buffer
[3]); // expected-warning{{conj_}}
359 clang_analyzer_dump(buffer
[4]); // expected-warning{{conj_}}
360 clang_analyzer_dump(buffer
[5]); // expected-warning{{6 S32b}}
362 char *c
= (char*)buffer
;
363 clang_analyzer_dump(c
[4+12]); // expected-warning{{conj_}} 16th byte of buffer, which is the beginning of the 4th 'int' in the buffer.
365 // FIXME: The store should have returned a partial binding for the 17th byte of the buffer, which is the 2nd byte of the previous int.
366 // This byte should have been initialized by the 'fread' earlier. However, the Store lies to us and says it's uninitialized.
367 clang_analyzer_dump(c
[4+13]); // expected-warning{{1st function call argument is an uninitialized value}} should be initialized.
368 clang_analyzer_dump(c
[4+16]); // This should be the first byte that 'fread' leaves uninitialized. This should raise the uninit read diag.
370 clang_analyzer_dump(buffer
[0]); // expected-warning{{1 S32b}} ok
371 clang_analyzer_dump(buffer
[1]); // expected-warning{{conj_}} ok
372 clang_analyzer_dump(buffer
[2]); // expected-warning{{conj_}} ok
373 clang_analyzer_dump(buffer
[3]); // expected-warning{{conj_}} ok
374 clang_analyzer_dump(buffer
[4]); // expected-warning{{conj_}} ok, but an uninit warning would be also fine.
375 clang_analyzer_dump(buffer
[5]); // expected-warning{{6 S32b}} ok
376 clang_analyzer_dump(buffer
[6]); // expected-warning{{1st function call argument is an uninitialized value}} ok
382 void test_whole_elements_read(void) {
383 clang_analyzer_dump(sizeof(int)); // expected-warning {{4 S32b}}
389 FILE *fp
= fopen("/home/test", "rb+");
391 // 3*20: 60 bytes read; which is basically 15 integers.
392 if (20 == fread(buffer
+ 1, 3, 20, fp
)) {
393 clang_analyzer_dump(buffer
[0]); // expected-warning{{1 S32b}}
394 clang_analyzer_dump(buffer
[15]); // expected-warning{{conj_}}
395 clang_analyzer_dump(buffer
[16]); // expected-warning{{3 S32b}}
396 clang_analyzer_dump(buffer
[17]); // expected-warning{{1st function call argument is an uninitialized value}}
398 clang_analyzer_dump(buffer
[0]); // expected-warning{{1 S32b}}
399 clang_analyzer_dump(buffer
[15]); // expected-warning{{conj_}}
400 clang_analyzer_dump(buffer
[16]); // expected-warning{{3 S32b}}
401 clang_analyzer_dump(buffer
[17]); // expected-warning{{1st function call argument is an uninitialized value}}
407 void test_unaligned_start_read(void) {
408 clang_analyzer_dump(sizeof(int)); // expected-warning {{4 S32b}}
414 char *asChar
= (char*)buffer
;
416 FILE *fp
= fopen("/home/test", "rb+");
418 // We have an 'int' binding at offset 0 of value 3.
419 // We read 4 bytes at byte offset: 1,2,3,4.
420 if (4 == fread(asChar
+ 1, 1, 4, fp
)) {
421 clang_analyzer_dump(buffer
[0]); // expected-warning{{3 S32b}} FIXME: The int binding should have been partially overwritten by the read call. This definitely should not be 3.
422 clang_analyzer_dump(buffer
[1]); // expected-warning{{conj_}}
423 clang_analyzer_dump(buffer
[2]); // expected-warning{{5 S32b}}
425 clang_analyzer_dump_char(asChar
[0]); // expected-warning{{3 S8b}} This is technically true assuming x86 (little-endian) architecture.
426 clang_analyzer_dump_char(asChar
[1]); // expected-warning{{conj_}} 1
427 clang_analyzer_dump_char(asChar
[2]); // expected-warning{{conj_}} 2
428 clang_analyzer_dump_char(asChar
[3]); // expected-warning{{conj_}} 3
429 clang_analyzer_dump_char(asChar
[4]); // expected-warning{{conj_}} 4
430 clang_analyzer_dump_char(asChar
[5]); // expected-warning{{1st function call argument is an uninitialized value}}
432 clang_analyzer_dump(buffer
[0]); // expected-warning{{3 S32b}} FIXME: The int binding should have been partially overwritten by the read call. This definitely should not be 3.
433 clang_analyzer_dump(buffer
[1]); // expected-warning{{conj_}}
434 clang_analyzer_dump(buffer
[2]); // expected-warning{{5 S32b}}
436 clang_analyzer_dump_char(asChar
[0]); // expected-warning{{3 S8b}} This is technically true assuming x86 (little-endian) architecture.
437 clang_analyzer_dump_char(asChar
[1]); // expected-warning{{conj_}} 1
438 clang_analyzer_dump_char(asChar
[2]); // expected-warning{{conj_}} 2
439 clang_analyzer_dump_char(asChar
[3]); // expected-warning{{conj_}} 3
440 clang_analyzer_dump_char(asChar
[4]); // expected-warning{{conj_}} 4
441 clang_analyzer_dump_char(asChar
[5]); // expected-warning{{1st function call argument is an uninitialized value}}
447 void no_crash_if_count_is_negative(long l
, long r
, unsigned char *buffer
) {
448 FILE *fp
= fopen("path", "r");
451 fread(buffer
, 1, l
* r
, fp
); // no-crash
457 void no_crash_if_size_is_negative(long l
, long r
, unsigned char *buffer
) {
458 FILE *fp
= fopen("path", "r");
461 fread(buffer
, l
* r
, 1, fp
); // no-crash
467 void no_crash_if_size_and_count_are_negative(long l
, long r
, unsigned char *buffer
) {
468 FILE *fp
= fopen("path", "r");
471 fread(buffer
, l
* r
, l
* r
, fp
); // no-crash