| // RUN: %clang_analyze_cc1 -verify %s \ |
| // RUN: -analyzer-checker=core \ |
| // RUN: -analyzer-checker=unix.cstring \ |
| // RUN: -analyzer-checker=alpha.unix.cstring \ |
| // RUN: -analyzer-disable-checker=alpha.unix.cstring.UninitializedRead \ |
| // RUN: -analyzer-checker=debug.ExprInspection \ |
| // RUN: -analyzer-config eagerly-assume=false |
| // |
| // RUN: %clang_analyze_cc1 -verify %s -DUSE_BUILTINS \ |
| // RUN: -analyzer-checker=core \ |
| // RUN: -analyzer-checker=unix.cstring \ |
| // RUN: -analyzer-checker=alpha.unix.cstring \ |
| // RUN: -analyzer-disable-checker=alpha.unix.cstring.UninitializedRead \ |
| // RUN: -analyzer-checker=debug.ExprInspection \ |
| // RUN: -analyzer-config eagerly-assume=false |
| |
| //===----------------------------------------------------------------------=== |
| // Declarations |
| //===----------------------------------------------------------------------=== |
| |
| // Some functions are implemented as builtins. These should be #defined as |
| // BUILTIN(f), which will prepend "__builtin_" if USE_BUILTINS is defined. |
| |
| #ifdef USE_BUILTINS |
| # define BUILTIN(f) __builtin_ ## f |
| #else /* USE_BUILTINS */ |
| # define BUILTIN(f) f |
| #endif /* USE_BUILTINS */ |
| |
| typedef __SIZE_TYPE__ size_t; |
| typedef __WCHAR_TYPE__ wchar_t; |
| |
| void clang_analyzer_eval(int); |
| |
| //===----------------------------------------------------------------------=== |
| // wmemcpy() |
| //===----------------------------------------------------------------------=== |
| |
| #define wmemcpy BUILTIN(wmemcpy) |
| wchar_t *wmemcpy(wchar_t *restrict s1, const wchar_t *restrict s2, size_t n); |
| |
| void wmemcpy0 (void) { |
| wchar_t src[] = {1, 2, 3, 4}; |
| wchar_t dst[4] = {0}; |
| |
| wmemcpy(dst, src, 4); // no-warning |
| |
| clang_analyzer_eval(wmemcpy(dst, src, 4) == dst); // expected-warning{{TRUE}} |
| |
| // If we actually model the copy, we can make this known. |
| // The important thing for now is that the old value has been invalidated. |
| clang_analyzer_eval(dst[0] != 0); // expected-warning{{UNKNOWN}} |
| } |
| |
| void wmemcpy1 (void) { |
| wchar_t src[] = {1, 2, 3, 4}; |
| wchar_t dst[10]; |
| |
| wmemcpy(dst, src, 5); // expected-warning{{Memory copy function accesses out-of-bound array element}} |
| } |
| |
| void wmemcpy2 (void) { |
| wchar_t src[] = {1, 2, 3, 4}; |
| wchar_t dst[1]; |
| |
| wmemcpy(dst, src, 4); // expected-warning {{Memory copy function overflows the destination buffer}} |
| } |
| |
| void wmemcpy3 (void) { |
| wchar_t src[] = {1, 2, 3, 4}; |
| wchar_t dst[3]; |
| |
| wmemcpy(dst+1, src+2, 2); // no-warning |
| } |
| |
| void wmemcpy4 (void) { |
| wchar_t src[] = {1, 2, 3, 4}; |
| wchar_t dst[10]; |
| |
| wmemcpy(dst+2, src+2, 3); // expected-warning{{Memory copy function accesses out-of-bound array element}} |
| } |
| |
| void wmemcpy5(void) { |
| wchar_t src[] = {1, 2, 3, 4}; |
| wchar_t dst[3]; |
| |
| wmemcpy(dst + 2, src + 2, 2); // expected-warning{{Memory copy function overflows the destination buffer}} |
| } |
| |
| void wmemcpy6(void) { |
| wchar_t a[4] = {0}; |
| wmemcpy(a, a, 2); // expected-warning{{overlapping}} |
| } |
| |
| void wmemcpy7(void) { |
| wchar_t a[4] = {0}; |
| wmemcpy(a+2, a+1, 2); // expected-warning{{overlapping}} |
| } |
| |
| void wmemcpy8(void) { |
| wchar_t a[4] = {0}; |
| wmemcpy(a+1, a+2, 2); // expected-warning{{overlapping}} |
| } |
| |
| void wmemcpy9(void) { |
| wchar_t a[4] = {0}; |
| wmemcpy(a+2, a+1, 1); // no-warning |
| wmemcpy(a+1, a+2, 1); // no-warning |
| } |
| |
| void wmemcpy10(void) { |
| wchar_t a[4] = {0}; |
| wmemcpy(0, a, 1); // expected-warning{{Null pointer passed as 1st argument to memory copy function}} |
| } |
| |
| void wmemcpy11(void) { |
| wchar_t a[4] = {0}; |
| wmemcpy(a, 0, 1); // expected-warning{{Null pointer passed as 2nd argument to memory copy function}} |
| } |
| |
| void wmemcpy12(void) { |
| wchar_t a[4] = {0}; |
| wmemcpy(0, a, 0); // no-warning |
| } |
| |
| void wmemcpy13(void) { |
| wchar_t a[4] = {0}; |
| wmemcpy(a, 0, 0); // no-warning |
| } |
| |
| void wmemcpy_unknown_size (size_t n) { |
| wchar_t a[4], b[4] = {1}; |
| clang_analyzer_eval(wmemcpy(a, b, n) == a); // expected-warning{{TRUE}} |
| } |
| |
| void wmemcpy_unknown_size_warn (size_t n) { |
| wchar_t a[4]; |
| void *result = wmemcpy(a, 0, n); // expected-warning{{Null pointer passed as 2nd argument to memory copy function}} |
| clang_analyzer_eval(result == a); // no-warning (above is fatal) |
| } |
| |
| //===----------------------------------------------------------------------=== |
| // wmempcpy() |
| //===----------------------------------------------------------------------=== |
| |
| wchar_t *wmempcpy(wchar_t *restrict s1, const wchar_t *restrict s2, size_t n); |
| |
| void wmempcpy0 (void) { |
| wchar_t src[] = {1, 2, 3, 4}; |
| wchar_t dst[5] = {0}; |
| |
| wmempcpy(dst, src, 4); // no-warning |
| |
| clang_analyzer_eval(wmempcpy(dst, src, 4) == &dst[4]); // expected-warning{{TRUE}} |
| |
| // If we actually model the copy, we can make this known. |
| // The important thing for now is that the old value has been invalidated. |
| clang_analyzer_eval(dst[0] != 0); // expected-warning{{UNKNOWN}} |
| } |
| |
| void wmempcpy1 (void) { |
| wchar_t src[] = {1, 2, 3, 4}; |
| wchar_t dst[10]; |
| |
| wmempcpy(dst, src, 5); // expected-warning{{Memory copy function accesses out-of-bound array element}} |
| } |
| |
| void wmempcpy2 (void) { |
| wchar_t src[] = {1, 2, 3, 4}; |
| wchar_t dst[1]; |
| |
| wmempcpy(dst, src, 4); // expected-warning{{Memory copy function overflows the destination buffer}} |
| } |
| |
| void wmempcpy3 (void) { |
| wchar_t src[] = {1, 2, 3, 4}; |
| wchar_t dst[3]; |
| |
| wmempcpy(dst+1, src+2, 2); // no-warning |
| } |
| |
| void wmempcpy4 (void) { |
| wchar_t src[] = {1, 2, 3, 4}; |
| wchar_t dst[10]; |
| |
| wmempcpy(dst+2, src+2, 3); // expected-warning{{Memory copy function accesses out-of-bound array element}} |
| } |
| |
| void wmempcpy5(void) { |
| wchar_t src[] = {1, 2, 3, 4}; |
| wchar_t dst[3]; |
| |
| wmempcpy(dst + 2, src + 2, 2); // expected-warning{{Memory copy function overflows the destination buffer}} |
| } |
| |
| void wmempcpy6(void) { |
| wchar_t a[4] = {0}; |
| wmempcpy(a, a, 2); // expected-warning{{overlapping}} |
| } |
| |
| void wmempcpy7(void) { |
| wchar_t a[4] = {0}; |
| wmempcpy(a+2, a+1, 2); // expected-warning{{overlapping}} |
| } |
| |
| void wmempcpy8(void) { |
| wchar_t a[4] = {0}; |
| wmempcpy(a+1, a+2, 2); // expected-warning{{overlapping}} |
| } |
| |
| void wmempcpy9(void) { |
| wchar_t a[4] = {0}; |
| wmempcpy(a+2, a+1, 1); // no-warning |
| wmempcpy(a+1, a+2, 1); // no-warning |
| } |
| |
| void wmempcpy10(void) { |
| wchar_t a[4] = {0}; |
| wmempcpy(0, a, 1); // expected-warning{{Null pointer passed as 1st argument to memory copy function}} |
| } |
| |
| void wmempcpy11(void) { |
| wchar_t a[4] = {0}; |
| wmempcpy(a, 0, 1); // expected-warning{{Null pointer passed as 2nd argument to memory copy function}} |
| } |
| |
| void wmempcpy12(void) { |
| wchar_t a[4] = {0}; |
| wmempcpy(0, a, 0); // no-warning |
| } |
| |
| void wmempcpy13(void) { |
| wchar_t a[4] = {0}; |
| wmempcpy(a, 0, 0); // no-warning |
| } |
| |
| void wmempcpy14(void) { |
| wchar_t src[] = {1, 2, 3, 4}; |
| wchar_t dst[5] = {0}; |
| wchar_t *p; |
| |
| p = wmempcpy(dst, src, 4); |
| |
| clang_analyzer_eval(p == &dst[4]); // expected-warning{{TRUE}} |
| } |
| |
| struct st { |
| wchar_t i; |
| wchar_t j; |
| }; |
| |
| void wmempcpy15(void) { |
| struct st s1 = {0}; |
| struct st s2; |
| struct st *p1; |
| struct st *p2; |
| |
| p1 = (&s2) + 1; |
| p2 = (struct st *)wmempcpy((wchar_t *)&s2, (wchar_t *)&s1, 2); |
| |
| clang_analyzer_eval(p1 == p2); // expected-warning{{TRUE}} |
| } |
| |
| void wmempcpy16(void) { |
| struct st s1[10] = {{0}}; |
| struct st s2[10]; |
| struct st *p1; |
| struct st *p2; |
| |
| p1 = (&s2[0]) + 5; |
| p2 = (struct st *)wmempcpy((wchar_t *)&s2[0], (wchar_t *)&s1[0], 5 * 2); |
| |
| clang_analyzer_eval(p1 == p2); // expected-warning{{TRUE}} |
| } |
| |
| void wmempcpy_unknown_size_warn (size_t n) { |
| wchar_t a[4]; |
| void *result = wmempcpy(a, 0, n); // expected-warning{{Null pointer passed as 2nd argument to memory copy function}} |
| clang_analyzer_eval(result == a); // no-warning (above is fatal) |
| } |
| |
| void wmempcpy_unknownable_size (wchar_t *src, float n) { |
| wchar_t a[4]; |
| // This used to crash because we don't model floats. |
| wmempcpy(a, src, (size_t)n); |
| } |
| |
| //===----------------------------------------------------------------------=== |
| // wmemmove() |
| //===----------------------------------------------------------------------=== |
| |
| #define wmemmove BUILTIN(wmemmove) |
| wchar_t *wmemmove(wchar_t *s1, const wchar_t *s2, size_t n); |
| |
| void wmemmove0 (void) { |
| wchar_t src[] = {1, 2, 3, 4}; |
| wchar_t dst[4] = {0}; |
| |
| wmemmove(dst, src, 4); // no-warning |
| |
| clang_analyzer_eval(wmemmove(dst, src, 4) == dst); // expected-warning{{TRUE}} |
| |
| clang_analyzer_eval(dst[0] != 0); // expected-warning{{UNKNOWN}} |
| } |
| |
| void wmemmove1 (void) { |
| wchar_t src[] = {1, 2, 3, 4}; |
| wchar_t dst[10]; |
| |
| wmemmove(dst, src, 5); // expected-warning{{out-of-bound}} |
| } |
| |
| void wmemmove2 (void) { |
| wchar_t src[] = {1, 2, 3, 4}; |
| wchar_t dst[1]; |
| |
| wmemmove(dst, src, 4); // expected-warning{{Memory copy function overflows the destination buffer}} |
| } |
| |
| //===----------------------------------------------------------------------=== |
| // wmemcmp() |
| //===----------------------------------------------------------------------=== |
| |
| #define wmemcmp BUILTIN(wmemcmp) |
| int wmemcmp(const wchar_t *s1, const wchar_t *s2, size_t n); |
| |
| void wmemcmp0 (void) { |
| wchar_t a[] = {1, 2, 3, 4}; |
| wchar_t b[4] = { 0 }; |
| |
| wmemcmp(a, b, 4); // no-warning |
| } |
| |
| void wmemcmp1 (void) { |
| wchar_t a[] = {1, 2, 3, 4}; |
| wchar_t b[10] = { 0 }; |
| |
| wmemcmp(a, b, 5); // expected-warning{{out-of-bound}} |
| } |
| |
| void wmemcmp2 (void) { |
| wchar_t a[] = {1, 2, 3, 4}; |
| wchar_t b[1] = { 0 }; |
| |
| wmemcmp(a, b, 4); // expected-warning{{out-of-bound}} |
| } |
| |
| void wmemcmp3 (void) { |
| wchar_t a[] = {1, 2, 3, 4}; |
| |
| clang_analyzer_eval(wmemcmp(a, a, 4) == 0); // expected-warning{{TRUE}} |
| } |
| |
| void wmemcmp4 (wchar_t *input) { |
| wchar_t a[] = {1, 2, 3, 4}; |
| |
| clang_analyzer_eval(wmemcmp(a, input, 4) == 0); // expected-warning{{UNKNOWN}} |
| } |
| |
| void wmemcmp5 (wchar_t *input) { |
| wchar_t a[] = {1, 2, 3, 4}; |
| |
| clang_analyzer_eval(wmemcmp(a, 0, 0) == 0); // expected-warning{{TRUE}} |
| clang_analyzer_eval(wmemcmp(0, a, 0) == 0); // expected-warning{{TRUE}} |
| clang_analyzer_eval(wmemcmp(a, input, 0) == 0); // expected-warning{{TRUE}} |
| } |
| |
| void wmemcmp6 (wchar_t *a, wchar_t *b, size_t n) { |
| int result = wmemcmp(a, b, n); |
| if (result != 0) |
| clang_analyzer_eval(n != 0); // expected-warning{{TRUE}} |
| // else |
| // analyzer_assert_unknown(n == 0); |
| |
| // We can't do the above comparison because n has already been constrained. |
| // On one path n == 0, on the other n != 0. |
| } |
| |
| int wmemcmp7 (wchar_t *a, size_t x, size_t y, size_t n) { |
| // We used to crash when either of the arguments was unknown. |
| return wmemcmp(a, &a[x*y], n) + |
| wmemcmp(&a[x*y], a, n); |
| } |
| |
| int wmemcmp8(wchar_t *a, size_t n) { |
| wchar_t *b = 0; |
| // Do not warn about the first argument! |
| return wmemcmp(a, b, n); // expected-warning{{Null pointer passed as 2nd argument to memory comparison function}} |
| } |
| |
| //===----------------------------------------------------------------------=== |
| // wcslen() |
| //===----------------------------------------------------------------------=== |
| |
| #define wcslen BUILTIN(wcslen) |
| size_t wcslen(const wchar_t *s); |
| |
| void wcslen_constant0(void) { |
| clang_analyzer_eval(wcslen(L"123") == 3); // expected-warning{{TRUE}} |
| } |
| |
| void wcslen_constant1(void) { |
| const wchar_t *a = L"123"; |
| clang_analyzer_eval(wcslen(a) == 3); // expected-warning{{TRUE}} |
| } |
| |
| void wcslen_constant2(wchar_t x) { |
| wchar_t a[] = L"123"; |
| clang_analyzer_eval(wcslen(a) == 3); // expected-warning{{TRUE}} |
| |
| a[0] = x; |
| clang_analyzer_eval(wcslen(a) == 3); // expected-warning{{UNKNOWN}} |
| } |
| |
| size_t wcslen_null(void) { |
| return wcslen(0); // expected-warning{{Null pointer passed as 1st argument to string length function}} |
| } |
| |
| size_t wcslen_fn(void) { |
| return wcslen((wchar_t*)&wcslen_fn); // expected-warning{{Argument to string length function is the address of the function 'wcslen_fn', which is not a null-terminated string}} |
| } |
| |
| size_t wcslen_nonloc(void) { |
| label: |
| return wcslen((wchar_t*)&&label); // expected-warning{{Argument to string length function is the address of the label 'label', which is not a null-terminated string}} |
| } |
| |
| void wcslen_subregion(void) { |
| struct two_strings { wchar_t a[2], b[2]; }; |
| extern void use_two_strings(struct two_strings *); |
| |
| struct two_strings z; |
| use_two_strings(&z); |
| |
| size_t a = wcslen(z.a); |
| z.b[0] = 5; |
| size_t b = wcslen(z.a); |
| if (a == 0) |
| clang_analyzer_eval(b == 0); // expected-warning{{TRUE}} |
| |
| use_two_strings(&z); |
| |
| size_t c = wcslen(z.a); |
| if (a == 0) |
| clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}} |
| } |
| |
| extern void use_string(wchar_t *); |
| void wcslen_argument(wchar_t *x) { |
| size_t a = wcslen(x); |
| size_t b = wcslen(x); |
| if (a == 0) |
| clang_analyzer_eval(b == 0); // expected-warning{{TRUE}} |
| |
| use_string(x); |
| |
| size_t c = wcslen(x); |
| if (a == 0) |
| clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}} |
| } |
| |
| extern wchar_t global_str[]; |
| void wcslen_global(void) { |
| size_t a = wcslen(global_str); |
| size_t b = wcslen(global_str); |
| if (a == 0) { |
| clang_analyzer_eval(b == 0); // expected-warning{{TRUE}} |
| // Make sure clang_analyzer_eval does not invalidate globals. |
| clang_analyzer_eval(wcslen(global_str) == 0); // expected-warning{{TRUE}} |
| } |
| |
| // Call a function with unknown effects, which should invalidate globals. |
| use_string(0); |
| |
| size_t c = wcslen(global_str); |
| if (a == 0) |
| clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}} |
| } |
| |
| void wcslen_indirect(wchar_t *x) { |
| size_t a = wcslen(x); |
| wchar_t *p = x; |
| wchar_t **p2 = &p; |
| size_t b = wcslen(x); |
| if (a == 0) |
| clang_analyzer_eval(b == 0); // expected-warning{{TRUE}} |
| |
| extern void use_string_ptr(wchar_t*const*); |
| use_string_ptr(p2); |
| |
| size_t c = wcslen(x); |
| if (a == 0) |
| clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}} |
| } |
| |
| void wcslen_indirect2(wchar_t *x) { |
| size_t a = wcslen(x); |
| wchar_t *p = x; |
| wchar_t **p2 = &p; |
| extern void use_string_ptr2(wchar_t**); |
| use_string_ptr2(p2); |
| |
| size_t c = wcslen(x); |
| if (a == 0) |
| clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}} |
| } |
| |
| void wcslen_liveness(const wchar_t *x) { |
| if (wcslen(x) < 5) |
| return; |
| clang_analyzer_eval(wcslen(x) < 5); // expected-warning{{FALSE}} |
| } |
| |
| |
| size_t wcslenWrapper(const wchar_t *str) { |
| return wcslen(str); |
| } |
| |
| extern void invalidate(wchar_t *s); |
| |
| void testwcslenCallee(void) { |
| wchar_t str[42]; |
| invalidate(str); |
| size_t lenBefore = wcslenWrapper(str); |
| invalidate(str); |
| size_t lenAfter = wcslenWrapper(str); |
| clang_analyzer_eval(lenBefore == lenAfter); // expected-warning{{UNKNOWN}} |
| } |
| |
| //===----------------------------------------------------------------------=== |
| // wcsnlen() |
| //===----------------------------------------------------------------------=== |
| |
| size_t wcsnlen(const wchar_t *s, size_t maxlen); |
| |
| void wcsnlen_constant0(void) { |
| clang_analyzer_eval(wcsnlen(L"123", 10) == 3); // expected-warning{{TRUE}} |
| } |
| |
| void wcsnlen_constant1(void) { |
| const wchar_t *a = L"123"; |
| clang_analyzer_eval(wcsnlen(a, 10) == 3); // expected-warning{{TRUE}} |
| } |
| |
| void wcsnlen_constant2(char x) { |
| wchar_t a[] = L"123"; |
| clang_analyzer_eval(wcsnlen(a, 10) == 3); // expected-warning{{TRUE}} |
| a[0] = x; |
| clang_analyzer_eval(wcsnlen(a, 10) == 3); // expected-warning{{UNKNOWN}} |
| } |
| |
| void wcsnlen_constant4(void) { |
| clang_analyzer_eval(wcsnlen(L"123456", 3) == 3); // expected-warning{{TRUE}} |
| } |
| |
| void wcsnlen_constant5(void) { |
| const wchar_t *a = L"123456"; |
| clang_analyzer_eval(wcsnlen(a, 3) == 3); // expected-warning{{TRUE}} |
| } |
| |
| void wcsnlen_constant6(char x) { |
| wchar_t a[] = L"123456"; |
| clang_analyzer_eval(wcsnlen(a, 3) == 3); // expected-warning{{TRUE}} |
| a[0] = x; |
| clang_analyzer_eval(wcsnlen(a, 3) == 3); // expected-warning{{UNKNOWN}} |
| } |
| |
| size_t wcsnlen_null(void) { |
| return wcsnlen(0, 3); // expected-warning{{Null pointer passed as 1st argument to string length function}} |
| } |
| |
| size_t wcsnlen_fn(void) { |
| return wcsnlen((wchar_t*)&wcsnlen_fn, 3); // expected-warning{{Argument to string length function is the address of the function 'wcsnlen_fn', which is not a null-terminated string}} |
| } |
| |
| size_t wcsnlen_nonloc(void) { |
| label: |
| return wcsnlen((wchar_t*)&&label, 3); // expected-warning{{Argument to string length function is the address of the label 'label', which is not a null-terminated string}} |
| } |
| |
| void wcsnlen_zero(void) { |
| clang_analyzer_eval(wcsnlen(L"abc", 0) == 0); // expected-warning{{TRUE}} |
| clang_analyzer_eval(wcsnlen(0, 0) == 0); // expected-warning{{TRUE}} |
| } |
| |
| size_t wcsnlen_compound_literal(void) { |
| // This used to crash because we don't model the string lengths of |
| // compound literals. |
| return wcsnlen((wchar_t[]) { 'a', 'b', 0 }, 1); |
| } |
| |
| size_t wcsnlen_unknown_limit(float f) { |
| // This used to crash because we don't model the integer values of floats. |
| return wcsnlen(L"abc", (int)f); |
| } |
| |
| void wcsnlen_is_not_wcslen(wchar_t *x) { |
| clang_analyzer_eval(wcsnlen(x, 10) == wcslen(x)); // expected-warning{{UNKNOWN}} |
| } |
| |
| void wcsnlen_at_limit(wchar_t *x) { |
| size_t len = wcsnlen(x, 10); |
| clang_analyzer_eval(len <= 10); // expected-warning{{TRUE}} |
| clang_analyzer_eval(len == 10); // expected-warning{{UNKNOWN}} |
| clang_analyzer_eval(len < 10); // expected-warning{{UNKNOWN}} |
| } |
| |
| void wcsnlen_at_actual(size_t limit) { |
| size_t len = wcsnlen(L"abc", limit); |
| clang_analyzer_eval(len <= 3); // expected-warning{{TRUE}} |
| // This is due to eager assertion in wcsnlen. |
| if (limit == 0) { |
| clang_analyzer_eval(len == 0); // expected-warning{{TRUE}} |
| } else { |
| clang_analyzer_eval(len == 3); // expected-warning{{UNKNOWN}} |
| clang_analyzer_eval(len < 3); // expected-warning{{UNKNOWN}} |
| } |
| } |
| |
| //===----------------------------------------------------------------------=== |
| // other tests |
| //===----------------------------------------------------------------------=== |
| |
| static const wchar_t w_str[] = L"Hello world"; |
| |
| void wmemcpy_sizeof(void) { |
| wchar_t a[32]; |
| wmemcpy(a, w_str, sizeof(w_str) / sizeof(w_str[0])); |
| wmemcpy(a, w_str, (sizeof(w_str) / sizeof(w_str[0])) + 1); // expected-warning {{Memory copy function accesses out-of-bound array element}} |
| } |
| |
| void wmemcpy_wcslen(void) { |
| wchar_t a[32]; |
| // FIXME: This should work with 'w_str' instead of 'w_str1' |
| const wchar_t w_str1[] = L"Hello world"; |
| wmemcpy(a, w_str1, wcslen(w_str1) + 1); |
| wmemcpy(a, w_str1, wcslen(w_str1) + 2); // expected-warning {{Memory copy function accesses out-of-bound array element}} |
| } |