blob: af43c4b03c0e702041fa5f6220ee526d8124e16b (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
//===----------------------------------------------------------------------===
// Declarations
//===----------------------------------------------------------------------===
// Some functions are so similar to each other that they follow the same code
// path, such as memcpy and __memcpy_chk, or memcmp and bcmp. If VARIANT is
// defined, make sure to use the variants instead to make sure they are still
// checked by the analyzer.
// Some functions are implemented as builtins. These should be #defined as
// BUILTIN(f), which will prepend "__builtin_" if USE_BUILTINS is defined.
// Functions that have variants and are also availabe as builtins should be
// declared carefully! See memcpy() for an example.
#ifdef USE_BUILTINS
# define BUILTIN(f) __builtin_ ## f
#else /* USE_BUILTINS */
# define BUILTIN(f) f
#endif /* USE_BUILTINS */
typedef typeof(sizeof(int)) size_t;
//===----------------------------------------------------------------------===
// strlen()
//===----------------------------------------------------------------------===
#define strlen BUILTIN(strlen)
size_t strlen(const char *s);
void strlen_constant0() {
if (strlen("123") != 3)
(void)*(char*)0; // no-warning
}
void strlen_constant1() {
const char *a = "123";
if (strlen(a) != 3)
(void)*(char*)0; // no-warning
}
void strlen_constant2(char x) {
char a[] = "123";
if (strlen(a) != 3)
(void)*(char*)0; // no-warning
a[0] = x;
if (strlen(a) != 3)
(void)*(char*)0; // expected-warning{{null}}
}
size_t strlen_null() {
return strlen(0); // expected-warning{{Null pointer argument in call to byte string function}}
}
size_t strlen_fn() {
return strlen((char*)&strlen_fn); // expected-warning{{Argument to byte string function is the address of the function 'strlen_fn', which is not a null-terminated string}}
}
size_t strlen_nonloc() {
label:
return strlen((char*)&&label); // expected-warning{{Argument to byte string function is the address of the label 'label', which is not a null-terminated string}}
}
void strlen_subregion() {
struct two_strings { char a[2], b[2] };
extern void use_two_strings(struct two_strings *);
struct two_strings z;
use_two_strings(&z);
size_t a = strlen(z.a);
z.b[0] = 5;
size_t b = strlen(z.a);
if (a == 0 && b != 0)
(void)*(char*)0; // expected-warning{{never executed}}
use_two_strings(&z);
size_t c = strlen(z.a);
if (a == 0 && c != 0)
(void)*(char*)0; // expected-warning{{null}}
}
extern void use_string(char *);
void strlen_argument(char *x) {
size_t a = strlen(x);
size_t b = strlen(x);
if (a == 0 && b != 0)
(void)*(char*)0; // expected-warning{{never executed}}
use_string(x);
size_t c = strlen(x);
if (a == 0 && c != 0)
(void)*(char*)0; // expected-warning{{null}}
}
extern char global_str[];
void strlen_global() {
size_t a = strlen(global_str);
size_t b = strlen(global_str);
if (a == 0 && b != 0)
(void)*(char*)0; // expected-warning{{never executed}}
// Call a function with unknown effects, which should invalidate globals.
use_string(0);
size_t c = strlen(global_str);
if (a == 0 && c != 0)
(void)*(char*)0; // expected-warning{{null}}
}
void strlen_indirect(char *x) {
size_t a = strlen(x);
char *p = x;
char **p2 = &p;
size_t b = strlen(x);
if (a == 0 && b != 0)
(void)*(char*)0; // expected-warning{{never executed}}
extern void use_string_ptr(char*const*);
use_string_ptr(p2);
size_t c = strlen(x);
if (a == 0 && c != 0)
(void)*(char*)0; // expected-warning{{null}}
}
void strlen_liveness(const char *x) {
if (strlen(x) < 5)
return;
if (strlen(x) < 5)
(void)*(char*)0; // no-warning
}
|