aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/c-c++-common/attr-nonstring-8.c
blob: 9ad33425b27a22e09fb74220731cad150fbc18eb (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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/* PR middle-end/85602 - -Wsizeof-pointer-memaccess for strncat with size
   of source
   { dg-do compile }
   { dg-options "-O2 -Wno-array-bounds -Wsizeof-pointer-memaccess -Wstringop-truncation -ftrack-macro-expansion=0" } */

#include "../gcc.dg/range.h"

typedef __SIZE_TYPE__ size_t;

#if __cplusplus
extern "C" {
#endif

char* strcpy (char*, const char*);
size_t strlen (const char*);
char* strncat (char*, const char*, __SIZE_TYPE__);
char* strncpy (char*, const char*, __SIZE_TYPE__);

#if __cplusplus
}
#endif

#define NONSTR __attribute__ ((nonstring))

NONSTR char nd3[3];
NONSTR char nd4[4];
NONSTR char nd5[5];

NONSTR char ns3[3];
NONSTR char ns4[4];
NONSTR char ns5[5];

NONSTR char* pns;

void sink (void*, ...);

#define T(call) sink (call)

/* Verify that for a nonstring source array of an unknown length
   a warning is issued only when the bound exceeds the array size.  */

void test_strncat_nonstring_cst (char *d)
{
  T (strncat (d, ns3, 1));
  T (strncat (d, ns3, 2));
  T (strncat (d, ns3, 3));
  T (strncat (d, ns3, sizeof ns3));
  T (strncat (d, ns3, 4));     /* { dg-warning "argument 2 declared attribute .nonstring. is smaller than the specified bound 4" } */

  T (strncat (d, ns4, 1));
  T (strncat (d, ns4, 2));
  T (strncat (d, ns4, 3));
  T (strncat (d, ns4, 4));
  T (strncat (d, ns4, sizeof ns4));
  T (strncat (d, ns4, 5));     /* { dg-warning "argument 2 declared attribute .nonstring. is smaller than the specified bound 5" } */

  T (strncat (nd3, ns3, 1));
  T (strncat (nd3, ns3, 2));
  T (strncat (nd3, ns3, 3));     /* { dg-warning "specified bound 3 equals destination size" } */
  /* Either of the two warnings below is fine.  */
  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" } */

  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" } */
}


void test_strncat_nonstring_var (char *d, size_t n)
{
  /* In the following the bound coulld apply to either the destination
     or the source.  The expected use of strncat() is to pass it as
     the bound DSIZE - strlen(D) - 1 so the call below is diagnosed.  */
  T (strncat (d, ns3, n));            /* { dg-warning "argument 2 declared attribute .nonstring." } */

  T (strncat (d, ns3, UR (0, 1)));
  T (strncat (d, ns3, UR (1, 2)));
  T (strncat (d, ns3, UR (2, 3)));
  T (strncat (d, ns3, UR (3, 4)));    /* { dg-warning "argument 2 declared attribute 'nonstring' may be smaller than the specified bound \\\[3, 4]" } */
  T (strncat (d, ns3, UR (4, 5)));    /* { dg-warning "argument 2 declared attribute 'nonstring' is smaller than the specified bound \\\[4, 5]" } */

  /* Verify that the call below (the intended use of strncat()) is
     also diagnosed.  */
  T (strncat (d, ns3, 256 - strlen (d) - 1));   /* { dg-warning "argument 2 declared attribute .nonstring." } */

  T (strncat (nd3, ns5, UR (0, 1)));
  T (strncat (nd3, ns5, UR (1, 2)));
  T (strncat (nd3, ns5, UR (2, 3)));
  T (strncat (nd3, ns5, UR (3, 4)));
  T (strncat (nd3, ns5, UR (4, 5)));  /* { dg-warning "specified bound \\\[4, 5] exceeds destination size 3" } */

  T (strncat (nd5, ns3, UR (0, 1)));
  T (strncat (nd5, ns3, UR (1, 2)));
  T (strncat (nd5, ns3, UR (2, 3)));
  T (strncat (nd5, ns3, UR (3, 4)));  /* { dg-warning "argument 2 declared attribute 'nonstring' may be smaller than the specified bound \\\[3, 4]" } */
}

/* Verify that for a nonstring source array of a known length (i.e.,
   a nonstring array containing a nul-terminated string) a warning
   is issued only for certain truncation.

   The test cases are split up to work around bug 81343 (or one like
   it).  */

void test_strncat_string_1_1 (char *d)
{
  strcpy (ns3, "1");
  T (strncat (d, ns3, 1));    /* { dg-warning "output truncated before terminating nul copying 1 byte from a string of the same length" } */
}

void test_strncat_string_1_2 (char *d)
{
  strcpy (ns3, "1");
  T (strncat (d, ns3, 2));
}

void test_strncat_string_1_3 (char *d)
{
  strcpy (ns3, "1");
  T (strncat (d, ns3, 3));
}

void test_strncat_string_2_1 (char *d)
{
  strcpy (ns3, "12");
  T (strncat (d, ns3, 1));    /* { dg-warning "output truncated copying 1 byte from a string of length 2" } */
}

void test_strncat_string_2_2 (char *d)
{
  strcpy (ns3, "12");
  T (strncat (d, ns3, 2));    /* { dg-warning "output truncated before terminating nul copying 2 bytes from a string of the same length" } */
}

void test_strncat_string_2_3 (char *d)
{
  strcpy (ns3, "12");
  T (strncat (d, ns3, 3));
}


void test_strcncpy_nonstring_cst (char *d)
{
  T (strncpy (d, ns3, 1));
  T (strncpy (d, ns3, 2));
  T (strncpy (d, ns3, 3));
  T (strncpy (d, ns3, sizeof ns3));
  T (strncpy (d, ns3, 4));      /* { dg-warning "argument 2 declared attribute .nonstring. is smaller than the specified bound 4" } */
}