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