aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/c-c++-common/attr-nonstring-2.c
blob: 6e273e785a00fef95aaccf672d945e7c485f8fa3 (plain)
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);
}