Home | History | Annotate | Download | only in src
      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>
     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 
    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     // FIXME(gbiv): Clang (and GCC, for that matter) should diagnose this.
    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{{called with bigger length than the destination}}
    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     // FIXME(gbiv): Clang (and GCC, for that matter) should diagnose this.
    189     EXPECT_DEATH_STRUCT(
    190         stpncpy(split.tiny_buffer, small_string, sizeof(small_string)));
    191 
    192 #if _FORTIFY_SOURCE > 1
    193     // expected-warning@+2{{destination buffer will always be overflown}}
    194 #endif
    195     EXPECT_DEATH_STRUCT(strcat(split.tiny_buffer, small_string));
    196 
    197 #if _FORTIFY_SOURCE > 1
    198     // expected-warning@+2{{called with bigger length than the destination}}
    199 #endif
    200     EXPECT_DEATH_STRUCT(
    201         strncat(split.tiny_buffer, small_string, sizeof(small_string)));
    202   }
    203 }
    204 
    205 // Since these emit hard errors, it's sort of hard to run them...
    206 #ifdef COMPILATION_TESTS
    207 namespace compilation_tests {
    208 static void testFcntl() {
    209   // FIXME(gbiv): Need to fix these; they got dropped.
    210 #if 0
    211   // expected-error@+1{{either with 2 or 3 arguments, not more}}
    212 #endif
    213   open("/", 0, 0, 0);
    214 #if 0
    215   // expected-error@+1{{either with 2 or 3 arguments, not more}}
    216 #endif
    217   open64("/", 0, 0, 0);
    218   // expected-error@+1{{either with 3 or 4 arguments, not more}}
    219   openat(0, "/", 0, 0, 0);
    220   // expected-error@+1{{either with 3 or 4 arguments, not more}}
    221   openat64(0, "/", 0, 0, 0);
    222 
    223   // expected-error@+1{{needs 3 arguments}}
    224   open("/", O_CREAT);
    225   // expected-error@+1{{needs 3 arguments}}
    226   open("/", O_TMPFILE);
    227   // expected-error@+1{{needs 3 arguments}}
    228   open64("/", O_CREAT);
    229   // expected-error@+1{{needs 3 arguments}}
    230   open64("/", O_TMPFILE);
    231   // expected-error@+1{{needs 4 arguments}}
    232   openat(0, "/", O_CREAT);
    233   // expected-error@+1{{needs 4 arguments}}
    234   openat(0, "/", O_TMPFILE);
    235   // expected-error@+1{{needs 4 arguments}}
    236   openat64(0, "/", O_CREAT);
    237   // expected-error@+1{{needs 4 arguments}}
    238   openat64(0, "/", O_TMPFILE);
    239 
    240   // Superfluous modes are sometimes bugs, but not often enough to complain
    241   // about, apparently.
    242 }
    243 
    244 static void testMqueue() {
    245   // FIXME(gbiv): remove mq_open's FORTIFY'ed body from glibc...
    246 
    247   // expected-error@+1{{with 2 or 4 arguments}}
    248   mq_open("/", 0, 0);
    249   // expected-error@+1{{with 2 or 4 arguments}}
    250   mq_open("/", 0, 0, 0, 0);
    251 
    252   // expected-error@+1{{needs 4 arguments}}
    253   mq_open("/", O_CREAT);
    254 }
    255 } // namespace compilation_tests
    256 #endif
    257 
    258 static void TestPoll() {
    259   struct pollfd invalid_poll_fd = {kBogusFD, 0, 0};
    260   {
    261     struct pollfd few_fds[] = {invalid_poll_fd, invalid_poll_fd};
    262     // expected-warning@+1{{fds buffer too small}}
    263     EXPECT_DEATH(poll(few_fds, 3, 0));
    264     // expected-warning@+1{{fds buffer too small}}
    265     EXPECT_DEATH(ppoll(few_fds, 3, 0, 0));
    266   }
    267 
    268   {
    269     struct {
    270       struct pollfd few[2];
    271       struct pollfd extra[1];
    272     } fds = {{invalid_poll_fd, invalid_poll_fd}, {invalid_poll_fd}};
    273     _Static_assert(sizeof(fds) >= sizeof(struct pollfd) * 3, "");
    274 
    275 #if _FORTIFY_SOURCE > 1
    276     // expected-warning@+2{{fds buffer too small}}
    277 #endif
    278     EXPECT_DEATH_STRUCT(poll(fds.few, 3, 0));
    279 
    280     struct timespec timeout = {};
    281 #if _FORTIFY_SOURCE > 1
    282     // expected-warning@+2{{fds buffer too small}}
    283 #endif
    284     EXPECT_DEATH_STRUCT(ppoll(fds.few, 3, &timeout, 0));
    285   }
    286 }
    287 
    288 static void TestSocket() {
    289   {
    290     char small_buffer[8];
    291     // expected-warning@+1{{bigger length than size of destination buffer}}
    292     EXPECT_DEATH(recv(kBogusFD, small_buffer, sizeof(small_buffer) + 1, 0));
    293     // expected-warning@+1{{bigger length than size of destination buffer}}
    294     EXPECT_DEATH(
    295         recvfrom(kBogusFD, small_buffer, sizeof(small_buffer) + 1, 0, 0, 0));
    296   }
    297 
    298   {
    299     struct {
    300       char tiny_buffer[4];
    301       char tiny_buffer2;
    302     } split = {};
    303 
    304     EXPECT_NO_DEATH(recv(kBogusFD, split.tiny_buffer, sizeof(split), 0));
    305     EXPECT_NO_DEATH(
    306         recvfrom(kBogusFD, split.tiny_buffer, sizeof(split), 0, 0, 0));
    307   }
    308 }
    309 
    310 static void TestStdio() {
    311   char small_buffer[8] = {};
    312   {
    313     // expected-warning@+1{{may overflow the destination buffer}}
    314     EXPECT_DEATH(snprintf(small_buffer, sizeof(small_buffer) + 1, ""));
    315 
    316     va_list va;
    317     // expected-warning@+1{{may overflow the destination buffer}}
    318     EXPECT_DEATH(vsnprintf(small_buffer, sizeof(small_buffer) + 1, "", va));
    319   }
    320 
    321   // gets is safe here, since stdin is actually /dev/null
    322   // expected-warning@+1{{ignoring return value}}
    323   EXPECT_NO_DEATH(gets(small_buffer));
    324 
    325   char *volatile unknown_size_buffer = small_buffer;
    326   // FIXME(gbiv): This should issue a "don't use me" warning, besides just
    327   // deprecation (which is suppressed)...
    328   // Since stdin is /dev/null, gets on a tiny buffer is safe here.
    329   // expected-warning@+1{{ignoring return value}}
    330   EXPECT_NO_DEATH(gets(unknown_size_buffer));
    331 }
    332 
    333 static void TestUnistd() {
    334   char small_buffer[8];
    335 
    336   // Return value warnings are (sort of) a part of FORTIFY, so we don't ignore
    337   // them.
    338   // expected-warning@+2{{ignoring return value of function}}
    339   // expected-warning@+1{{bigger length than size of the destination buffer}}
    340   EXPECT_DEATH(read(kBogusFD, small_buffer, sizeof(small_buffer) + 1));
    341   // expected-warning@+2{{ignoring return value of function}}
    342   // expected-warning@+1{{bigger length than size of the destination buffer}}
    343   EXPECT_DEATH(pread(kBogusFD, small_buffer, sizeof(small_buffer) + 1, 0));
    344   // expected-warning@+2{{ignoring return value of function}}
    345   // expected-warning@+1{{bigger length than size of the destination buffer}}
    346   EXPECT_DEATH(pread64(kBogusFD, small_buffer, sizeof(small_buffer) + 1, 0));
    347   // expected-warning@+2{{ignoring return value of function}}
    348   // expected-warning@+1{{bigger length than size of destination buffer}}
    349   EXPECT_DEATH(readlink("/", small_buffer, sizeof(small_buffer) + 1));
    350   // expected-warning@+2{{ignoring return value of function}}
    351   // expected-warning@+1{{bigger length than size of destination buffer}}
    352   EXPECT_DEATH(getcwd(small_buffer, sizeof(small_buffer) + 1));
    353 
    354   // glibc allocates and returns a buffer if you pass null to getcwd
    355   // expected-warning@+1{{ignoring return value of function}}
    356   EXPECT_NO_DEATH(getcwd(NULL, 0));
    357   // expected-warning@+1{{ignoring return value of function}}
    358   EXPECT_NO_DEATH(getcwd(NULL, 4096));
    359 
    360   {
    361     char large_buffer[PATH_MAX * 2];
    362     // expected-warning@+1{{ignoring return value of function}}
    363     EXPECT_NO_DEATH(getwd(large_buffer));
    364 
    365     char *volatile unknown_size_buffer = large_buffer;
    366     // expected-warning@+2{{ignoring return value of function}}
    367     // FIXME(gbiv): We should emit a "use getcwd" complaint here.
    368     EXPECT_NO_DEATH(getwd(unknown_size_buffer));
    369   }
    370 
    371   // expected-warning@+1{{bigger length than size of destination buffer}}
    372   EXPECT_DEATH(confstr(0, small_buffer, sizeof(small_buffer) + 1));
    373 
    374   {
    375     gid_t gids[2];
    376     // expected-warning@+1{{bigger group count than what can fit}}
    377     EXPECT_DEATH(getgroups(3, gids));
    378   }
    379 
    380   // expected-warning@+1{{bigger buflen than size of destination buffer}}
    381   EXPECT_DEATH(ttyname_r(kBogusFD, small_buffer, sizeof(small_buffer) + 1));
    382   // expected-warning@+1{{bigger buflen than size of destination buffer}}
    383   EXPECT_DEATH(getlogin_r(small_buffer, sizeof(small_buffer) + 1));
    384   // expected-warning@+1{{bigger buflen than size of destination buffer}}
    385   EXPECT_DEATH(gethostname(small_buffer, sizeof(small_buffer) + 1));
    386   // expected-warning@+1{{bigger buflen than size of destination buffer}}
    387   EXPECT_DEATH(getdomainname(small_buffer, sizeof(small_buffer) + 1));
    388 
    389   // We've already checked the warn-unused-result warnings; no need to clutter
    390   // the code with rechecks...
    391 #pragma clang diagnostic push
    392 #pragma clang diagnostic ignored "-Wunused-value"
    393   struct {
    394     char tiny_buffer[4];
    395     char tiny_buffer2[4];
    396   } split;
    397 
    398   EXPECT_NO_DEATH(read(kBogusFD, split.tiny_buffer, sizeof(split)));
    399   EXPECT_NO_DEATH(pread(kBogusFD, split.tiny_buffer, sizeof(split), 0));
    400   EXPECT_NO_DEATH(pread64(kBogusFD, split.tiny_buffer, sizeof(split), 0));
    401 
    402 #if _FORTIFY_SOURCE > 1
    403   // expected-warning@+2{{bigger length than size of destination buffer}}
    404 #endif
    405   EXPECT_DEATH_STRUCT(readlink("/", split.tiny_buffer, sizeof(split)));
    406 #if _FORTIFY_SOURCE > 1
    407   // expected-warning@+2{{bigger length than size of destination buffer}}
    408 #endif
    409   EXPECT_DEATH_STRUCT(getcwd(split.tiny_buffer, sizeof(split)));
    410 
    411 #if _FORTIFY_SOURCE > 1
    412   // expected-warning@+2{{bigger length than size of destination buffer}}
    413 #endif
    414   EXPECT_DEATH_STRUCT(confstr(kBogusFD, split.tiny_buffer, sizeof(split)));
    415 
    416   {
    417     struct {
    418       gid_t tiny_buffer[2];
    419       gid_t tiny_buffer2[1];
    420     } split_gids;
    421 #if _FORTIFY_SOURCE > 1
    422     // expected-warning@+2{{bigger group count than what can fit}}
    423 #endif
    424     EXPECT_DEATH_STRUCT(getgroups(3, split_gids.tiny_buffer));
    425   }
    426 
    427 #if _FORTIFY_SOURCE > 1
    428   // expected-warning@+2{{bigger buflen than size of destination buffer}}
    429 #endif
    430   EXPECT_DEATH_STRUCT(ttyname_r(kBogusFD, split.tiny_buffer, sizeof(split)));
    431 #if _FORTIFY_SOURCE > 1
    432   // expected-warning@+2{{bigger buflen than size of destination buffer}}
    433 #endif
    434   EXPECT_DEATH_STRUCT(getlogin_r(split.tiny_buffer, sizeof(split)));
    435 #if _FORTIFY_SOURCE > 1
    436   // expected-warning@+2{{bigger buflen than size of destination buffer}}
    437 #endif
    438   EXPECT_DEATH_STRUCT(gethostname(split.tiny_buffer, sizeof(split)));
    439 #if _FORTIFY_SOURCE > 1
    440   // expected-warning@+2{{bigger buflen than size of destination buffer}}
    441 #endif
    442   EXPECT_DEATH_STRUCT(getdomainname(split.tiny_buffer, sizeof(split)));
    443 
    444 #pragma clang diagnostic pop // -Wunused-value
    445 }
    446 
    447 static void TestWchar() {
    448   // Sizes here are all expressed in terms of sizeof(wchar_t).
    449   const int small_buffer_size = 8;
    450   wchar_t small_buffer[small_buffer_size] = {};
    451   {
    452     const int large_buffer_size = small_buffer_size + 1;
    453     wchar_t large_buffer[large_buffer_size];
    454 
    455     // expected-warning@+1{{length bigger than size of destination buffer}}
    456     EXPECT_DEATH(wmemcpy(small_buffer, large_buffer, large_buffer_size));
    457     // expected-warning@+1{{length bigger than size of destination buffer}}
    458     EXPECT_DEATH(wmemmove(small_buffer, large_buffer, large_buffer_size));
    459     // expected-warning@+1{{length bigger than size of destination buffer}}
    460     EXPECT_DEATH(wmempcpy(small_buffer, large_buffer, large_buffer_size));
    461   }
    462 
    463   {
    464     const wchar_t large_string[] = L"Hello!!!";
    465     const int large_string_size = small_buffer_size + 1;
    466     _Static_assert(sizeof(large_string) == large_string_size * sizeof(wchar_t),
    467                    "");
    468 
    469     // expected-warning@+1{{length bigger than size of destination buffer}}
    470     EXPECT_DEATH(wmemset(small_buffer, 0, small_buffer_size + 1));
    471     // expected-warning@+1{{length bigger than size of destination buffer}}
    472     EXPECT_DEATH(wcsncpy(small_buffer, large_string, small_buffer_size + 1));
    473     // expected-warning@+1{{length bigger than size of destination buffer}}
    474     EXPECT_DEATH(wcpncpy(small_buffer, large_string, small_buffer_size + 1));
    475 
    476     // expected-warning@+2{{ignoring return value of function}}
    477     // expected-warning@+1{{length bigger than size of destination buffer}}
    478     EXPECT_DEATH(fgetws(small_buffer, sizeof(small_buffer) + 1, 0));
    479     // expected-warning@+2{{ignoring return value of function}}
    480     // expected-warning@+1{{bigger size than length of destination buffer}}
    481     EXPECT_DEATH(fgetws_unlocked(small_buffer, sizeof(small_buffer) + 1, 0));
    482 
    483     // No diagnostics emitted for either clang or gcc :(
    484     EXPECT_DEATH(wcscpy(small_buffer, large_string));
    485     EXPECT_DEATH(wcpcpy(small_buffer, large_string));
    486     EXPECT_DEATH(wcscat(small_buffer, large_string));
    487     EXPECT_DEATH(wcsncat(small_buffer, large_string, large_string_size));
    488   }
    489 
    490   mbstate_t mbs;
    491   bzero(&mbs, sizeof(mbs));
    492   {
    493     const char *src[small_buffer_size * sizeof(wchar_t)];
    494     // expected-warning@+1{{called with dst buffer smaller than}}
    495     EXPECT_DEATH(mbsrtowcs(small_buffer, src, sizeof(small_buffer) + 1, &mbs));
    496   }
    497 
    498   {
    499     const int array_len = 8;
    500     char chars[array_len];
    501     const char *chars_ptr = chars;
    502     wchar_t wchars[array_len];
    503     const wchar_t *wchars_ptr = wchars;
    504     // expected-warning@+1{{called with dst buffer smaller than}}
    505     EXPECT_DEATH(wcsrtombs(chars, &wchars_ptr, array_len + 1, &mbs));
    506     // expected-warning@+1{{called with dst buffer smaller than}}
    507     EXPECT_DEATH(mbsnrtowcs(wchars, &chars_ptr, 0, array_len + 1, &mbs));
    508     // expected-warning@+1{{called with dst buffer smaller than}}
    509     EXPECT_DEATH(wcsnrtombs(chars, &wchars_ptr, 0, array_len + 1, &mbs));
    510   }
    511 
    512 
    513   struct {
    514     wchar_t buf[small_buffer_size - 1];
    515     wchar_t extra;
    516   } small_split;
    517   _Static_assert(sizeof(small_split) == sizeof(small_buffer), "");
    518   bzero(&small_split, sizeof(small_split));
    519 
    520   EXPECT_NO_DEATH(wmemcpy(small_split.buf, small_buffer, small_buffer_size));
    521   EXPECT_NO_DEATH(wmemmove(small_split.buf, small_buffer, small_buffer_size));
    522   EXPECT_NO_DEATH(wmempcpy(small_split.buf, small_buffer, small_buffer_size));
    523 
    524   {
    525     const wchar_t small_string[] = L"Hello!!";
    526     _Static_assert(sizeof(small_buffer) == sizeof(small_string), "");
    527 
    528     EXPECT_NO_DEATH(wmemset(small_split.buf, 0, small_buffer_size));
    529 #if _FORTIFY_SOURCE > 1
    530     // expected-warning@+2{{length bigger than size of destination buffer}}
    531 #endif
    532     EXPECT_DEATH_STRUCT(
    533         wcsncpy(small_split.buf, small_string, small_buffer_size));
    534 #if _FORTIFY_SOURCE > 1
    535     // expected-warning@+2{{length bigger than size of destination buffer}}
    536 #endif
    537     EXPECT_DEATH_STRUCT(
    538         wcpncpy(small_split.buf, small_string, small_buffer_size));
    539 
    540     // FIXME(gbiv): FORTIFY doesn't warn about this eagerly enough on
    541     // _FORTIFY_SOURCE=1.
    542     // expected-warning@+4{{ignoring return value of function}}
    543 #if _FORTIFY_SOURCE > 1
    544     // expected-warning@+2{{length bigger than size of destination buffer}}
    545 #endif
    546     EXPECT_DEATH(fgetws(small_split.buf, small_buffer_size, 0));
    547 
    548     // FIXME(gbiv): FORTIFY doesn't warn about this eagerly enough on
    549     // _FORTIFY_SOURCE=1.
    550     // expected-warning@+4{{ignoring return value of function}}
    551 #if _FORTIFY_SOURCE > 1
    552     // expected-warning@+2{{bigger size than length of destination buffer}}
    553 #endif
    554     EXPECT_DEATH(fgetws_unlocked(small_split.buf, small_buffer_size, 0));
    555 
    556     // No diagnostics emitted for either clang or gcc :(
    557     EXPECT_DEATH_STRUCT(wcscpy(small_split.buf, small_string));
    558     EXPECT_DEATH_STRUCT(wcpcpy(small_split.buf, small_string));
    559     EXPECT_DEATH_STRUCT(wcscat(small_split.buf, small_string));
    560     EXPECT_DEATH_STRUCT(
    561         wcsncat(small_split.buf, small_string, small_buffer_size));
    562   }
    563 
    564   {
    565     // NOREVIEW: STRUCT
    566     const char *src[sizeof(small_buffer)] = {};
    567     // FIXME(gbiv): _FORTIFY_SOURCE=1 should diagnose this more aggressively
    568 #if _FORTIFY_SOURCE > 1
    569     // expected-warning@+2{{called with dst buffer smaller than}}
    570 #endif
    571     EXPECT_DEATH(mbsrtowcs(small_split.buf, src, small_buffer_size, &mbs));
    572   }
    573 
    574   {
    575     // NOREVIEW: STRUCT
    576     const int array_len = 8;
    577     struct {
    578       char buf[array_len - 1];
    579       char extra;
    580     } split_chars;
    581     const char *chars_ptr = split_chars.buf;
    582     struct {
    583       wchar_t buf[array_len - 1];
    584       wchar_t extra;
    585     } split_wchars;
    586     const wchar_t *wchars_ptr = split_wchars.buf;
    587 #if _FORTIFY_SOURCE > 1
    588     // expected-warning@+2{{called with dst buffer smaller than}}
    589 #endif
    590     EXPECT_DEATH_STRUCT(
    591         wcsrtombs(split_chars.buf, &wchars_ptr, array_len, &mbs));
    592 #if _FORTIFY_SOURCE > 1
    593     // expected-warning@+2{{called with dst buffer smaller than}}
    594 #endif
    595     EXPECT_DEATH_STRUCT(
    596         mbsnrtowcs(split_wchars.buf, &chars_ptr, 0, array_len, &mbs));
    597 #if _FORTIFY_SOURCE > 1
    598     // expected-warning@+2{{called with dst buffer smaller than}}
    599 #endif
    600     EXPECT_DEATH_STRUCT(
    601         wcsnrtombs(split_chars.buf, &wchars_ptr, 0, array_len, &mbs));
    602   }
    603 }
    604 
    605 static void TestStdlib() {
    606   {
    607     char path_buffer[PATH_MAX - 1];
    608     // expected-warning@+2{{ignoring return value of function}}
    609     // expected-warning@+1{{must be either NULL or at least PATH_MAX bytes}}
    610     EXPECT_DEATH(realpath("/", path_buffer));
    611     // expected-warning@+1{{ignoring return value of function}}
    612     realpath("/", NULL);
    613   }
    614 
    615   char small_buffer[8];
    616   // expected-warning@+1{{called with buflen bigger than size of buf}}
    617   EXPECT_DEATH(ptsname_r(kBogusFD, small_buffer, sizeof(small_buffer) + 1));
    618 
    619   {
    620     const int wchar_buffer_size = 8;
    621     wchar_t wchar_buffer[wchar_buffer_size];
    622     // expected-warning@+1{{called with dst buffer smaller than}}
    623     EXPECT_DEATH(mbstowcs(wchar_buffer, small_buffer, wchar_buffer_size + 1));
    624     // expected-warning@+1{{called with dst buffer smaller than}}
    625     EXPECT_DEATH(
    626         wcstombs(small_buffer, wchar_buffer, sizeof(small_buffer) + 1));
    627   }
    628 
    629   {
    630     struct {
    631       char path_buffer[PATH_MAX - 1];
    632       char rest[1];
    633     } split;
    634     // expected-warning@+4{{ignoring return value of function}}
    635 #if _FORTIFY_SOURCE > 1
    636     // expected-warning@+2{{must be either NULL or at least PATH_MAX bytes}}
    637 #endif
    638     EXPECT_DEATH_STRUCT(realpath("/", split.path_buffer));
    639   }
    640 
    641   struct {
    642     char tiny_buffer[4];
    643     char rest[1];
    644   } split;
    645 #if _FORTIFY_SOURCE > 1
    646   // expected-warning@+2{{called with buflen bigger than size of buf}}
    647 #endif
    648   EXPECT_DEATH_STRUCT(ptsname_r(kBogusFD, split.tiny_buffer, sizeof(split)));
    649 
    650   {
    651     const int tiny_buffer_size = 4;
    652     struct {
    653       wchar_t tiny_buffer[tiny_buffer_size];
    654       wchar_t rest;
    655     } wsplit;
    656 #if _FORTIFY_SOURCE > 1
    657     // expected-warning@+2{{called with dst buffer smaller than}}
    658 #endif
    659     EXPECT_DEATH_STRUCT(
    660         mbstowcs(wsplit.tiny_buffer, small_buffer, tiny_buffer_size + 1));
    661 #if _FORTIFY_SOURCE > 1
    662     // expected-warning@+2{{called with dst buffer smaller than}}
    663 #endif
    664     EXPECT_DEATH_STRUCT(
    665         wcstombs(split.tiny_buffer, wsplit.tiny_buffer, sizeof(split)));
    666   }
    667 }
    668 
    669 /////////////////// Test infrastructure; nothing to see here ///////////////////
    670 
    671 #define CONCAT2(x, y) x ## y
    672 #define CONCAT(x, y) CONCAT2(x, y)
    673 
    674 // Exported to the driver so we can run these tests.
    675 std::vector<Failure> CONCAT(test_fortify_, _FORTIFY_SOURCE)() {
    676   std::vector<Failure> result;
    677   failures = &result;
    678 
    679   TestPoll();
    680   TestSocket();
    681   TestStdio();
    682   TestStdlib();
    683   TestString();
    684   TestUnistd();
    685   TestWchar();
    686 
    687   failures = nullptr;
    688   return result;
    689 }
    690