1 /* PR middle-end/85602 - -Wsizeof-pointer-memaccess for strncat with size
2    of source
3    { dg-do compile }
4    { dg-options "-O2 -Wno-array-bounds -Wsizeof-pointer-memaccess -Wstringop-truncation -ftrack-macro-expansion=0" } */
5 
6 #include "../gcc.dg/range.h"
7 
8 typedef __SIZE_TYPE__ size_t;
9 
10 #if __cplusplus
11 extern "C" {
12 #endif
13 
14 char* strcpy (char*, const char*);
15 size_t strlen (const char*);
16 char* strncat (char*, const char*, __SIZE_TYPE__);
17 char* strncpy (char*, const char*, __SIZE_TYPE__);
18 
19 #if __cplusplus
20 }
21 #endif
22 
23 #define NONSTR __attribute__ ((nonstring))
24 
25 NONSTR char nd3[3];
26 NONSTR char nd4[4];
27 NONSTR char nd5[5];
28 
29 NONSTR char ns3[3];
30 NONSTR char ns4[4];
31 NONSTR char ns5[5];
32 
33 NONSTR char* pns;
34 
35 void sink (void*, ...);
36 
37 #define T(call) sink (call)
38 
39 /* Verify that for a nonstring source array of an unknown length
40    a warning is issued only when the bound exceeds the array size.  */
41 
test_strncat_nonstring_cst(char * d)42 void test_strncat_nonstring_cst (char *d)
43 {
44   T (strncat (d, ns3, 1));
45   T (strncat (d, ns3, 2));
46   T (strncat (d, ns3, 3));
47   T (strncat (d, ns3, sizeof ns3));
48   T (strncat (d, ns3, 4));     /* { dg-warning "argument 2 declared attribute .nonstring. is smaller than the specified bound 4" } */
49 
50   T (strncat (d, ns4, 1));
51   T (strncat (d, ns4, 2));
52   T (strncat (d, ns4, 3));
53   T (strncat (d, ns4, 4));
54   T (strncat (d, ns4, sizeof ns4));
55   T (strncat (d, ns4, 5));     /* { dg-warning "argument 2 declared attribute .nonstring. is smaller than the specified bound 5" } */
56 
57   T (strncat (nd3, ns3, 1));
58   T (strncat (nd3, ns3, 2));
59   T (strncat (nd3, ns3, 3));     /* { dg-warning "specified bound 3 equals destination size" } */
60   /* Either of the two warnings below is fine.  */
61   T (strncat (nd3, ns3, 4));     /* { dg-warning "argument 2 declared attribute .nonstring. is smaller than the specified bound 4|specified bound 4 exceeds destination size 3" } */
62 
63   T (strncat (d, pns, sizeof pns));   /* { dg-warning "argument to .sizeof. in .\[^\n\r\]*strncat\[^\n\r\]*. call is the same expression as the source" } */
64 }
65 
66 
test_strncat_nonstring_var(char * d,size_t n)67 void test_strncat_nonstring_var (char *d, size_t n)
68 {
69   /* In the following the bound coulld apply to either the destination
70      or the source.  The expected use of strncat() is to pass it as
71      the bound DSIZE - strlen(D) - 1 so the call below is diagnosed.  */
72   T (strncat (d, ns3, n));            /* { dg-warning "argument 2 declared attribute .nonstring." } */
73 
74   T (strncat (d, ns3, UR (0, 1)));
75   T (strncat (d, ns3, UR (1, 2)));
76   T (strncat (d, ns3, UR (2, 3)));
77   T (strncat (d, ns3, UR (3, 4)));    /* { dg-warning "argument 2 declared attribute 'nonstring' may be smaller than the specified bound \\\[3, 4]" } */
78   T (strncat (d, ns3, UR (4, 5)));    /* { dg-warning "argument 2 declared attribute 'nonstring' is smaller than the specified bound \\\[4, 5]" } */
79 
80   /* Verify that the call below (the intended use of strncat()) is
81      also diagnosed.  */
82   T (strncat (d, ns3, 256 - strlen (d) - 1));   /* { dg-warning "argument 2 declared attribute .nonstring." } */
83 
84   T (strncat (nd3, ns5, UR (0, 1)));
85   T (strncat (nd3, ns5, UR (1, 2)));
86   T (strncat (nd3, ns5, UR (2, 3)));
87   T (strncat (nd3, ns5, UR (3, 4)));
88   T (strncat (nd3, ns5, UR (4, 5)));  /* { dg-warning "specified bound between 4 and 5 exceeds destination size 3" } */
89 
90   T (strncat (nd5, ns3, UR (0, 1)));
91   T (strncat (nd5, ns3, UR (1, 2)));
92   T (strncat (nd5, ns3, UR (2, 3)));
93   T (strncat (nd5, ns3, UR (3, 4)));  /* { dg-warning "argument 2 declared attribute 'nonstring' may be smaller than the specified bound \\\[3, 4]" } */
94 }
95 
96 /* Verify that for a nonstring source array of a known length (i.e.,
97    a nonstring array containing a nul-terminated string) a warning
98    is issued only for certain truncation.
99 
100    The test cases are split up to work around bug 81343 (or one like
101    it).  */
102 
test_strncat_string_1_1(char * d)103 void test_strncat_string_1_1 (char *d)
104 {
105   strcpy (ns3, "1");
106   T (strncat (d, ns3, 1));    /* { dg-warning "output truncated before terminating nul copying 1 byte from a string of the same length" } */
107 }
108 
test_strncat_string_1_2(char * d)109 void test_strncat_string_1_2 (char *d)
110 {
111   strcpy (ns3, "1");
112   T (strncat (d, ns3, 2));
113 }
114 
test_strncat_string_1_3(char * d)115 void test_strncat_string_1_3 (char *d)
116 {
117   strcpy (ns3, "1");
118   T (strncat (d, ns3, 3));
119 }
120 
test_strncat_string_2_1(char * d)121 void test_strncat_string_2_1 (char *d)
122 {
123   strcpy (ns3, "12");
124   T (strncat (d, ns3, 1));    /* { dg-warning "output truncated copying 1 byte from a string of length 2" } */
125 }
126 
test_strncat_string_2_2(char * d)127 void test_strncat_string_2_2 (char *d)
128 {
129   strcpy (ns3, "12");
130   T (strncat (d, ns3, 2));    /* { dg-warning "output truncated before terminating nul copying 2 bytes from a string of the same length" } */
131 }
132 
test_strncat_string_2_3(char * d)133 void test_strncat_string_2_3 (char *d)
134 {
135   strcpy (ns3, "12");
136   T (strncat (d, ns3, 3));
137 }
138 
139 
test_strcncpy_nonstring_cst(char * d)140 void test_strcncpy_nonstring_cst (char *d)
141 {
142   T (strncpy (d, ns3, 1));
143   T (strncpy (d, ns3, 2));
144   T (strncpy (d, ns3, 3));
145   T (strncpy (d, ns3, sizeof ns3));
146   T (strncpy (d, ns3, 4));      /* { dg-warning "argument 2 declared attribute .nonstring. is smaller than the specified bound 4" } */
147 }
148