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