1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #if !defined(__clang__)
6 #error "Non-clang isn't supported"
7 #endif
8
9 // Clang compile-time and run-time tests for glibc FORTIFY.
10 //
11 // This file is compiled in two configurations ways to give us a sane set of
12 // tests for clang's FORTIFY implementation.
13 //
14 // One configuration uses clang's diagnostic consumer
15 // (https://clang.llvm.org/doxygen/classclang_1_1VerifyDiagnosticConsumer.html#details)
16 // to check diagnostics (e.g. the expected-* comments everywhere).
17 //
18 // The other configuration builds this file such that the resultant object file
19 // exports a function named test_fortify_1 or test_fortify_2, depending on the
20 // FORTIFY level we're using. These are called by clang_fortify_driver.cpp.
21 //
22 // Please note that this test does things like leaking memory. That's WAI.
23
24 // Silence all "from 'diagnose_if'" `note`s from anywhere, including headers;
25 // they're uninteresting for this test case, and their line numbers may change
26 // over time.
27 // expected-note@* 0+{{from 'diagnose_if'}}
28 //
29 // Similarly, there are a few overload tricks we have to emit errors. Ignore any
30 // notes from those.
31 // expected-note@* 0+{{candidate function}}
32 // expected-note@* 0+{{has been explicitly marked unavailable}}
33
34 // Must come before stdlib.h
35 #include <limits.h>
36
37 #include <err.h>
38 #include <fcntl.h>
39 #include <mqueue.h>
40 #include <poll.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/socket.h>
45 #include <sys/wait.h>
46 #include <syslog.h>
47 #include <unistd.h>
48 #include <vector>
49 #include <wchar.h>
50
51 #include "clang-fortify-common.h"
52
53 // We're going to use deprecated APIs here (e.g. getwd). That's OK.
54 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
55
56 #ifndef _FORTIFY_SOURCE
57 #error "_FORTIFY_SOURCE must be defined"
58 #endif
59
60 /////////////////// Test infrastructure; nothing to see here ///////////////////
61
62 // GTest doesn't seem to have an EXPECT_NO_DEATH equivalent, and this all seems
63 // easy enough to hand-roll in a simple environment.
64
65 // Failures get stored here.
66 static std::vector<Failure> *failures;
67
68 template <typename Fn>
ForkAndExpect(int line,const char * message,Fn && F,bool expect_death)69 static void ForkAndExpect(int line, const char *message, Fn &&F,
70 bool expect_death) {
71 fprintf(stderr, "Running %s... (expected to %s)\n", message,
72 expect_death ? "die" : "not die");
73
74 int pid = fork();
75 if (pid == -1)
76 err(1, "Failed to fork() a subproc");
77
78 if (pid == 0) {
79 F();
80 exit(0);
81 }
82
83 int status;
84 if (waitpid(pid, &status, 0) == -1)
85 err(1, "Failed to wait on child (pid %d)", pid);
86
87 bool died = WIFSIGNALED(status) || WEXITSTATUS(status) != 0;
88 if (died != expect_death) {
89 fprintf(stderr, "Check `%s` (at line %d) %s\n", message, line,
90 expect_death ? "failed to die" : "died");
91 failures->push_back({line, message, expect_death});
92 }
93 }
94
95 #define FORK_AND_EXPECT(x, die) ForkAndExpect(__LINE__, #x, [&] { (x); }, die)
96
97 // EXPECT_NO_DEATH forks so that the test remains alive on a bug, and so that
98 // the environment doesn't get modified on no bug. (Environment modification is
99 // especially tricky to deal with given the *_STRUCT variants below.)
100 #define EXPECT_NO_DEATH(x) FORK_AND_EXPECT(x, false)
101 #define EXPECT_DEATH(x) FORK_AND_EXPECT(x, true)
102
103 // Expecting death, but only if we're doing a "strict" struct-checking mode.
104 #if _FORTIFY_SOURCE > 1
105 #define EXPECT_DEATH_STRUCT(x) EXPECT_DEATH(x)
106 #else
107 #define EXPECT_DEATH_STRUCT(x) EXPECT_NO_DEATH(x)
108 #endif
109
110 //////////////////////////////// FORTIFY tests! ////////////////////////////////
111
112 // FIXME(gbiv): glibc shouldn't #define this with FORTIFY on.
113 #undef mempcpy
114
115 const static int kBogusFD = -1;
116
TestString()117 static void TestString() {
118 char small_buffer[8] = {};
119
120 {
121 char large_buffer[sizeof(small_buffer) + 1] = {};
122 // expected-warning@+1{{called with bigger length than the destination}}
123 EXPECT_DEATH(memcpy(small_buffer, large_buffer, sizeof(large_buffer)));
124 // expected-warning@+1{{called with bigger length than the destination}}
125 EXPECT_DEATH(memmove(small_buffer, large_buffer, sizeof(large_buffer)));
126 // expected-warning@+1{{called with bigger length than the destination}}
127 EXPECT_DEATH(mempcpy(small_buffer, large_buffer, sizeof(large_buffer)));
128 // expected-warning@+1{{called with bigger length than the destination}}
129 EXPECT_DEATH(memset(small_buffer, 0, sizeof(large_buffer)));
130 // expected-warning@+1{{transposed parameters}}
131 memset(small_buffer, sizeof(small_buffer), 0);
132 // expected-warning@+1{{called with bigger length than the destination}}
133 EXPECT_DEATH(bcopy(large_buffer, small_buffer, sizeof(large_buffer)));
134 // expected-warning@+1{{called with bigger length than the destination}}
135 EXPECT_DEATH(bzero(small_buffer, sizeof(large_buffer)));
136 }
137
138 {
139 const char large_string[] = "Hello!!!";
140 _Static_assert(sizeof(large_string) > sizeof(small_buffer), "");
141
142 // expected-warning@+1{{destination buffer will always be overflown}}
143 EXPECT_DEATH(strcpy(small_buffer, large_string));
144 // expected-warning@+1{{destination buffer will always be overflown}}
145 EXPECT_DEATH(stpcpy(small_buffer, large_string));
146 // expected-warning@+1{{called with bigger length than the destination}}
147 EXPECT_DEATH(strncpy(small_buffer, large_string, sizeof(large_string)));
148 // expected-warning@+1{{called with bigger length than the destination}}
149 EXPECT_DEATH(stpncpy(small_buffer, large_string, sizeof(large_string)));
150 // expected-warning@+1{{destination buffer will always be overflown}}
151 EXPECT_DEATH(strcat(small_buffer, large_string));
152 // expected-warning@+1{{destination buffer will always be overflown}}
153 EXPECT_DEATH(strncat(small_buffer, large_string, sizeof(large_string)));
154 }
155
156 {
157 struct {
158 char tiny_buffer[4];
159 char tiny_buffer2[4];
160 } split = {};
161
162 EXPECT_NO_DEATH(memcpy(split.tiny_buffer, &split, sizeof(split)));
163 EXPECT_NO_DEATH(memcpy(split.tiny_buffer, &split, sizeof(split)));
164 EXPECT_NO_DEATH(memmove(split.tiny_buffer, &split, sizeof(split)));
165 EXPECT_NO_DEATH(mempcpy(split.tiny_buffer, &split, sizeof(split)));
166 EXPECT_NO_DEATH(memset(split.tiny_buffer, 0, sizeof(split)));
167
168 EXPECT_NO_DEATH(bcopy(&split, split.tiny_buffer, sizeof(split)));
169 EXPECT_NO_DEATH(bzero(split.tiny_buffer, sizeof(split)));
170
171 const char small_string[] = "Hi!!";
172 _Static_assert(sizeof(small_string) > sizeof(split.tiny_buffer), "");
173
174 #if _FORTIFY_SOURCE > 1
175 // expected-warning@+2{{destination buffer will always be overflown}}
176 #endif
177 EXPECT_DEATH_STRUCT(strcpy(split.tiny_buffer, small_string));
178
179 #if _FORTIFY_SOURCE > 1
180 // expected-warning@+2{{destination buffer will always be overflown}}
181 #endif
182 EXPECT_DEATH_STRUCT(stpcpy(split.tiny_buffer, small_string));
183
184 #if _FORTIFY_SOURCE > 1
185 // expected-warning@+2{{called with bigger length than the destination}}
186 #endif
187 EXPECT_DEATH_STRUCT(
188 strncpy(split.tiny_buffer, small_string, sizeof(small_string)));
189
190 #if _FORTIFY_SOURCE > 1
191 // expected-warning@+2{{called with bigger length than the destination}}
192 #endif
193 EXPECT_DEATH_STRUCT(
194 stpncpy(split.tiny_buffer, small_string, sizeof(small_string)));
195
196 #if _FORTIFY_SOURCE > 1
197 // expected-warning@+2{{destination buffer will always be overflown}}
198 #endif
199 EXPECT_DEATH_STRUCT(strcat(split.tiny_buffer, small_string));
200
201 #if _FORTIFY_SOURCE > 1
202 // expected-warning@+2{{destination buffer will always be overflown}}
203 #endif
204 EXPECT_DEATH_STRUCT(
205 strncat(split.tiny_buffer, small_string, sizeof(small_string)));
206 }
207 }
208
209 // Since these emit hard errors, it's sort of hard to run them...
210 #ifdef COMPILATION_TESTS
211 namespace compilation_tests {
testFcntl()212 static void testFcntl() {
213 // FIXME(gbiv): Need to fix these; they got dropped.
214 #if 0
215 // expected-error@+1{{either with 2 or 3 arguments, not more}}
216 #endif
217 open("/", 0, 0, 0);
218 #if 0
219 // expected-error@+1{{either with 2 or 3 arguments, not more}}
220 #endif
221 open64("/", 0, 0, 0);
222 // expected-error@+1{{either with 3 or 4 arguments, not more}}
223 openat(0, "/", 0, 0, 0);
224 // expected-error@+1{{either with 3 or 4 arguments, not more}}
225 openat64(0, "/", 0, 0, 0);
226
227 // expected-error@+1{{needs 3 arguments}}
228 open("/", O_CREAT);
229 // expected-error@+1{{needs 3 arguments}}
230 open("/", O_TMPFILE);
231 // expected-error@+1{{needs 3 arguments}}
232 open64("/", O_CREAT);
233 // expected-error@+1{{needs 3 arguments}}
234 open64("/", O_TMPFILE);
235 // expected-error@+1{{needs 4 arguments}}
236 openat(0, "/", O_CREAT);
237 // expected-error@+1{{needs 4 arguments}}
238 openat(0, "/", O_TMPFILE);
239 // expected-error@+1{{needs 4 arguments}}
240 openat64(0, "/", O_CREAT);
241 // expected-error@+1{{needs 4 arguments}}
242 openat64(0, "/", O_TMPFILE);
243
244 // Superfluous modes are sometimes bugs, but not often enough to complain
245 // about, apparently.
246 }
247
testMqueue()248 static void testMqueue() {
249 // FIXME(gbiv): remove mq_open's FORTIFY'ed body from glibc...
250
251 // expected-error@+1{{with 2 or 4 arguments}}
252 mq_open("/", 0, 0);
253 // expected-error@+1{{with 2 or 4 arguments}}
254 mq_open("/", 0, 0, 0, 0);
255
256 // expected-error@+1{{needs 4 arguments}}
257 mq_open("/", O_CREAT);
258 }
259
testFormatStrings()260 static void testFormatStrings() {
261 const auto unsigned_value = std::declval<unsigned long long>();
262 const auto *unknown_string = std::declval<const char *>();
263 const auto va = std::declval<va_list>();
264
265 {
266 auto some_fd = std::declval<int>();
267 // expected-warning@+1{{format specifies type 'int'}}
268 dprintf(some_fd, "%d", unsigned_value);
269 // expected-warning@+1{{format string is not a string literal}}
270 dprintf(some_fd, unknown_string, unsigned_value);
271 // expected-warning@+1{{format string is not a string literal}}
272 vdprintf(1, unknown_string, va);
273 }
274
275 {
276 auto *retval = std::declval<char *>();
277 // expected-warning@+2{{ignoring return value}}
278 // expected-warning@+1{{format specifies type 'int'}}
279 asprintf(&retval, "%d", unsigned_value);
280 // expected-warning@+2{{ignoring return value}}
281 // expected-warning@+1{{format string is not a string literal}}
282 asprintf(&retval, unknown_string, unsigned_value);
283 // expected-warning@+2{{ignoring return value}}
284 // expected-warning@+1{{format string is not a string literal}}
285 vasprintf(&retval, unknown_string, va);
286 }
287
288 {
289 auto *obs = std::declval<obstack *>();
290 // expected-warning@+1{{format specifies type 'int'}}
291 obstack_printf(obs, "%d", unsigned_value);
292 // expected-warning@+1{{format string is not a string literal}}
293 obstack_printf(obs, unknown_string, unsigned_value);
294 // expected-warning@+1{{format string is not a string literal}}
295 obstack_vprintf(obs, unknown_string, va);
296 }
297
298 // expected-warning@+1{{format specifies type 'int'}}
299 syslog(0, "%d", unsigned_value);
300 // expected-warning@+1{{format string is not a string literal}}
301 syslog(0, unknown_string, unsigned_value);
302 // expected-warning@+1{{format string is not a string literal}}
303 vsyslog(0, unknown_string, va);
304
305 {
306 auto *file = std::declval<FILE *>();
307 // expected-warning@+1{{format specifies type 'int'}}
308 fprintf(file, "%d", unsigned_value);
309 // expected-warning@+1{{format string is not a string literal}}
310 fprintf(file, unknown_string, unsigned_value);
311 // expected-warning@+1{{format string is not a string literal}}
312 vfprintf(file, unknown_string, va);
313 }
314
315 // expected-warning@+1{{format specifies type 'int'}}
316 printf("%d", unsigned_value);
317 // expected-warning@+1{{format string is not a string literal}}
318 printf(unknown_string, unsigned_value);
319 // expected-warning@+1{{format string is not a string literal}}
320 vprintf(unknown_string, va);
321
322 {
323 char buf[128];
324 // expected-warning@+1{{format specifies type 'int'}}
325 sprintf(buf, "%d", unsigned_value);
326 // expected-warning@+1{{format string is not a string literal}}
327 sprintf(buf, unknown_string, unsigned_value);
328 // expected-warning@+1{{format string is not a string literal}}
329 sprintf(buf, unknown_string, va);
330
331 // expected-warning@+1{{format specifies type 'int'}}
332 snprintf(buf, sizeof(buf), "%d", unsigned_value);
333 // expected-warning@+1{{format string is not a string literal}}
334 snprintf(buf, sizeof(buf), unknown_string, unsigned_value);
335 // expected-warning@+1{{format string is not a string literal}}
336 vsnprintf(buf, sizeof(buf), unknown_string, va);
337 }
338
339 // Note that glibc doesn't try to specify __format__ attrs for wchar printf
340 // functions, so we don't check for that.
341 }
342 } // namespace compilation_tests
343 #endif
344
TestPoll()345 static void TestPoll() {
346 struct pollfd invalid_poll_fd = {kBogusFD, 0, 0};
347 {
348 struct pollfd few_fds[] = {invalid_poll_fd, invalid_poll_fd};
349 // expected-warning@+1{{fds buffer too small}}
350 EXPECT_DEATH(poll(few_fds, 3, 0));
351 // expected-warning@+1{{fds buffer too small}}
352 EXPECT_DEATH(ppoll(few_fds, 3, 0, 0));
353 }
354
355 {
356 struct {
357 struct pollfd few[2];
358 struct pollfd extra[1];
359 } fds = {{invalid_poll_fd, invalid_poll_fd}, {invalid_poll_fd}};
360 _Static_assert(sizeof(fds) >= sizeof(struct pollfd) * 3, "");
361
362 #if _FORTIFY_SOURCE > 1
363 // expected-warning@+2{{fds buffer too small}}
364 #endif
365 EXPECT_DEATH_STRUCT(poll(fds.few, 3, 0));
366
367 struct timespec timeout = {};
368 #if _FORTIFY_SOURCE > 1
369 // expected-warning@+2{{fds buffer too small}}
370 #endif
371 EXPECT_DEATH_STRUCT(ppoll(fds.few, 3, &timeout, 0));
372 }
373 }
374
TestSocket()375 static void TestSocket() {
376 {
377 char small_buffer[8];
378 // expected-warning@+1{{bigger length than size of destination buffer}}
379 EXPECT_DEATH(recv(kBogusFD, small_buffer, sizeof(small_buffer) + 1, 0));
380 // expected-warning@+1{{bigger length than size of destination buffer}}
381 EXPECT_DEATH(
382 recvfrom(kBogusFD, small_buffer, sizeof(small_buffer) + 1, 0, 0, 0));
383 }
384
385 {
386 struct {
387 char tiny_buffer[4];
388 char tiny_buffer2;
389 } split = {};
390
391 EXPECT_NO_DEATH(recv(kBogusFD, split.tiny_buffer, sizeof(split), 0));
392 EXPECT_NO_DEATH(
393 recvfrom(kBogusFD, split.tiny_buffer, sizeof(split), 0, 0, 0));
394 }
395 }
396
TestStdio()397 static void TestStdio() {
398 char small_buffer[8] = {};
399 {
400 // expected-warning@+1{{may overflow the destination buffer}}
401 EXPECT_DEATH(snprintf(small_buffer, sizeof(small_buffer) + 1, ""));
402
403 va_list va;
404 // expected-warning@+2{{format string is empty}}
405 // expected-warning@+1{{may overflow the destination buffer}}
406 EXPECT_DEATH(vsnprintf(small_buffer, sizeof(small_buffer) + 1, "", va));
407 }
408
409 // gets is safe here, since stdin is actually /dev/null
410 // expected-warning@+1{{ignoring return value}}
411 EXPECT_NO_DEATH(gets(small_buffer));
412
413 char *volatile unknown_size_buffer = small_buffer;
414 // Since stdin is /dev/null, gets on a tiny buffer is safe here.
415 // expected-warning@+2{{ignoring return value}}
416 // expected-warning@+1{{please use fgets or getline}}
417 EXPECT_NO_DEATH(gets(unknown_size_buffer));
418 }
419
TestUnistd()420 static void TestUnistd() {
421 char small_buffer[8];
422
423 // Return value warnings are (sort of) a part of FORTIFY, so we don't ignore
424 // them.
425 // expected-warning@+2{{ignoring return value of function}}
426 // expected-warning@+1{{bigger length than size of the destination buffer}}
427 EXPECT_DEATH(read(kBogusFD, small_buffer, sizeof(small_buffer) + 1));
428 // expected-warning@+2{{ignoring return value of function}}
429 // expected-warning@+1{{bigger length than size of the destination buffer}}
430 EXPECT_DEATH(pread(kBogusFD, small_buffer, sizeof(small_buffer) + 1, 0));
431 // expected-warning@+2{{ignoring return value of function}}
432 // expected-warning@+1{{bigger length than size of the destination buffer}}
433 EXPECT_DEATH(pread64(kBogusFD, small_buffer, sizeof(small_buffer) + 1, 0));
434 // expected-warning@+2{{ignoring return value of function}}
435 // expected-warning@+1{{bigger length than size of destination buffer}}
436 EXPECT_DEATH(readlink("/", small_buffer, sizeof(small_buffer) + 1));
437 // expected-warning@+2{{ignoring return value of function}}
438 // expected-warning@+1{{bigger length than size of destination buffer}}
439 EXPECT_DEATH(getcwd(small_buffer, sizeof(small_buffer) + 1));
440
441 // glibc allocates and returns a buffer if you pass null to getcwd
442 // expected-warning@+1{{ignoring return value of function}}
443 EXPECT_NO_DEATH(getcwd(NULL, 0));
444 // expected-warning@+1{{ignoring return value of function}}
445 EXPECT_NO_DEATH(getcwd(NULL, 4096));
446
447 {
448 char large_buffer[PATH_MAX * 2];
449 // expected-warning@+1{{ignoring return value of function}}
450 EXPECT_NO_DEATH(getwd(large_buffer));
451
452 char *volatile unknown_size_buffer = large_buffer;
453 // expected-warning@+2{{ignoring return value of function}}
454 // expected-warning@+1{{please use getcwd instead}}
455 EXPECT_NO_DEATH(getwd(unknown_size_buffer));
456 }
457
458 // expected-warning@+1{{bigger length than size of destination buffer}}
459 EXPECT_DEATH(confstr(0, small_buffer, sizeof(small_buffer) + 1));
460
461 {
462 gid_t gids[2];
463 // expected-warning@+1{{bigger group count than what can fit}}
464 EXPECT_DEATH(getgroups(3, gids));
465 }
466
467 // expected-warning@+1{{bigger buflen than size of destination buffer}}
468 EXPECT_DEATH(ttyname_r(kBogusFD, small_buffer, sizeof(small_buffer) + 1));
469 // expected-warning@+1{{bigger buflen than size of destination buffer}}
470 EXPECT_DEATH(getlogin_r(small_buffer, sizeof(small_buffer) + 1));
471 // expected-warning@+1{{bigger buflen than size of destination buffer}}
472 EXPECT_DEATH(gethostname(small_buffer, sizeof(small_buffer) + 1));
473 // expected-warning@+1{{bigger buflen than size of destination buffer}}
474 EXPECT_DEATH(getdomainname(small_buffer, sizeof(small_buffer) + 1));
475
476 // We've already checked the warn-unused-result warnings; no need to clutter
477 // the code with rechecks...
478 #pragma clang diagnostic push
479 #pragma clang diagnostic ignored "-Wunused-value"
480 struct {
481 char tiny_buffer[4];
482 char tiny_buffer2[4];
483 } split;
484
485 EXPECT_NO_DEATH(read(kBogusFD, split.tiny_buffer, sizeof(split)));
486 EXPECT_NO_DEATH(pread(kBogusFD, split.tiny_buffer, sizeof(split), 0));
487 EXPECT_NO_DEATH(pread64(kBogusFD, split.tiny_buffer, sizeof(split), 0));
488
489 #if _FORTIFY_SOURCE > 1
490 // expected-warning@+2{{bigger length than size of destination buffer}}
491 #endif
492 EXPECT_DEATH_STRUCT(readlink("/", split.tiny_buffer, sizeof(split)));
493 #if _FORTIFY_SOURCE > 1
494 // expected-warning@+2{{bigger length than size of destination buffer}}
495 #endif
496 EXPECT_DEATH_STRUCT(getcwd(split.tiny_buffer, sizeof(split)));
497
498 #if _FORTIFY_SOURCE > 1
499 // expected-warning@+2{{bigger length than size of destination buffer}}
500 #endif
501 EXPECT_DEATH_STRUCT(confstr(kBogusFD, split.tiny_buffer, sizeof(split)));
502
503 {
504 struct {
505 gid_t tiny_buffer[2];
506 gid_t tiny_buffer2[1];
507 } split_gids;
508 #if _FORTIFY_SOURCE > 1
509 // expected-warning@+2{{bigger group count than what can fit}}
510 #endif
511 EXPECT_DEATH_STRUCT(getgroups(3, split_gids.tiny_buffer));
512 }
513
514 #if _FORTIFY_SOURCE > 1
515 // expected-warning@+2{{bigger buflen than size of destination buffer}}
516 #endif
517 EXPECT_DEATH_STRUCT(ttyname_r(kBogusFD, split.tiny_buffer, sizeof(split)));
518 #if _FORTIFY_SOURCE > 1
519 // expected-warning@+2{{bigger buflen than size of destination buffer}}
520 #endif
521 EXPECT_DEATH_STRUCT(getlogin_r(split.tiny_buffer, sizeof(split)));
522 #if _FORTIFY_SOURCE > 1
523 // expected-warning@+2{{bigger buflen than size of destination buffer}}
524 #endif
525 EXPECT_DEATH_STRUCT(gethostname(split.tiny_buffer, sizeof(split)));
526 #if _FORTIFY_SOURCE > 1
527 // expected-warning@+2{{bigger buflen than size of destination buffer}}
528 #endif
529 EXPECT_DEATH_STRUCT(getdomainname(split.tiny_buffer, sizeof(split)));
530
531 #pragma clang diagnostic pop // -Wunused-value
532 }
533
TestWchar()534 static void TestWchar() {
535 // Sizes here are all expressed in terms of sizeof(wchar_t).
536 const int small_buffer_size = 8;
537 wchar_t small_buffer[small_buffer_size] = {};
538 {
539 const int large_buffer_size = small_buffer_size + 1;
540 wchar_t large_buffer[large_buffer_size];
541
542 // expected-warning@+1{{length bigger than size of destination buffer}}
543 EXPECT_DEATH(wmemcpy(small_buffer, large_buffer, large_buffer_size));
544 // expected-warning@+1{{length bigger than size of destination buffer}}
545 EXPECT_DEATH(wmemmove(small_buffer, large_buffer, large_buffer_size));
546 // expected-warning@+1{{length bigger than size of destination buffer}}
547 EXPECT_DEATH(wmempcpy(small_buffer, large_buffer, large_buffer_size));
548 }
549
550 {
551 const wchar_t large_string[] = L"Hello!!!";
552 const int large_string_size = small_buffer_size + 1;
553 _Static_assert(sizeof(large_string) == large_string_size * sizeof(wchar_t),
554 "");
555
556 // expected-warning@+1{{length bigger than size of destination buffer}}
557 EXPECT_DEATH(wmemset(small_buffer, 0, small_buffer_size + 1));
558 // expected-warning@+1{{length bigger than size of destination buffer}}
559 EXPECT_DEATH(wcsncpy(small_buffer, large_string, small_buffer_size + 1));
560 // expected-warning@+1{{length bigger than size of destination buffer}}
561 EXPECT_DEATH(wcpncpy(small_buffer, large_string, small_buffer_size + 1));
562
563 // expected-warning@+2{{ignoring return value of function}}
564 // expected-warning@+1{{length bigger than size of destination buffer}}
565 EXPECT_DEATH(fgetws(small_buffer, sizeof(small_buffer) + 1, 0));
566 // expected-warning@+2{{ignoring return value of function}}
567 // expected-warning@+1{{bigger size than length of destination buffer}}
568 EXPECT_DEATH(fgetws_unlocked(small_buffer, sizeof(small_buffer) + 1, 0));
569
570 // No diagnostics emitted for either clang or gcc :(
571 EXPECT_DEATH(wcscpy(small_buffer, large_string));
572 EXPECT_DEATH(wcpcpy(small_buffer, large_string));
573 EXPECT_DEATH(wcscat(small_buffer, large_string));
574 EXPECT_DEATH(wcsncat(small_buffer, large_string, large_string_size));
575 }
576
577 mbstate_t mbs;
578 bzero(&mbs, sizeof(mbs));
579 {
580 const char *src[small_buffer_size * sizeof(wchar_t)];
581 // expected-warning@+1{{called with dst buffer smaller than}}
582 EXPECT_DEATH(mbsrtowcs(small_buffer, src, sizeof(small_buffer) + 1, &mbs));
583 }
584
585 {
586 const int array_len = 8;
587 char chars[array_len];
588 const char *chars_ptr = chars;
589 wchar_t wchars[array_len];
590 const wchar_t *wchars_ptr = wchars;
591 // expected-warning@+1{{called with dst buffer smaller than}}
592 EXPECT_DEATH(wcsrtombs(chars, &wchars_ptr, array_len + 1, &mbs));
593 // expected-warning@+1{{called with dst buffer smaller than}}
594 EXPECT_DEATH(mbsnrtowcs(wchars, &chars_ptr, 0, array_len + 1, &mbs));
595 // expected-warning@+1{{called with dst buffer smaller than}}
596 EXPECT_DEATH(wcsnrtombs(chars, &wchars_ptr, 0, array_len + 1, &mbs));
597 }
598
599
600 struct {
601 wchar_t buf[small_buffer_size - 1];
602 wchar_t extra;
603 } small_split;
604 _Static_assert(sizeof(small_split) == sizeof(small_buffer), "");
605 bzero(&small_split, sizeof(small_split));
606
607 EXPECT_NO_DEATH(wmemcpy(small_split.buf, small_buffer, small_buffer_size));
608 EXPECT_NO_DEATH(wmemmove(small_split.buf, small_buffer, small_buffer_size));
609 EXPECT_NO_DEATH(wmempcpy(small_split.buf, small_buffer, small_buffer_size));
610
611 {
612 const wchar_t small_string[] = L"Hello!!";
613 _Static_assert(sizeof(small_buffer) == sizeof(small_string), "");
614
615 EXPECT_NO_DEATH(wmemset(small_split.buf, 0, small_buffer_size));
616 #if _FORTIFY_SOURCE > 1
617 // expected-warning@+2{{length bigger than size of destination buffer}}
618 #endif
619 EXPECT_DEATH_STRUCT(
620 wcsncpy(small_split.buf, small_string, small_buffer_size));
621 #if _FORTIFY_SOURCE > 1
622 // expected-warning@+2{{length bigger than size of destination buffer}}
623 #endif
624 EXPECT_DEATH_STRUCT(
625 wcpncpy(small_split.buf, small_string, small_buffer_size));
626
627 // FIXME(gbiv): FORTIFY doesn't warn about this eagerly enough on
628 // _FORTIFY_SOURCE=1.
629 // expected-warning@+4{{ignoring return value of function}}
630 #if _FORTIFY_SOURCE > 1
631 // expected-warning@+2{{length bigger than size of destination buffer}}
632 #endif
633 EXPECT_DEATH(fgetws(small_split.buf, small_buffer_size, 0));
634
635 // FIXME(gbiv): FORTIFY doesn't warn about this eagerly enough on
636 // _FORTIFY_SOURCE=1.
637 // expected-warning@+4{{ignoring return value of function}}
638 #if _FORTIFY_SOURCE > 1
639 // expected-warning@+2{{bigger size than length of destination buffer}}
640 #endif
641 EXPECT_DEATH(fgetws_unlocked(small_split.buf, small_buffer_size, 0));
642
643 // No diagnostics emitted for either clang or gcc :(
644 EXPECT_DEATH_STRUCT(wcscpy(small_split.buf, small_string));
645 EXPECT_DEATH_STRUCT(wcpcpy(small_split.buf, small_string));
646 EXPECT_DEATH_STRUCT(wcscat(small_split.buf, small_string));
647 EXPECT_DEATH_STRUCT(
648 wcsncat(small_split.buf, small_string, small_buffer_size));
649 }
650
651 {
652 // NOREVIEW: STRUCT
653 const char *src[sizeof(small_buffer)] = {};
654 // FIXME(gbiv): _FORTIFY_SOURCE=1 should diagnose this more aggressively
655 #if _FORTIFY_SOURCE > 1
656 // expected-warning@+2{{called with dst buffer smaller than}}
657 #endif
658 EXPECT_DEATH(mbsrtowcs(small_split.buf, src, small_buffer_size, &mbs));
659 }
660
661 {
662 // NOREVIEW: STRUCT
663 const int array_len = 8;
664 struct {
665 char buf[array_len - 1];
666 char extra;
667 } split_chars;
668 const char *chars_ptr = split_chars.buf;
669 struct {
670 wchar_t buf[array_len - 1];
671 wchar_t extra;
672 } split_wchars;
673 const wchar_t *wchars_ptr = split_wchars.buf;
674 #if _FORTIFY_SOURCE > 1
675 // expected-warning@+2{{called with dst buffer smaller than}}
676 #endif
677 EXPECT_DEATH_STRUCT(
678 wcsrtombs(split_chars.buf, &wchars_ptr, array_len, &mbs));
679 #if _FORTIFY_SOURCE > 1
680 // expected-warning@+2{{called with dst buffer smaller than}}
681 #endif
682 EXPECT_DEATH_STRUCT(
683 mbsnrtowcs(split_wchars.buf, &chars_ptr, 0, array_len, &mbs));
684 #if _FORTIFY_SOURCE > 1
685 // expected-warning@+2{{called with dst buffer smaller than}}
686 #endif
687 EXPECT_DEATH_STRUCT(
688 wcsnrtombs(split_chars.buf, &wchars_ptr, 0, array_len, &mbs));
689 }
690 }
691
TestStdlib()692 static void TestStdlib() {
693 {
694 char path_buffer[PATH_MAX - 1];
695 // expected-warning@+2{{ignoring return value of function}}
696 // expected-warning@+1{{must be either NULL or at least PATH_MAX bytes}}
697 EXPECT_DEATH(realpath("/", path_buffer));
698 // expected-warning@+1{{ignoring return value of function}}
699 realpath("/", NULL);
700 }
701
702 char small_buffer[8];
703 // expected-warning@+1{{called with buflen bigger than size of buf}}
704 EXPECT_DEATH(ptsname_r(kBogusFD, small_buffer, sizeof(small_buffer) + 1));
705
706 {
707 const int wchar_buffer_size = 8;
708 wchar_t wchar_buffer[wchar_buffer_size];
709 // expected-warning@+1{{called with dst buffer smaller than}}
710 EXPECT_DEATH(mbstowcs(wchar_buffer, small_buffer, wchar_buffer_size + 1));
711 // expected-warning@+1{{called with dst buffer smaller than}}
712 EXPECT_DEATH(
713 wcstombs(small_buffer, wchar_buffer, sizeof(small_buffer) + 1));
714 }
715
716 {
717 struct {
718 char path_buffer[PATH_MAX - 1];
719 char rest[1];
720 } split;
721 // expected-warning@+4{{ignoring return value of function}}
722 #if _FORTIFY_SOURCE > 1
723 // expected-warning@+2{{must be either NULL or at least PATH_MAX bytes}}
724 #endif
725 EXPECT_DEATH_STRUCT(realpath("/", split.path_buffer));
726 }
727
728 struct {
729 char tiny_buffer[4];
730 char rest[1];
731 } split;
732 #if _FORTIFY_SOURCE > 1
733 // expected-warning@+2{{called with buflen bigger than size of buf}}
734 #endif
735 EXPECT_DEATH_STRUCT(ptsname_r(kBogusFD, split.tiny_buffer, sizeof(split)));
736
737 {
738 const int tiny_buffer_size = 4;
739 struct {
740 wchar_t tiny_buffer[tiny_buffer_size];
741 wchar_t rest;
742 } wsplit;
743 #if _FORTIFY_SOURCE > 1
744 // expected-warning@+2{{called with dst buffer smaller than}}
745 #endif
746 EXPECT_DEATH_STRUCT(
747 mbstowcs(wsplit.tiny_buffer, small_buffer, tiny_buffer_size + 1));
748 #if _FORTIFY_SOURCE > 1
749 // expected-warning@+2{{called with dst buffer smaller than}}
750 #endif
751 EXPECT_DEATH_STRUCT(
752 wcstombs(split.tiny_buffer, wsplit.tiny_buffer, sizeof(split)));
753 }
754 }
755
756 /////////////////// Test infrastructure; nothing to see here ///////////////////
757
758 #define CONCAT2(x, y) x ## y
759 #define CONCAT(x, y) CONCAT2(x, y)
760
761 // Exported to the driver so we can run these tests.
CONCAT(test_fortify_,_FORTIFY_SOURCE)762 std::vector<Failure> CONCAT(test_fortify_, _FORTIFY_SOURCE)() {
763 std::vector<Failure> result;
764 failures = &result;
765
766 TestPoll();
767 TestSocket();
768 TestStdio();
769 TestStdlib();
770 TestString();
771 TestUnistd();
772 TestWchar();
773
774 failures = nullptr;
775 return result;
776 }
777