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