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.
64static std::vector<Failure> *failures;
65
66template <typename Fn>
67static 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
113const static int kBogusFD = -1;
114
115static 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
207namespace compilation_tests {
208static 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
244static 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
258static 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
288static 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
310static 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
333static 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
447static 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
605static 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.
675std::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