1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,debug.ExprInspection -verify %s
2
3 #include "Inputs/system-header-simulator.h"
4 #include "Inputs/system-header-simulator-for-malloc.h"
5 #include "Inputs/system-header-simulator-for-valist.h"
6
7 void clang_analyzer_eval(int);
8 void clang_analyzer_dump_int(int);
9 void clang_analyzer_dump_ptr(void*);
10 void clang_analyzer_warnIfReached();
11
test_getline_null_lineptr()12 void test_getline_null_lineptr() {
13 FILE *F1 = tmpfile();
14 if (!F1)
15 return;
16
17 char **buffer = NULL;
18 size_t n = 0;
19 getline(buffer, &n, F1); // expected-warning {{Line pointer might be NULL}}
20 fclose(F1);
21 }
22
test_getline_null_size()23 void test_getline_null_size() {
24 FILE *F1 = tmpfile();
25 if (!F1)
26 return;
27 char *buffer = NULL;
28 getline(&buffer, NULL, F1); // expected-warning {{Size pointer might be NULL}}
29 fclose(F1);
30 }
31
test_getline_null_buffer_size_gt0()32 void test_getline_null_buffer_size_gt0() {
33 FILE *F1 = tmpfile();
34 if (!F1)
35 return;
36 char *buffer = NULL;
37 size_t n = 8;
38 getline(&buffer, &n, F1); // ok since posix 2018
39 free(buffer);
40 fclose(F1);
41 }
42
test_getline_null_buffer_size_gt0_2(size_t n)43 void test_getline_null_buffer_size_gt0_2(size_t n) {
44 FILE *F1 = tmpfile();
45 if (!F1)
46 return;
47 char *buffer = NULL;
48 if (n > 0) {
49 getline(&buffer, &n, F1); // ok since posix 2018
50 }
51 free(buffer);
52 fclose(F1);
53 }
54
test_getline_null_buffer_unknown_size(size_t n)55 void test_getline_null_buffer_unknown_size(size_t n) {
56 FILE *F1 = tmpfile();
57 if (!F1)
58 return;
59 char *buffer = NULL;
60
61 getline(&buffer, &n, F1); // ok
62 fclose(F1);
63 free(buffer);
64 }
65
test_getline_null_buffer_undef_size()66 void test_getline_null_buffer_undef_size() {
67 FILE *F1 = tmpfile();
68 if (!F1)
69 return;
70
71 char *buffer = NULL;
72 size_t n;
73
74 getline(&buffer, &n, F1); // ok since posix 2018
75 fclose(F1);
76 free(buffer);
77 }
78
test_getline_buffer_size_0()79 void test_getline_buffer_size_0() {
80 FILE *F1 = tmpfile();
81 if (!F1)
82 return;
83
84 char *buffer = malloc(10);
85 size_t n = 0;
86 if (buffer != NULL)
87 getline(&buffer, &n, F1); // ok, the buffer is enough for 0 character
88 fclose(F1);
89 free(buffer);
90 }
91
test_getline_buffer_bad_size()92 void test_getline_buffer_bad_size() {
93 FILE *F1 = tmpfile();
94 if (!F1)
95 return;
96
97 char *buffer = malloc(10);
98 size_t n = 100;
99 if (buffer != NULL)
100 getline(&buffer, &n, F1); // expected-warning {{The buffer from the first argument is smaller than the size specified by the second parameter}}
101 fclose(F1);
102 free(buffer);
103 }
104
test_getline_buffer_smaller_size()105 void test_getline_buffer_smaller_size() {
106 FILE *F1 = tmpfile();
107 if (!F1)
108 return;
109
110 char *buffer = malloc(100);
111 size_t n = 10;
112 if (buffer != NULL)
113 getline(&buffer, &n, F1); // ok, there is enough space for 10 characters
114 fclose(F1);
115 free(buffer);
116 }
117
test_getline_buffer_undef_size()118 void test_getline_buffer_undef_size() {
119 FILE *F1 = tmpfile();
120 if (!F1)
121 return;
122
123 char *buffer = malloc(100);
124 size_t n;
125 if (buffer != NULL)
126 getline(&buffer, &n, F1); // expected-warning {{The buffer from the first argument is not NULL, but the size specified by the second parameter is undefined}}
127 fclose(F1);
128 free(buffer);
129 }
130
131
test_getline_null_buffer()132 void test_getline_null_buffer() {
133 FILE *F1 = tmpfile();
134 if (!F1)
135 return;
136 char *buffer = NULL;
137 size_t n = 0;
138 ssize_t r = getline(&buffer, &n, F1);
139 // getline returns -1 on failure, number of char reads on success (>= 0)
140 if (r < -1) {
141 clang_analyzer_warnIfReached(); // must not happen
142 } else {
143 // The buffer could be allocated both on failure and success
144 clang_analyzer_dump_int(n); // expected-warning {{conj_$}}
145 clang_analyzer_dump_ptr(buffer); // expected-warning {{conj_$}}
146 }
147 free(buffer);
148 fclose(F1);
149 }
150
test_getdelim_null_size()151 void test_getdelim_null_size() {
152 FILE *F1 = tmpfile();
153 if (!F1)
154 return;
155 char *buffer = NULL;
156 getdelim(&buffer, NULL, ',', F1); // expected-warning {{Size pointer might be NULL}}
157 fclose(F1);
158 }
159
test_getdelim_null_buffer_size_gt0()160 void test_getdelim_null_buffer_size_gt0() {
161 FILE *F1 = tmpfile();
162 if (!F1)
163 return;
164 char *buffer = NULL;
165 size_t n = 8;
166 getdelim(&buffer, &n, ';', F1); // ok since posix 2018
167 free(buffer);
168 fclose(F1);
169 }
170
test_getdelim_null_buffer_size_gt0_2(size_t n)171 void test_getdelim_null_buffer_size_gt0_2(size_t n) {
172 FILE *F1 = tmpfile();
173 if (!F1)
174 return;
175 char *buffer = NULL;
176 if (n > 0) {
177 getdelim(&buffer, &n, ' ', F1); // ok since posix 2018
178 }
179 free(buffer);
180 fclose(F1);
181 }
182
test_getdelim_null_buffer_unknown_size(size_t n)183 void test_getdelim_null_buffer_unknown_size(size_t n) {
184 FILE *F1 = tmpfile();
185 if (!F1)
186 return;
187 char *buffer = NULL;
188 getdelim(&buffer, &n, '-', F1); // ok
189 fclose(F1);
190 free(buffer);
191 }
192
test_getdelim_null_buffer()193 void test_getdelim_null_buffer() {
194 FILE *F1 = tmpfile();
195 if (!F1)
196 return;
197 char *buffer = NULL;
198 size_t n = 0;
199 ssize_t r = getdelim(&buffer, &n, '\r', F1);
200 // getdelim returns -1 on failure, number of char reads on success (>= 0)
201 if (r < -1) {
202 clang_analyzer_warnIfReached(); // must not happen
203 }
204 else {
205 // The buffer could be allocated both on failure and success
206 clang_analyzer_dump_int(n); // expected-warning {{conj_$}}
207 clang_analyzer_dump_ptr(buffer); // expected-warning {{conj_$}}
208 }
209 free(buffer);
210 fclose(F1);
211 }
212
test_getline_while()213 void test_getline_while() {
214 FILE *file = fopen("file.txt", "r");
215 if (file == NULL) {
216 return;
217 }
218
219 char *line = NULL;
220 size_t len = 0;
221 ssize_t read;
222
223 while ((read = getline(&line, &len, file)) != -1) {
224 printf("%s\n", line);
225 }
226
227 free(line);
228 fclose(file);
229 }
230
test_getline_return_check()231 void test_getline_return_check() {
232 FILE *file = fopen("file.txt", "r");
233 if (file == NULL) {
234 return;
235 }
236
237 char *line = NULL;
238 size_t len = 0;
239 ssize_t r = getline(&line, &len, file);
240
241 if (r != -1) {
242 if (line[0] == '\0') {} // ok
243 }
244 free(line);
245 fclose(file);
246 }
247
test_getline_clear_eof()248 void test_getline_clear_eof() {
249 FILE *file = fopen("file.txt", "r");
250 if (file == NULL) {
251 return;
252 }
253
254 size_t n = 10;
255 char *buffer = malloc(n);
256 ssize_t read = fread(buffer, n, 1, file);
257 if (feof(file)) {
258 clearerr(file);
259 getline(&buffer, &n, file); // ok
260 }
261 fclose(file);
262 free(buffer);
263 }
264
test_getline_not_null(char ** buffer,size_t * size)265 void test_getline_not_null(char **buffer, size_t *size) {
266 FILE *file = fopen("file.txt", "r");
267 if (file == NULL) {
268 return;
269 }
270
271 getline(buffer, size, file);
272 fclose(file);
273
274 if (size == NULL || buffer == NULL) {
275 clang_analyzer_warnIfReached(); // must not happen
276 }
277 }
278
test_getline_size_constraint(size_t size)279 void test_getline_size_constraint(size_t size) {
280 FILE *file = fopen("file.txt", "r");
281 if (file == NULL) {
282 return;
283 }
284
285 size_t old_size = size;
286 char *buffer = malloc(10);
287 if (buffer != NULL) {
288 ssize_t r = getline(&buffer, &size, file);
289 if (r >= 0) {
290 // Since buffer has a size of 10, old_size must be less than or equal to 10.
291 // Otherwise, there would be UB.
292 clang_analyzer_eval(old_size <= 10); // expected-warning{{TRUE}}
293 }
294 }
295 fclose(file);
296 free(buffer);
297 }
298
test_getline_negative_buffer()299 void test_getline_negative_buffer() {
300 FILE *file = fopen("file.txt", "r");
301 if (file == NULL) {
302 return;
303 }
304
305 char *buffer = NULL;
306 size_t n = -1;
307 getline(&buffer, &n, file); // ok since posix 2018
308 free(buffer);
309 fclose(file);
310 }
311
test_getline_negative_buffer_2(char * buffer)312 void test_getline_negative_buffer_2(char *buffer) {
313 FILE *file = fopen("file.txt", "r");
314 if (file == NULL) {
315 return;
316 }
317
318 size_t n = -1;
319 (void)getline(&buffer, &n, file); // ok
320 free(buffer);
321 fclose(file);
322 }
323