1*67e74705SXin Li // RUN: %clang_cc1 -Wstrncat-size -verify -fsyntax-only %s
2*67e74705SXin Li // RUN: %clang_cc1 -DUSE_BUILTINS -Wstrncat-size -verify -fsyntax-only %s
3*67e74705SXin Li // RUN: %clang_cc1 -fsyntax-only -Wstrncat-size -fixit -x c %s
4*67e74705SXin Li // RUN: %clang_cc1 -DUSE_BUILTINS -fsyntax-only -Wstrncat-size -fixit -x c %s
5*67e74705SXin Li
6*67e74705SXin Li typedef __SIZE_TYPE__ size_t;
7*67e74705SXin Li size_t strlen (const char *s);
8*67e74705SXin Li
9*67e74705SXin Li #ifdef USE_BUILTINS
10*67e74705SXin Li # define BUILTIN(f) __builtin_ ## f
11*67e74705SXin Li #else
12*67e74705SXin Li # define BUILTIN(f) f
13*67e74705SXin Li #endif
14*67e74705SXin Li
15*67e74705SXin Li #define strncat BUILTIN(strncat)
16*67e74705SXin Li char *strncat(char *restrict s1, const char *restrict s2, size_t n);
17*67e74705SXin Li
18*67e74705SXin Li struct {
19*67e74705SXin Li char f1[100];
20*67e74705SXin Li char f2[100][3];
21*67e74705SXin Li } s4, **s5;
22*67e74705SXin Li
23*67e74705SXin Li char s1[100];
24*67e74705SXin Li char s2[200];
25*67e74705SXin Li int x;
26*67e74705SXin Li
test(char * src)27*67e74705SXin Li void test(char *src) {
28*67e74705SXin Li char dest[10];
29*67e74705SXin Li
30*67e74705SXin Li strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest) - strlen(dest) - 1); // no-warning
31*67e74705SXin Li strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest) - 1); // no-warning - the code might assume that dest is empty
32*67e74705SXin Li
33*67e74705SXin Li strncat(dest, src, sizeof(src)); // expected-warning {{size argument in 'strncat' call appears to be size of the source}} expected-note {{change the argument to be the free space in the destination buffer minus the terminating null byte}}
34*67e74705SXin Li
35*67e74705SXin Li strncat(dest, src, sizeof(src) - 1); // expected-warning {{size argument in 'strncat' call appears to be size of the source}} expected-note {{change the argument to be the free space in the destination buffer minus the terminating null byte}}
36*67e74705SXin Li
37*67e74705SXin Li strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest)); // expected-warning{{the value of the size argument in 'strncat' is too large, might lead to a buffer overflow}} expected-note {{change the argument to be the free space in the destination buffer minus the terminating null byte}}
38*67e74705SXin Li
39*67e74705SXin Li strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest) - strlen(dest)); // expected-warning{{the value of the size argument in 'strncat' is too large, might lead to a buffer overflow}} expected-note {{change the argument to be the free space in the destination buffer minus the terminating null byte}}
40*67e74705SXin Li
41*67e74705SXin Li strncat((*s5)->f2[x], s2, sizeof(s2)); // expected-warning {{size argument in 'strncat' call appears to be size of the source}} expected-note {{change the argument to be the free space in the destination buffer minus the terminating null byte}}
42*67e74705SXin Li strncat(s1+3, s2, sizeof(s2)); // expected-warning {{size argument in 'strncat' call appears to be size of the source}}
43*67e74705SXin Li strncat(s4.f1, s2, sizeof(s2)); // expected-warning {{size argument in 'strncat' call appears to be size of the source}} expected-note {{change the argument to be the free space in the destination buffer minus the terminating null byte}}
44*67e74705SXin Li }
45*67e74705SXin Li
46*67e74705SXin Li // Don't issue FIXIT for flexible arrays.
47*67e74705SXin Li struct S {
48*67e74705SXin Li int y;
49*67e74705SXin Li char x[];
50*67e74705SXin Li };
51*67e74705SXin Li
flexible_arrays(struct S * s)52*67e74705SXin Li void flexible_arrays(struct S *s) {
53*67e74705SXin Li char str[] = "hi";
54*67e74705SXin Li strncat(s->x, str, sizeof(str)); // expected-warning {{size argument in 'strncat' call appears to be size of the source}}
55*67e74705SXin Li }
56*67e74705SXin Li
57*67e74705SXin Li // Don't issue FIXIT for destinations of size 1.
size_1()58*67e74705SXin Li void size_1() {
59*67e74705SXin Li char z[1];
60*67e74705SXin Li char str[] = "hi";
61*67e74705SXin Li
62*67e74705SXin Li strncat(z, str, sizeof(z)); // expected-warning{{the value of the size argument to 'strncat' is wrong}}
63*67e74705SXin Li }
64*67e74705SXin Li
65*67e74705SXin Li // Support VLAs.
vlas(int size)66*67e74705SXin Li void vlas(int size) {
67*67e74705SXin Li char z[size];
68*67e74705SXin Li char str[] = "hi";
69*67e74705SXin Li
70*67e74705SXin Li strncat(z, str, sizeof(str)); // expected-warning {{size argument in 'strncat' call appears to be size of the source}} expected-note {{change the argument to be the free space in the destination buffer minus the terminating null byte}}
71*67e74705SXin Li }
72*67e74705SXin Li
73*67e74705SXin Li // Non-array type gets a different error message.
f(char * s,char * d)74*67e74705SXin Li void f(char* s, char* d) {
75*67e74705SXin Li strncat(d, s, sizeof(d)); // expected-warning {{the value of the size argument to 'strncat' is wrong}}
76*67e74705SXin Li }
77