blob: 5757a23141ed96130cbd7ac825248192d8c90077 [file] [log] [blame]
/* 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);
/* There is no overflow in the following calls but they are diagnosed
by -Wstringop-truncation. Verify that they aren'y also diagnosed
by -Wstringop-overflow. */
T (d, s, strlen (s));
{
int n = strlen (s);
T (d, s, n);
}
{
unsigned n = strlen (s);
T (d, s, n);
}
{
size_t n;
n = strlen (s);
T (d, s, n);
}
{
size_t n;
n = strlen (s) - 1;
T (d, s, n);
}
{
/* 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. */
size_t n = i < strlen (s) ? i : strlen (s); /* { dg-message "length computed here" "note" { xfail *-*-* } } */
T (d, s, n); /* { dg-message ".strncpy\[^\n\r]* specified bound depends on the length of the source argument" "pr?????" { xfail *-*-* } } */
}
}