summaryrefslogtreecommitdiff
path: root/gcc/testsuite/c-c++-common/Wstringop-overflow.c
blob: 53f5166f30a7f6e94fa70b9d632b0d5e7539dd34 (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
148
149
150
151
152
153
154
155
156
157
158
/* PR middle-end/81117 - Improve buffer overflow checking in strncpy
   { dg-do compile }
   { dg-options "-O2 -Wstringop-overflow -Wno-stringop-truncation -ftrack-macro-expansion=0" } */

typedef __SIZE_TYPE__ size_t;

#if __cplusplus
extern "C" {
#endif

size_t strlen (const char*);
char* strncat (char*, const char*, size_t);
char* strncpy (char*, const char*, size_t);
#if __cplusplus
}
#endif

const char ar[] = "123";

void test_strncat (char **d, const char* s, int i)
{
  /* Use a fresh pointer for each test to prevent the optimizer from
     eliminating redundant writes into the same destination.  Avoid
     calling functions like sink() on the result that would have to
     be assumed to change the source string by the alias oracle.  */
#define T(d, s, len) strncat (*d++, (s), (len))

  T (d, "",    0);
  T (d, "",    1);
  T (d, "",    2);
  T (d, "",    3);
  T (d, "123", 0);
  /* The following two calls truncate the copy and are diagnosed
     by -Wstringop-truncation but there is evidence of overflow so
     they're not diagnosed by -Wstringop-overflow.  */
  T (d, "123", 1);
  T (d, "123", 2);

  T (d, "123", 3);                /* { dg-warning ".strncat\[^\n\r\]* specified bound 3 equals source length" } */
  T (d, "123", 4);
  T (d, "123", 9);

  T (d, s, strlen (s));           /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */
  T (d, s, strlen (s) + 1);       /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */
  /* The following could also be diagnosed by -Wstringop-truncation
     (with some effort to distinguish the pattern from others like
     the one above.  */
  T (d, s, strlen (s) - 1);       /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */
  T (d, s, strlen (s) - i);       /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */

  /* The following is dubious but not necessarily a smoking gun.  */
  T (d, s, strlen (s) - strlen (s));

  {
    signed char n = strlen (s);   /* { dg-message "length computed here" } */
    T (d, s, n);                  /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */
  }

  {
    short n = strlen (s);         /* { dg-message "length computed here" } */
    T (d, s, n);                  /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */
  }

  {
    int n = strlen (s);           /* { dg-message "length computed here" } */
    T (d, s, n);                  /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */
  }

  {
    unsigned n = strlen (s);      /* { dg-message "length computed here" } */
    T (d, s, n);                  /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */
  }

  {
    size_t n;
    n = strlen (s);               /* { dg-message "length computed here" } */
    T (d, s, n);                  /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */
  }

  {
    size_t n;
    n = strlen (s) - 1;           /* { dg-message "length computed here" } */
    T (d, s, n);                  /* { dg-message ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */
  }

  {
    /* This doesn't overflow so iit should not be diagnosed.  */
    size_t n = strlen (s) - strlen (s);
    T (d, s, n);
  }

  {
    size_t n = i < strlen (s) ? i : strlen (s);   /* { dg-message "length computed here" } */
    T (d, s, n);                  /* { dg-message ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */
  }
}


void test_strncpy (char **d, const char* s, int i)
{
#undef T
#define T(d, s, len) strncpy (*d++, (s), (len))

  T (d, "",    0);
  T (d, "",    1);
  T (d, "",    2);
  T (d, "",    3);
  T (d, "123", 0);
  T (d, "123", 1);
  T (d, "123", 2);
  T (d, "123", 3);
  T (d, "123", 4);
  T (d, "123", 9);

  T (d, "123", sizeof "123");
  T (d, ar, sizeof ar);

  T (d, s, strlen (s));       /* { dg-warning "\\\[-Wstringop-overflow=]" } */

  {
    int n = strlen (s);       /* { dg-message "length computed here" } */
    T (d, s, n);              /* { dg-warning "\\\[-Wstringop-overflow=]" } */
  }

  {
    unsigned n = strlen (s);   /* { dg-message "length computed here" } */
    T (d, s, n);               /* { dg-warning "\\\[-Wstringop-overflow=]" } */
  }

  {
    size_t n;
    n = strlen (s);           /* { dg-message "length computed here" } */
    T (d, s, n);              /* { dg-warning "\\\[-Wstringop-overflow=]" } */
  }

  {
    size_t n;
    n = strlen (s) - 1;       /* { dg-message "length computed here" } */
    T (d, s, n);              /* { dg-warning "\\\[-Wstringop-overflow=]" } */
  }

  {
    /* This is diagnosed by -Wstringop-truncation.  Verify that it isn't
       also diagnosed by -Wstringop-overflow.  */
    size_t n = strlen (s) - strlen (s);
    T (d, s, n);
  }

  {
    /* This use of strncpy is certainly dubious and it could well be
       diagnosed by -Wstringop-truncation but it isn't.  That it is
       diagnosed with -Wstringop-overflow is more by accident than
       by design.  -Wstringop-overflow considers any dependency of
       the bound on strlen(s) a potential bug.  */
    size_t n = i < strlen (s) ? i : strlen (s);   /* { dg-message "length computed here" } */
    T (d, s, n);                  /* { dg-message ".strncpy\[^\n\r]* specified bound depends on the length of the source argument" } */
  }
}