1 /* Test to exercise attribute "nonstring".
2    { dg-do compile }
3    { dg-options "-O2 -Wattributes -Wstringop-truncation -ftrack-macro-expansion=0" }  */
4 
5 #define ATTR(list) __attribute__ (list)
6 #define NONSTR     ATTR ((nonstring))
7 #define strncpy(d, s, n) (__builtin_strncpy ((d), (s), (n)), sink (d))
8 
9 void sink (void*);
10 
11 /* Global string with an unknown bound.  */
12 extern char gsx[];
13 
14 /* Global string with an known bound.  */
15 extern char gs3[3];
16 
17 /* Global non-strings with an unknown bound.  */
18 extern NONSTR char gax_1[];
19 extern char NONSTR gax_2[];
20 extern char gax_3[] NONSTR;
21 
22 /* Global non-strings with a known bound.  */
23 NONSTR char gns3[3];
24 char NONSTR gns4[4];
25 char gns5[5] NONSTR;
26 
27 /* Global string pointer.  */
28 extern char *ps_1;
29 
30 /* Global non-string pointers.  */
31 extern NONSTR char *pns_1;
32 extern char* NONSTR pns_2;
33 extern char *pns_3 NONSTR;
34 
35 struct MemArrays
36 {
37   NONSTR char ma3[3];
38   char NONSTR ma4[4];
39   char ma5[5] NONSTR;
40   char max[] NONSTR;
41 };
42 
43 
test_array(const char * s,unsigned n)44 void test_array (const char *s, unsigned n)
45 {
46   const char s7[] = "1234567";
47 
48   strncpy (gs3, "", 0);           /* { dg-warning "destination unchanged after copying no bytes" } */
49   strncpy (gs3, "a", 1);          /* { dg-warning "output truncated before terminating nul copying 1 byte from a string of the same length" } */
50   strncpy (gs3, "a", 2);
51   strncpy (gs3, "a", 3);
52   strncpy (gs3, "ab", 3);
53   strncpy (gs3, "abc", 3);        /* { dg-warning "output truncated before terminating nul copying 3 bytes from a string of the same length" } */
54 
55   /* It might perhaps be helpful to diagnose certain truncation even
56      for non-strings.  Then again, since the destination has been
57      explicitly annotated as non-string, it might be viewed as a false
58      positive.  A valid use case seen in Glibc goes something like this:
59 
60      #if FOO
61      # define S "1234"
62      #else
63      # define S "12345678"
64      #endif
65 
66      strncpy (d, S, 8);
67   */
68   strncpy (gax_3, s7, 3);
69 
70   strncpy (gax_1, "a", 1);
71   strncpy (gax_2, "ab", 2);
72   strncpy (gax_3, "abc", 3);
73   strncpy (gax_3, s7, 3);
74 
75   strncpy (gax_1, s, 1);
76   strncpy (gax_2, s, 1);
77   strncpy (gax_3, s, 1);
78 
79   strncpy (gax_1, s, n);
80   strncpy (gax_2, s, n);
81   strncpy (gax_3, s, n);
82 }
83 
84 
test_pointer(const char * s,unsigned n)85 void test_pointer (const char *s, unsigned n)
86 {
87   const char s7[] = "1234567";
88 
89   strncpy (pns_1, "a", 1);
90   strncpy (pns_2, "ab", 2);
91   strncpy (pns_3, "abc", 3);
92   strncpy (pns_3, s7, 3);
93 
94   strncpy (pns_1, s, 1);
95   strncpy (pns_2, s, 1);
96   strncpy (pns_3, s, 1);
97 
98   strncpy (pns_1, s, n);
99   strncpy (pns_2, s, n);
100   strncpy (pns_3, s, n);
101 }
102 
103 
test_member_array(struct MemArrays * p,const char * s,unsigned n)104 void test_member_array (struct MemArrays *p, const char *s, unsigned n)
105 {
106   const char s7[] = "1234567";
107 
108   strncpy (p->ma3, "", 0);
109   strncpy (p->ma3, "a", 1);
110   strncpy (p->ma4, "ab", 2);
111   strncpy (p->ma5, "abc", 3);
112   strncpy (p->max, "abcd", 4);
113   strncpy (p->max, s7, 5);
114 
115   strncpy (p->ma3, s, 1);
116   strncpy (p->ma4, s, 1);
117   strncpy (p->ma5, s, 1);
118   strncpy (p->max, s, 1);
119 
120   strncpy (p->ma3, s7, n);
121   strncpy (p->ma4, s7, n);
122   strncpy (p->ma5, s7, n);
123   strncpy (p->max, s7, n);
124 }
125