Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*
     18  * If this test fails, you can see the compiler's output by erasing a few args from the failing
     19  * command. Specifically, delete everything before the path/to/the/compiler, then delete the first
     20  * arg after the path/to/the/compiler. For example, given the following command:
     21  *
     22  * bionic/tests/file-check-cxx out/host/linux-x86/bin/FileCheck \
     23  * prebuilts/clang/host/linux-x86/clang-4053586/bin/clang++ CLANG    -I bionic/tests -I ...
     24  *
     25  * If you delete everything before clang++ and delete "CLANG" (or "GCC" if gcc is failing), then
     26  * you'll end up with:
     27  *
     28  * prebuilts/clang/host/linux-x86/clang-4053586/bin/clang++ -I bionic/tests -I ...
     29  *
     30  * Which is the command that FileCheck executes.
     31  */
     32 
     33 #undef _FORTIFY_SOURCE
     34 #define _FORTIFY_SOURCE 2
     35 #include <fcntl.h>
     36 #include <netinet/in.h>
     37 #include <poll.h>
     38 #include <stdarg.h>
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <string.h>
     42 #include <sys/socket.h>
     43 #include <sys/stat.h>
     44 #include <time.h>
     45 #include <unistd.h>
     46 
     47 void test_sprintf() {
     48   char buf[4];
     49 
     50   // NOLINTNEXTLINE(whitespace/line_length)
     51   // GCC: warning: call to int __builtin___sprintf_chk(char*, int, {{(long )?}}unsigned int, const char*, ...) will always overflow destination buffer
     52   // CLANG: error: call to unavailable function 'sprintf': format string will always overflow destination buffer
     53   sprintf(buf, "foobar");  // NOLINT(runtime/printf)
     54 
     55   // NOLINTNEXTLINE(whitespace/line_length)
     56   // GCC: warning: call to int __builtin___sprintf_chk(char*, int, {{(long )?}}unsigned int, const char*, ...) will always overflow destination buffer
     57   // clang should emit a warning, but doesn't
     58   sprintf(buf, "%s", "foobar");  // NOLINT(runtime/printf)
     59 }
     60 
     61 void test_snprintf() {
     62   char buf[4];
     63 
     64   // NOLINTNEXTLINE(whitespace/line_length)
     65   // GCC: warning: call to int __builtin___snprintf_chk(char*, {{(long )?}}unsigned int, int, {{(long )?}}unsigned int, const char*, ...) will always overflow destination buffer
     66   // CLANG: error: call to unavailable function 'snprintf': format string will always overflow destination buffer
     67   snprintf(buf, 5, "foobar");  // NOLINT(runtime/printf)
     68 
     69   // NOLINTNEXTLINE(whitespace/line_length)
     70   // GCC: warning: call to int __builtin___snprintf_chk(char*, {{(long )?}}unsigned int, int, {{(long )?}}unsigned int, const char*, ...) will always overflow destination buffer
     71   // clang should emit a warning, but doesn't
     72   snprintf(buf, 5, "%s", "foobar");  // NOLINT(runtime/printf)
     73 
     74   // NOLINTNEXTLINE(whitespace/line_length)
     75   // GCC: warning: call to int __builtin___snprintf_chk(char*, {{(long )?}}unsigned int, int, {{(long )?}}unsigned int, const char*, ...) will always overflow destination buffer
     76   // clang should emit a warning, but doesn't
     77   snprintf(buf, 5, " %s ", "foobar");  // NOLINT(runtime/printf)
     78 
     79   // NOLINTNEXTLINE(whitespace/line_length)
     80   // GCC: warning: call to int __builtin___snprintf_chk(char*, {{(long )?}}unsigned int, int, {{(long )?}}unsigned int, const char*, ...) will always overflow destination buffer
     81   // clang should emit a warning, but doesn't
     82   snprintf(buf, 5, "%d", 100000);  // NOLINT(runtime/printf)
     83 }
     84 
     85 void test_memcpy() {
     86   char buf[4];
     87 
     88   // NOLINTNEXTLINE(whitespace/line_length)
     89   // GCC: warning: call to void* __builtin___memcpy_chk(void*, const void*, {{(long )?}}unsigned int, {{(long )?}}unsigned int) will always overflow destination buffer
     90   // CLANG: error: 'memcpy' called with size bigger than buffer
     91   memcpy(buf, "foobar", sizeof("foobar") + 100);
     92 }
     93 
     94 void test_memmove() {
     95   char buf[4];
     96 
     97   // NOLINTNEXTLINE(whitespace/line_length)
     98   // GCC: warning: call to void* __builtin___memmove_chk(void*, const void*, {{(long )?}}unsigned int, {{(long )?}}unsigned int) will always overflow destination buffer
     99   // CLANG: error: 'memmove' called with size bigger than buffer
    100   memmove(buf, "foobar", sizeof("foobar"));
    101 }
    102 
    103 void test_memset() {
    104   char buf[4];
    105 
    106   // NOLINTNEXTLINE(whitespace/line_length)
    107   // GCC: warning: call to void* __builtin___memset_chk(void*, int, {{(long )?}}unsigned int, {{(long )?}}unsigned int) will always overflow destination buffer
    108   // CLANG: error: 'memset' called with size bigger than buffer
    109   memset(buf, 0, 6);
    110 }
    111 
    112 void test_strcpy() {
    113   char buf[4];
    114 
    115   // NOLINTNEXTLINE(whitespace/line_length)
    116   // GCC: warning: call to {{(char\* __builtin___strcpy_chk\(char\*, const char\*, unsigned int\))|(void\* __builtin___memcpy_chk\(void\*, const void\*, (long )?unsigned int, (long )?unsigned int\))}} will always overflow destination buffer
    117   // CLANG: error: 'strcpy' called with string bigger than buffer
    118   strcpy(buf, "foobar");  // NOLINT(runtime/printf)
    119 
    120   // NOLINTNEXTLINE(whitespace/line_length)
    121   // GCC: warning: call to {{(char\* __builtin___strcpy_chk\(char\*, const char\*, unsigned int\))|(void\* __builtin___memcpy_chk\(void\*, const void\*, (long )?unsigned int, (long )?unsigned int\))}} will always overflow destination buffer
    122   // CLANG: error: 'strcpy' called with string bigger than buffer
    123   strcpy(buf, "quux");
    124 }
    125 
    126 void test_stpcpy() {
    127   char buf[4];
    128 
    129   // NOLINTNEXTLINE(whitespace/line_length)
    130   // GCC: warning: call to char* __builtin___stpcpy_chk(char*, const char*, {{(long )?}}unsigned int) will always overflow destination buffer
    131   // CLANG: error: 'stpcpy' called with string bigger than buffer
    132   stpcpy(buf, "foobar");
    133 
    134   // NOLINTNEXTLINE(whitespace/line_length)
    135   // GCC: warning: call to char* __builtin___stpcpy_chk(char*, const char*, {{(long )?}}unsigned int) will always overflow destination buffer
    136   // CLANG: error: 'stpcpy' called with string bigger than buffer
    137   stpcpy(buf, "quux");
    138 }
    139 
    140 void test_strncpy() {
    141   char buf[4];
    142 
    143   // NOLINTNEXTLINE(whitespace/line_length)
    144   // GCC: warning: call to char* __builtin___strncpy_chk(char*, const char*, {{(long )?}}unsigned int, {{(long )?}}unsigned int) will always overflow destination buffer
    145   // clang should emit a warning, but doesn't
    146   strncpy(buf, "foobar", sizeof("foobar"));
    147 }
    148 
    149 void test_strcat() {
    150   char buf[4] = "";
    151 
    152   // NOLINTNEXTLINE(whitespace/line_length)
    153   // GCC: warning: call to {{(char\* __builtin___strcat_chk\(char\*, const char\*, unsigned int\))|(void\* __builtin___memcpy_chk\(void\*, const void\*, (long )?unsigned int, (long )?unsigned int\))}} will always overflow destination buffer
    154   // clang should emit a warning, but doesn't
    155   strcat(buf, "foobar");  // NOLINT(runtime/printf)
    156 }
    157 
    158 void test_strncat() {
    159   char buf[4] = "";
    160 
    161   // NOLINTNEXTLINE(whitespace/line_length)
    162   // GCC: warning: call to {{(char\* __builtin___strcat_chk\(char\*, const char\*, unsigned int\))|(void\* __builtin___memcpy_chk\(void\*, const void\*, (long )?unsigned int, (long )?unsigned int\))}} will always overflow destination buffer
    163   // gcc output warning with __builtin___strcat_chk for __builtin___strncat_chk.
    164   // clang should emit a warning, but doesn't
    165   strncat(buf, "foobar", sizeof("foobar"));
    166 }
    167 
    168 void test_vsprintf(const char* fmt, ...) {
    169   va_list va;
    170   char buf[4];
    171   va_start(va, fmt);
    172 
    173   // NOLINTNEXTLINE(whitespace/line_length)
    174   // GCC: warning: call to int __builtin___vsprintf_chk(char*, int, {{(long )?}}unsigned int, const char*, {{(__va_list)|(void\*)|(char\*)|(__va_list_tag\*)}}) will always overflow destination buffer
    175   // clang should emit a warning, but doesn't
    176   vsprintf(buf, "foobar", va);
    177   va_end(va);
    178 }
    179 
    180 void test_vsnprintf(const char* fmt, ...) {
    181   va_list va;
    182   char buf[4];
    183   va_start(va, fmt);
    184 
    185   // NOLINTNEXTLINE(whitespace/line_length)
    186   // GCC: warning: call to int __builtin___vsnprintf_chk(char*, {{(long )?}}unsigned int, int, {{(long )?}}unsigned int, const char*, {{(__va_list)|(void\*)|(char\*)|(__va_list_tag\*)}}) will always overflow destination buffer
    187   // clang should emit a warning, but doesn't
    188   vsnprintf(buf, 5, "foobar", va);  // NOLINT(runtime/printf)
    189 
    190   va_end(va);
    191 }
    192 
    193 void test_fgets() {
    194   char buf[4];
    195 
    196   // NOLINTNEXTLINE(whitespace/line_length)
    197   // GCC: error: call to '__fgets_too_small_error' declared with attribute error: fgets called with size less than zero
    198   // CLANG: error: in call to 'fgets', size should not be negative
    199   fgets(buf, -1, stdin);
    200 
    201   // NOLINTNEXTLINE(whitespace/line_length)
    202   // GCC: error: call to '__fgets_too_big_error' declared with attribute error: fgets called with size bigger than buffer
    203   // CLANG: error: in call to 'fgets', size is larger than the destination buffer
    204   fgets(buf, 6, stdin);
    205 }
    206 
    207 void test_recvfrom() {
    208   char buf[4];
    209   sockaddr_in addr;
    210 
    211   // NOLINTNEXTLINE(whitespace/line_length)
    212   // GCC: error: call to '__recvfrom_error' declared with attribute error: 'recvfrom' called with size bigger than buffer
    213   // CLANG: error: 'recvfrom' called with size bigger than buffer
    214   recvfrom(0, buf, 6, 0, reinterpret_cast<sockaddr*>(&addr), NULL);
    215 }
    216 
    217 void test_recv() {
    218   char buf[4] = {0};
    219 
    220   // NOLINTNEXTLINE(whitespace/line_length)
    221   // GCC: error: call to '__recvfrom_error' declared with attribute error: 'recvfrom' called with size bigger than buffer
    222   // CLANG: error: 'recv' called with size bigger than buffer
    223   recv(0, buf, 6, 0);
    224 }
    225 
    226 void test_umask() {
    227   // NOLINTNEXTLINE(whitespace/line_length)
    228   // GCC: error: call to '__umask_invalid_mode' declared with attribute error: 'umask' called with invalid mode
    229   // CLANG: error: 'umask' called with invalid mode
    230   umask(01777);
    231 }
    232 
    233 void test_read() {
    234   char buf[4];
    235   // NOLINTNEXTLINE(whitespace/line_length)
    236   // GCC: error: call to '__read_dest_size_error' declared with attribute error: read called with size bigger than destination
    237   // CLANG: error: in call to 'read', 'count' bytes overflows the given object
    238   read(0, buf, 6);
    239 }
    240 
    241 void test_open() {
    242   // NOLINTNEXTLINE(whitespace/line_length)
    243   // GCC: error: call to '__creat_missing_mode' declared with attribute error: called with O_CREAT or O_TMPFILE, but missing mode
    244   // CLANG: error: 'open' called with O_CREAT or O_TMPFILE, but missing mode
    245   open("/dev/null", O_CREAT);
    246 
    247   // GCC: error: call to '__creat_missing_mode' declared with attribute error: called with O_CREAT or O_TMPFILE, but missing mode
    248   // CLANG: error: 'open' called with O_CREAT or O_TMPFILE, but missing mode
    249   open("/dev/null", O_TMPFILE);
    250 
    251   // NOLINTNEXTLINE(whitespace/line_length)
    252   // GCC: error: call to '__creat_too_many_args' declared with attribute error: too many arguments
    253   // CLANG: error: call to unavailable function 'open': too many arguments
    254   open("/dev/null", O_CREAT, 0, 0);
    255 
    256   // GCC: error: call to '__creat_too_many_args' declared with attribute error: too many arguments
    257   // CLANG: error: call to unavailable function 'open': too many arguments
    258   open("/dev/null", O_TMPFILE, 0, 0);
    259 
    260   // CLANG: warning: 'open' has superfluous mode bits; missing O_CREAT?
    261   open("/dev/null", O_RDONLY, 0644);
    262 
    263   // CLANG: warning: 'open' has superfluous mode bits; missing O_CREAT?
    264   open("/dev/null", O_DIRECTORY, 0644);
    265 }
    266 
    267 void test_poll() {
    268   pollfd fds[1];
    269   // NOLINTNEXTLINE(whitespace/line_length)
    270   // GCC: error: call to '__poll_too_small_error' declared with attribute error: poll: pollfd array smaller than fd count
    271   // CLANG: error: in call to 'poll', fd_count is larger than the given buffer
    272   poll(fds, 2, 0);
    273 }
    274 
    275 void test_ppoll() {
    276   pollfd fds[1];
    277   timespec timeout;
    278   // NOLINTNEXTLINE(whitespace/line_length)
    279   // GCC: error: call to '__ppoll_too_small_error' declared with attribute error: ppoll: pollfd array smaller than fd count
    280   // CLANG: error: in call to 'ppoll', fd_count is larger than the given buffer
    281   ppoll(fds, 2, &timeout, NULL);
    282 }
    283 
    284 void test_fread_overflow() {
    285   char buf[4];
    286   // NOLINTNEXTLINE(whitespace/line_length)
    287   // GCC: error: call to '__fread_overflow' declared with attribute error: fread called with overflowing size * count
    288   // CLANG: error: in call to 'fread', size * count overflows
    289   fread(buf, 2, (size_t)-1, stdin);
    290 }
    291 
    292 void test_fread_too_big() {
    293   char buf[4];
    294   // NOLINTNEXTLINE(whitespace/line_length)
    295   // GCC: error: call to '__fread_too_big_error' declared with attribute error: fread called with size * count bigger than buffer
    296   // NOLINTNEXTLINE(whitespace/line_length)
    297   // CLANG: error: in call to 'fread', size * count is too large for the given buffer
    298   fread(buf, 1, 5, stdin);
    299 }
    300 
    301 void test_fwrite_overflow() {
    302   char buf[4] = {0};
    303   // NOLINTNEXTLINE(whitespace/line_length)
    304   // GCC: error: call to '__fwrite_overflow' declared with attribute error: fwrite called with overflowing size * count
    305   // CLANG: error: in call to 'fwrite', size * count overflows
    306   fwrite(buf, 2, (size_t)-1, stdout);
    307 }
    308 
    309 void test_fwrite_too_big() {
    310   char buf[4] = {0};
    311   // NOLINTNEXTLINE(whitespace/line_length)
    312   // GCC: error: call to '__fwrite_too_big_error' declared with attribute error: fwrite called with size * count bigger than buffer
    313   // NOLINTNEXTLINE(whitespace/line_length)
    314   // CLANG: error: in call to 'fwrite', size * count is too large for the given buffer
    315   fwrite(buf, 1, 5, stdout);
    316 }
    317 
    318 void test_getcwd() {
    319   char buf[4];
    320   // NOLINTNEXTLINE(whitespace/line_length)
    321   // GCC: error: call to '__getcwd_dest_size_error' declared with attribute error: getcwd called with size bigger than destination
    322   // CLANG: error: in call to 'getcwd', 'size' bytes overflows the given object
    323   getcwd(buf, 5);
    324 }
    325 
    326 void test_pwrite64_size() {
    327   char buf[4] = {0};
    328   // NOLINTNEXTLINE(whitespace/line_length)
    329   // GCC: error: call to '__pwrite64_dest_size_error' declared with attribute error: pwrite64 called with size bigger than destination
    330   // CLANG: error: in call to 'pwrite64', 'count' bytes overflows the given object
    331   pwrite64(STDOUT_FILENO, buf, 5, 0);
    332 }
    333 
    334 void test_pwrite64_too_big_malloc() {
    335   void *buf = calloc(atoi("5"), 1);
    336   // NOLINTNEXTLINE(whitespace/line_length)
    337   // GCC: error: call to '__pwrite64_count_toobig_error' declared with attribute error: pwrite64 called with count > SSIZE_MAX
    338   // clang should emit a warning, but probably never will.
    339   pwrite64(STDOUT_FILENO, buf, SIZE_MAX, 0);
    340 }
    341 
    342 void test_pwrite64_too_big() {
    343   char buf[4] = {0};
    344   // NOLINTNEXTLINE(whitespace/line_length)
    345   // GCC: error: call to '__pwrite64_count_toobig_error' declared with attribute error: pwrite64 called with count > SSIZE_MAX
    346   // CLANG: error: in call to 'pwrite64', 'count' must be <= SSIZE_MAX
    347   pwrite64(STDOUT_FILENO, buf, SIZE_MAX, 0);
    348 }
    349 
    350 void test_write_size() {
    351   char buf[4] = {0};
    352   // NOLINTNEXTLINE(whitespace/line_length)
    353   // GCC: error: call to '__write_dest_size_error' declared with attribute error: write called with size bigger than destination
    354   // CLANG: error: in call to 'write', 'count' bytes overflows the given object
    355   write(STDOUT_FILENO, buf, 5);
    356 }
    357 
    358 void test_memset_args_flipped() {
    359   char from[4] = {0};
    360   // NOLINTNEXTLINE(whitespace/line_length)
    361   // CLANG: 'memset' will set 0 bytes; maybe the arguments got flipped?
    362   memset(from, sizeof(from), 0);
    363 }
    364 
    365 void test_sendto() {
    366   char buf[4] = {0};
    367   sockaddr_in addr;
    368 
    369   // NOLINTNEXTLINE(whitespace/line_length)
    370   // GCC: error: call to '__sendto_error' declared with attribute error: 'sendto' called with size bigger than buffer
    371   // CLANG: error: 'sendto' called with size bigger than buffer
    372   sendto(0, buf, 6, 0, reinterpret_cast<sockaddr*>(&addr), sizeof(sockaddr_in));
    373 }
    374 
    375 void test_send() {
    376   char buf[4] = {0};
    377 
    378   // NOLINTNEXTLINE(whitespace/line_length)
    379   // GCC: error: call to '__sendto_error' declared with attribute error: 'sendto' called with size bigger than buffer
    380   // CLANG: error: 'send' called with size bigger than buffer
    381   send(0, buf, 6, 0);
    382 }
    383 
    384 void test_realpath() {
    385   char buf[4] = {0};
    386   // NOLINTNEXTLINE(whitespace/line_length)
    387   // GCC: error: call to '__realpath_size_error' declared with attribute error: 'realpath' output parameter must be NULL or a pointer to a buffer with >= PATH_MAX bytes
    388   // NOLINTNEXTLINE(whitespace/line_length)
    389   // CLANG: error: 'realpath' output parameter must be NULL or a pointer to a buffer with >= PATH_MAX bytes
    390   realpath(".", buf);
    391 
    392   // This is fine.
    393   realpath(".", NULL);
    394 
    395   char bigbuf[PATH_MAX];
    396   // CLANG: error: 'realpath': NULL path is never correct; flipped arguments?
    397   realpath(NULL, bigbuf);
    398 }
    399