| 1 | // RUN: %clang_cc1 -fsyntax-only -verify -Wno-sizeof-array-argument %s |
| 2 | // |
| 3 | extern "C" void *bzero(void *, unsigned); |
| 4 | extern "C" void *memset(void *, int, unsigned); |
| 5 | extern "C" void *memmove(void *s1, const void *s2, unsigned n); |
| 6 | extern "C" void *memcpy(void *s1, const void *s2, unsigned n); |
| 7 | extern "C" void *memcmp(void *s1, const void *s2, unsigned n); |
| 8 | |
| 9 | struct S {int a, b, c, d;}; |
| 10 | typedef S* PS; |
| 11 | |
| 12 | struct Foo {}; |
| 13 | typedef const Foo& CFooRef; |
| 14 | typedef const Foo CFoo; |
| 15 | typedef volatile Foo VFoo; |
| 16 | typedef const volatile Foo CVFoo; |
| 17 | |
| 18 | typedef double Mat[4][4]; |
| 19 | |
| 20 | template <class Dest, class Source> |
| 21 | inline Dest bit_cast(const Source& source) { |
| 22 | Dest dest; |
| 23 | memcpy(&dest, &source, sizeof(dest)); |
| 24 | return dest; |
| 25 | } |
| 26 | |
| 27 | // http://www.lysator.liu.se/c/c-faq/c-2.html#2-6 |
| 28 | void f(Mat m, const Foo& const_foo, char *buffer) { |
| 29 | S s; |
| 30 | S* ps = &s; |
| 31 | PS ps2 = &s; |
| 32 | char arr[5]; |
| 33 | char* parr[5]; |
| 34 | Foo foo; |
| 35 | char* heap_buffer = new char[42]; |
| 36 | |
| 37 | /* Should warn */ |
| 38 | memset(&s, 0, sizeof(&s)); // \ |
| 39 | // expected-warning {{'memset' call operates on objects of type 'S' while the size is based on a different type 'S *'}} expected-note{{did you mean to remove the addressof in the argument to 'sizeof' (and multiply it by the number of elements)?}} |
| 40 | memset(ps, 0, sizeof(ps)); // \ |
| 41 | // expected-warning {{'memset' call operates on objects of type 'S' while the size is based on a different type 'S *'}} expected-note{{did you mean to dereference the argument to 'sizeof' (and multiply it by the number of elements)?}} |
| 42 | memset(ps2, 0, sizeof(ps2)); // \ |
| 43 | // expected-warning {{'memset' call operates on objects of type 'S' while the size is based on a different type 'PS' (aka 'S *')}} expected-note{{did you mean to dereference the argument to 'sizeof' (and multiply it by the number of elements)?}} |
| 44 | memset(ps2, 0, sizeof(typeof(ps2))); // \ |
| 45 | // expected-warning {{argument to 'sizeof' in 'memset' call is the same pointer type}} |
| 46 | memset(ps2, 0, sizeof(PS)); // \ |
| 47 | // expected-warning {{argument to 'sizeof' in 'memset' call is the same pointer type}} |
| 48 | memset(heap_buffer, 0, sizeof(heap_buffer)); // \ |
| 49 | // expected-warning {{'memset' call operates on objects of type 'char' while the size is based on a different type 'char *'}} expected-note{{did you mean to provide an explicit length?}} |
| 50 | |
| 51 | bzero(&s, sizeof(&s)); // \ |
| 52 | // expected-warning {{'bzero' call operates on objects of type 'S' while the size is based on a different type 'S *'}} expected-note{{did you mean to remove the addressof in the argument to 'sizeof' (and multiply it by the number of elements)?}} |
| 53 | bzero(ps, sizeof(ps)); // \ |
| 54 | // expected-warning {{'bzero' call operates on objects of type 'S' while the size is based on a different type 'S *'}} expected-note{{did you mean to dereference the argument to 'sizeof' (and multiply it by the number of elements)?}} |
| 55 | bzero(ps2, sizeof(ps2)); // \ |
| 56 | // expected-warning {{'bzero' call operates on objects of type 'S' while the size is based on a different type 'PS' (aka 'S *')}} expected-note{{did you mean to dereference the argument to 'sizeof' (and multiply it by the number of elements)?}} |
| 57 | bzero(ps2, sizeof(typeof(ps2))); // \ |
| 58 | // expected-warning {{argument to 'sizeof' in 'bzero' call is the same pointer type}} |
| 59 | bzero(ps2, sizeof(PS)); // \ |
| 60 | // expected-warning {{argument to 'sizeof' in 'bzero' call is the same pointer type}} |
| 61 | bzero(heap_buffer, sizeof(heap_buffer)); // \ |
| 62 | // expected-warning {{'bzero' call operates on objects of type 'char' while the size is based on a different type 'char *'}} expected-note{{did you mean to provide an explicit length?}} |
| 63 | |
| 64 | memcpy(&s, 0, sizeof(&s)); // \ |
| 65 | // expected-warning {{'memcpy' call operates on objects of type 'S' while the size is based on a different type 'S *'}} expected-note{{did you mean to remove the addressof in the argument to 'sizeof' (and multiply it by the number of elements)?}} |
| 66 | memcpy(0, &s, sizeof(&s)); // \ |
| 67 | // expected-warning {{'memcpy' call operates on objects of type 'S' while the size is based on a different type 'S *'}} expected-note{{did you mean to remove the addressof in the argument to 'sizeof' (and multiply it by the number of elements)?}} |
| 68 | |
| 69 | memmove(ps, 0, sizeof(ps)); // \ |
| 70 | // expected-warning {{'memmove' call operates on objects of type 'S' while the size is based on a different type 'S *'}} expected-note{{did you mean to dereference the argument to 'sizeof' (and multiply it by the number of elements)?}} |
| 71 | memcmp(ps, 0, sizeof(ps)); // \ |
| 72 | // expected-warning {{'memcmp' call operates on objects of type 'S' while the size is based on a different type 'S *'}} expected-note{{did you mean to dereference the argument to 'sizeof' (and multiply it by the number of elements)?}} |
| 73 | |
| 74 | /* Shouldn't warn */ |
| 75 | memset((void*)&s, 0, sizeof(&s)); |
| 76 | memset(&s, 0, sizeof(s)); |
| 77 | memset(&s, 0, sizeof(S)); |
| 78 | memset(&s, 0, sizeof(const S)); |
| 79 | memset(&s, 0, sizeof(volatile S)); |
| 80 | memset(&s, 0, sizeof(volatile const S)); |
| 81 | memset(&foo, 0, sizeof(CFoo)); |
| 82 | memset(&foo, 0, sizeof(VFoo)); |
| 83 | memset(&foo, 0, sizeof(CVFoo)); |
| 84 | memset(ps, 0, sizeof(*ps)); |
| 85 | memset(ps2, 0, sizeof(*ps2)); |
| 86 | memset(ps2, 0, sizeof(typeof(*ps2))); |
| 87 | memset(arr, 0, sizeof(arr)); |
| 88 | memset(parr, 0, sizeof(parr)); |
| 89 | |
| 90 | bzero((void*)&s, sizeof(&s)); |
| 91 | bzero(&s, sizeof(s)); |
| 92 | bzero(&s, sizeof(S)); |
| 93 | bzero(&s, sizeof(const S)); |
| 94 | bzero(&s, sizeof(volatile S)); |
| 95 | bzero(&s, sizeof(volatile const S)); |
| 96 | bzero(&foo, sizeof(CFoo)); |
| 97 | bzero(&foo, sizeof(VFoo)); |
| 98 | bzero(&foo, sizeof(CVFoo)); |
| 99 | bzero(ps, sizeof(*ps)); |
| 100 | bzero(ps2, sizeof(*ps2)); |
| 101 | bzero(ps2, sizeof(typeof(*ps2))); |
| 102 | bzero(arr, sizeof(arr)); |
| 103 | bzero(parr, sizeof(parr)); |
| 104 | |
| 105 | memcpy(&foo, &const_foo, sizeof(Foo)); |
| 106 | memcpy((void*)&s, 0, sizeof(&s)); |
| 107 | memcpy(0, (void*)&s, sizeof(&s)); |
| 108 | char *cptr; |
| 109 | memcpy(&cptr, buffer, sizeof(cptr)); |
| 110 | memcpy((char*)&cptr, buffer, sizeof(cptr)); |
| 111 | |
| 112 | CFooRef cfoo = foo; |
| 113 | memcpy(&foo, &cfoo, sizeof(Foo)); |
| 114 | |
| 115 | memcpy(0, &arr, sizeof(arr)); |
| 116 | typedef char Buff[8]; |
| 117 | memcpy(0, &arr, sizeof(Buff)); |
| 118 | |
| 119 | unsigned char* puc; |
| 120 | bit_cast<char*>(puc); |
| 121 | |
| 122 | float* pf; |
| 123 | bit_cast<int*>(pf); |
| 124 | |
| 125 | int iarr[14]; |
| 126 | memset(&iarr[0], 0, sizeof iarr); |
| 127 | memset(iarr, 0, sizeof iarr); |
| 128 | bzero(&iarr[0], sizeof iarr); |
| 129 | bzero(iarr, sizeof iarr); |
| 130 | |
| 131 | int* iparr[14]; |
| 132 | memset(&iparr[0], 0, sizeof iparr); |
| 133 | memset(iparr, 0, sizeof iparr); |
| 134 | bzero(&iparr[0], sizeof iparr); |
| 135 | bzero(iparr, sizeof iparr); |
| 136 | |
| 137 | memset(m, 0, sizeof(Mat)); |
| 138 | bzero(m, sizeof(Mat)); |
| 139 | |
| 140 | // Copy to raw buffer shouldn't warn either |
| 141 | memcpy(&foo, &arr, sizeof(Foo)); |
| 142 | memcpy(&arr, &foo, sizeof(Foo)); |
| 143 | |
| 144 | // Shouldn't warn, and shouldn't crash either. |
| 145 | memset(({ |
| 146 | if (0) {} |
| 147 | while (0) {} |
| 148 | for (;;) {} |
| 149 | &s; |
| 150 | }), 0, sizeof(s)); |
| 151 | |
| 152 | bzero(({ |
| 153 | if (0) {} |
| 154 | while (0) {} |
| 155 | for (;;) {} |
| 156 | &s; |
| 157 | }), sizeof(s)); |
| 158 | } |
| 159 | |
| 160 | namespace ns { |
| 161 | void memset(void* s, char c, int n); |
| 162 | void bzero(void* s, int n); |
| 163 | void f(int* i) { |
| 164 | memset(i, 0, sizeof(i)); |
| 165 | bzero(i, sizeof(i)); |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | extern "C" int strncmp(const char *s1, const char *s2, unsigned n); |
| 170 | extern "C" int strncasecmp(const char *s1, const char *s2, unsigned n); |
| 171 | extern "C" char *strncpy(char *det, const char *src, unsigned n); |
| 172 | extern "C" char *strncat(char *dst, const char *src, unsigned n); |
| 173 | extern "C" char *strndup(const char *src, unsigned n); |
| 174 | |
| 175 | void strcpy_and_friends() { |
| 176 | const char* FOO = "<- should be an array instead"; |
| 177 | const char* BAR = "<- this, too"; |
| 178 | |
| 179 | strncmp(FOO, BAR, sizeof(FOO)); // \ |
| 180 | // expected-warning {{'strncmp' call operates on objects of type 'const char' while the size is based on a different type 'const char *'}} expected-note{{did you mean to provide an explicit length?}} |
| 181 | strncasecmp(FOO, BAR, sizeof(FOO)); // \ |
| 182 | // expected-warning {{'strncasecmp' call operates on objects of type 'const char' while the size is based on a different type 'const char *'}} expected-note{{did you mean to provide an explicit length?}} |
| 183 | |
| 184 | char buff[80]; |
| 185 | |
| 186 | strncpy(buff, BAR, sizeof(BAR)); // \ |
| 187 | // expected-warning {{'strncpy' call operates on objects of type 'const char' while the size is based on a different type 'const char *'}} expected-note{{did you mean to provide an explicit length?}} |
| 188 | strndup(FOO, sizeof(FOO)); // \ |
| 189 | // expected-warning {{'strndup' call operates on objects of type 'const char' while the size is based on a different type 'const char *'}} expected-note{{did you mean to provide an explicit length?}} |
| 190 | } |
| 191 | |