PR tree-optimization/ 79376 - wrong lower bound with %s and non-constant
strings in -Wformat-overflow gcc/ChangeLog: * gimple-fold.c (get_range_strlen): Set the minimum length to zero. From-SVN: r245221
This commit is contained in:
parent
98e0924501
commit
e495e31a20
5 changed files with 333 additions and 2 deletions
|
@ -1,3 +1,8 @@
|
|||
2017-02-06 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR tree-optimization/79376
|
||||
* gimple-fold.c (get_range_strlen): Set the minimum length to zero.
|
||||
|
||||
2017-02-06 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
* config/i386/sse.md (vector modes -> vec_extract* splitter): Use
|
||||
|
|
|
@ -1244,8 +1244,9 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
|
|||
return false;
|
||||
val = fold_build2 (MINUS_EXPR, TREE_TYPE (val), val,
|
||||
integer_one_node);
|
||||
/* Avoid using the array size as the minimum. */
|
||||
minlen = NULL;
|
||||
/* Set the minimum size to zero since the string in
|
||||
the array could have zero length. */
|
||||
*minlen = ssize_int (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2017-02-06 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR tree-optimization/79376
|
||||
* gcc.dg/tree-ssa/builtin-sprintf-warn-14.c: New test.
|
||||
* gcc.dg/tree-ssa/pr79376.c: Ditto.
|
||||
|
||||
2017-02-06 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c++/79379
|
||||
|
|
210
gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-14.c
Normal file
210
gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-14.c
Normal file
|
@ -0,0 +1,210 @@
|
|||
/* PR middle-end/79376 - wrong lower bound with %s and non-constant
|
||||
strings in -Wformat-overflow
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall -Wformat-overflow=1 -ftrack-macro-expansion=0" } */
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
#define INT_MAX __INT_MAX__
|
||||
#define INT_MIN (-INT_MAX - 1)
|
||||
|
||||
/* When debugging, define LINE to the line number of the test case to exercise
|
||||
and avoid exercising any of the others. The buffer and objsize macros
|
||||
below make use of LINE to avoid warnings for other lines. */
|
||||
#ifndef LINE
|
||||
# define LINE 0
|
||||
#endif
|
||||
|
||||
extern int int_value (void);
|
||||
|
||||
int int_range (int min, int max)
|
||||
{
|
||||
int n = int_value ();
|
||||
return n < min || max < n ? min : n;
|
||||
}
|
||||
|
||||
const char*
|
||||
choose_string (const char *s1, const char *s2, const char *s3)
|
||||
{
|
||||
int i = int_value ();
|
||||
return i < 0 ? s1 : 0 < i ? s3 : s2;
|
||||
}
|
||||
|
||||
void sink (char*, char*);
|
||||
|
||||
int dummy_sprintf (char*, const char*, ...);
|
||||
|
||||
char buffer [256];
|
||||
extern char *ptr;
|
||||
|
||||
const char s0[] = "";
|
||||
const char s1[] = "1";
|
||||
const char s2[] = "12";
|
||||
const char s3[] = "123";
|
||||
const char s4[] = "1234";
|
||||
const char s5[] = "12345";
|
||||
const char s6[] = "123456";
|
||||
const char s7[] = "1234567";
|
||||
const char s8[] = "12345678";
|
||||
const char s9[] = "123456789";
|
||||
extern const char sx[];
|
||||
extern const char sy[];
|
||||
|
||||
/* Evaluate to an array of SIZE characters when non-negative, or to
|
||||
a pointer to an unknown object otherwise. */
|
||||
#define buffer(size) \
|
||||
((0 <= size) ? buffer + sizeof buffer - (size) : ptr)
|
||||
|
||||
/* Helper to expand function to either __builtin_f or dummy_f to
|
||||
make debugging GCC easy. */
|
||||
#define FUNC(f) \
|
||||
((!LINE || LINE == __LINE__) ? __builtin_ ## f : dummy_ ## f)
|
||||
|
||||
/* Macro to verify that calls to __builtin_sprintf (i.e., with no size
|
||||
argument) issue diagnostics by correctly determining the size of
|
||||
the destination buffer. */
|
||||
#define T(size, ...) \
|
||||
(FUNC (sprintf) (buffer (size), __VA_ARGS__), \
|
||||
sink (buffer, ptr))
|
||||
|
||||
/* Return a value in the range [MIN, MAX]. */
|
||||
#define R(min, max) int_range (min, max)
|
||||
|
||||
/* Return one of the strings S1, S2, S3. */
|
||||
#define S(s1, s2, s3) choose_string (s1, s2, s3)
|
||||
|
||||
struct S {
|
||||
char a1[1];
|
||||
char a2[2];
|
||||
char a3[3];
|
||||
char a4[4];
|
||||
char a5[5];
|
||||
char ax[];
|
||||
};
|
||||
|
||||
void test_strings (struct S *s)
|
||||
{
|
||||
T (0, "%-s", S (s->a1, s->a1, s1)); /* { dg-warning "writing up to 1 byte" } */
|
||||
T (0, "%-s", S (s->a1, s->a2, s1)); /* { dg-warning "writing up to 1 byte" } */
|
||||
T (0, "%-s", S (s->a2, s->a1, s1)); /* { dg-warning "writing up to 1 byte" } */
|
||||
|
||||
T (0, "%-s", S (s->a1, s1, s->a1)); /* { dg-warning "writing up to 1 byte" } */
|
||||
T (0, "%-s", S (s->a1, s1, s->a2)); /* { dg-warning "writing up to 1 byte" } */
|
||||
T (0, "%-s", S (s->a2, s1, s->a1)); /* { dg-warning "writing up to 1 byte" } */
|
||||
|
||||
T (0, "%-s", S (s1, s->a1, s1)); /* { dg-warning "writing up to 1 byte" } */
|
||||
T (0, "%-s", S (s1, s->a1, s1)); /* { dg-warning "writing up to 1 byte" } */
|
||||
T (0, "%-s", S (s1, s->a2, s1)); /* { dg-warning "writing up to 1 byte" } */
|
||||
|
||||
T (0, "%-s", S (s->a1, s->a1, s2)); /* { dg-warning "writing up to 2 bytes" } */
|
||||
T (0, "%-s", S (s->a1, s->a2, s2)); /* { dg-warning "writing up to 2 bytes" } */
|
||||
T (0, "%-s", S (s->a2, s->a1, s2)); /* { dg-warning "writing up to 2 bytes" } */
|
||||
|
||||
T (0, "%-s", S (s->a1, s2, s->a1)); /* { dg-warning "writing up to 2 bytes" } */
|
||||
T (0, "%-s", S (s->a1, s2, s->a2)); /* { dg-warning "writing up to 2 bytes" } */
|
||||
T (0, "%-s", S (s->a2, s2, s->a1)); /* { dg-warning "writing up to 2 bytes" } */
|
||||
|
||||
T (0, "%-s", S (s2, s->a1, s1)); /* { dg-warning "writing up to 2 bytes" } */
|
||||
T (0, "%-s", S (s2, s->a1, s1)); /* { dg-warning "writing up to 2 bytes" } */
|
||||
T (0, "%-s", S (s2, s->a2, s1)); /* { dg-warning "writing up to 2 bytes" } */
|
||||
|
||||
T (0, "%-s", S (s->a1, s->a1, s2)); /* { dg-warning "writing up to 2 bytes" } */
|
||||
T (0, "%-s", S (s->a1, s->a2, s2)); /* { dg-warning "writing up to 2 bytes" } */
|
||||
T (0, "%-s", S (s->a2, s->a1, s2)); /* { dg-warning "writing up to 2 bytes" } */
|
||||
|
||||
T (0, "%-s", S (s->a1, s2, s->a1)); /* { dg-warning "writing up to 2 bytes" } */
|
||||
T (0, "%-s", S (s->a1, s2, s->a2)); /* { dg-warning "writing up to 2 bytes" } */
|
||||
T (0, "%-s", S (s->a2, s2, s->a1)); /* { dg-warning "writing up to 2 bytes" } */
|
||||
|
||||
T (0, "%-s", S (s2, s->a1, s1)); /* { dg-warning "writing up to 2 bytes" } */
|
||||
T (0, "%-s", S (s3, s->a1, s2)); /* { dg-warning "writing up to 3 bytes" } */
|
||||
T (0, "%-s", S (s4, s->a2, s3)); /* { dg-warning "writing up to 4 bytes" } */
|
||||
|
||||
T (0, "%-s", S (s->a3, s->a5, s3)); /* { dg-warning "writing up to 4 bytes" } */
|
||||
T (0, "%-s", S (s->a3, s->a5, s3)); /* { dg-warning "writing up to 4 bytes" } */
|
||||
T (0, "%-s", S (s->a3, s->a5, s3)); /* { dg-warning "writing up to 4 bytes" } */
|
||||
|
||||
T (0, "%-s", S (s->a3, s3, s->a5)); /* { dg-warning "writing up to 4 bytes" } */
|
||||
T (0, "%-s", S (s->a5, s3, s->a3)); /* { dg-warning "writing up to 4 bytes" } */
|
||||
T (0, "%-s", S (s->a3, s3, s->a5)); /* { dg-warning "writing up to 4 bytes" } */
|
||||
|
||||
T (0, "%-s", S (s3, s->a1, s4)); /* { dg-warning "writing up to 4 bytes" } */
|
||||
T (0, "%-s", S (s4, s->a2, s3)); /* { dg-warning "writing up to 4 bytes" } */
|
||||
}
|
||||
|
||||
void test_strings_with_width (struct S *s)
|
||||
{
|
||||
T (0, "%*s", /* { dg-warning "writing up to 4 bytes" } */
|
||||
R (0, 1),
|
||||
S (s->a3, s->a5, s3));
|
||||
|
||||
T (0, "%*s", /* { dg-warning "writing up to 4 bytes" } */
|
||||
R (0, 4),
|
||||
S (s->a3, s->a5, s3));
|
||||
|
||||
T (0, "%*s", /* { dg-warning "writing between 1 and 4 bytes" } */
|
||||
R (1, 4),
|
||||
S (s->a3, s->a5, s3));
|
||||
|
||||
T (0, "%*s", /* { dg-warning "writing between 2 and 4 bytes" } */
|
||||
R (2, 4),
|
||||
S (s->a3, s->a5, s3));
|
||||
|
||||
T (0, "%*s", /* { dg-warning "writing between 3 and 4 bytes" } */
|
||||
R (3, 4),
|
||||
S (s->a3, s->a5, s3));
|
||||
|
||||
T (0, "%*s", /* { dg-warning "writing between 3 and 5 bytes" } */
|
||||
R (3, 5),
|
||||
S (s->a3, s->a5, s3));
|
||||
|
||||
T (0, "%*s", /* { dg-warning "writing between 3 and 9 bytes" } */
|
||||
R (3, 9),
|
||||
S (s->a3, s->a5, s3));
|
||||
|
||||
T (3, "%*s", /* { dg-warning "writing between 3 and 9 bytes" } */
|
||||
R (3, 9),
|
||||
S (s->a3, s->a5, s3));
|
||||
|
||||
/* The longest string fits but the terminating nul will overflow. Since
|
||||
the null won't overflow with the shorter strings the warning is a "may
|
||||
write." */
|
||||
T (4, "%*s", /* { dg-warning "may write a terminating nul" } */
|
||||
R (3, 9),
|
||||
S (s->a3, s->a5, s3));
|
||||
}
|
||||
|
||||
void test_strings_with_width_and_precisin (struct S *s)
|
||||
{
|
||||
T (0, "%*.*s", /* { dg-warning "writing up to 1 byte" } */
|
||||
R (0, 1),
|
||||
R (0, 1),
|
||||
S (s->a3, s->a5, s3));
|
||||
|
||||
T (0, "%*.*s", /* { dg-warning "writing up to 2 bytes" } */
|
||||
R (0, 2),
|
||||
R (0, 1),
|
||||
S (s->a3, s->a5, s3));
|
||||
|
||||
T (0, "%*.*s", /* { dg-warning "writing up to 9 bytes" } */
|
||||
R (0, 9),
|
||||
R (0, 1),
|
||||
S (s->a3, s->a5, s3));
|
||||
|
||||
/* Since the longest string/array fits there is no warning even if
|
||||
the maximum width would cause overflow. */
|
||||
T (6, "%*.*s",
|
||||
R (0, 9),
|
||||
R (0, 1),
|
||||
S (s->a3, s->a5, s3));
|
||||
|
||||
T (0, "%*.*s", /* { dg-warning "writing up to 2 bytes" } */
|
||||
R (0, 2),
|
||||
R (0, 2),
|
||||
S (s->a3, s->a5, s3));
|
||||
|
||||
T (0, "%*.*s", /* { dg-warning "writing up to 3 bytes" } */
|
||||
R (0, 3),
|
||||
R (0, 2),
|
||||
S (s->a3, s->a5, s3));
|
||||
}
|
109
gcc/testsuite/gcc.dg/tree-ssa/pr79376.c
Normal file
109
gcc/testsuite/gcc.dg/tree-ssa/pr79376.c
Normal file
|
@ -0,0 +1,109 @@
|
|||
/* PR tree-optimization/79376 - wrong lower bound with %s and non-constant
|
||||
strings in -Wformat-overflow
|
||||
{ dg-compile }
|
||||
{ dg-options "-O2 -fdump-tree-optimized" } */
|
||||
|
||||
#define CAT(s, n) s ## n
|
||||
#define FAIL(line) CAT (failure_on_line_, line)
|
||||
|
||||
/* Emit a call to a function named failure_on_line_NNN when EXPR is false. */
|
||||
#define ASSERT(expr) \
|
||||
do { \
|
||||
extern void FAIL (__LINE__)(void); \
|
||||
if (!(expr)) FAIL (__LINE__)(); \
|
||||
} while (0)
|
||||
|
||||
#define KEEP(line) CAT (keep_call_on_line_, line)
|
||||
|
||||
/* Emit a call to a function named keep_call_on_line_NNN when EXPR is true.
|
||||
Used to verify that the expression need not be the only one that holds. */
|
||||
#define ASSERT_MAYBE(expr) \
|
||||
do { \
|
||||
extern void KEEP (__LINE__)(void); \
|
||||
if (expr) KEEP (__LINE__)(); \
|
||||
} while (0)
|
||||
|
||||
struct Arrays
|
||||
{
|
||||
char a1[1];
|
||||
char a2[2];
|
||||
char a3[3];
|
||||
char a4[4];
|
||||
char a5[5];
|
||||
char ax[];
|
||||
};
|
||||
|
||||
void test_arrays (int i, struct Arrays *a)
|
||||
{
|
||||
{
|
||||
const char *s = i < 0 ? a->a3 : a->a1;
|
||||
|
||||
int n = __builtin_snprintf (0, 0, "%-s", s);
|
||||
|
||||
ASSERT (0 <= n && n < 3);
|
||||
|
||||
ASSERT_MAYBE (0 == n);
|
||||
ASSERT_MAYBE (1 == n);
|
||||
ASSERT_MAYBE (2 == n);
|
||||
}
|
||||
|
||||
{
|
||||
const char *s = i < 0 ? a->a3 : a->a5;
|
||||
|
||||
int n = __builtin_snprintf (0, 0, "%-s", s);
|
||||
|
||||
ASSERT (0 <= n && n < 5);
|
||||
|
||||
ASSERT_MAYBE (0 == n);
|
||||
ASSERT_MAYBE (1 == n);
|
||||
ASSERT_MAYBE (2 == n);
|
||||
ASSERT_MAYBE (3 == n);
|
||||
ASSERT_MAYBE (4 == n);
|
||||
}
|
||||
}
|
||||
|
||||
void test_string_and_array (int i, struct Arrays *a)
|
||||
{
|
||||
{
|
||||
const char *s = i < 0 ? a->a3 : "1";
|
||||
|
||||
int n = __builtin_snprintf (0, 0, "%-s", s);
|
||||
|
||||
ASSERT (0 <= n && n < 3);
|
||||
|
||||
ASSERT_MAYBE (0 == n);
|
||||
ASSERT_MAYBE (1 == n);
|
||||
ASSERT_MAYBE (2 == n);
|
||||
}
|
||||
|
||||
{
|
||||
const char *s = i < 0 ? "12" : a->a5;
|
||||
|
||||
int n = __builtin_snprintf (0, 0, "%-s", s);
|
||||
|
||||
ASSERT (0 <= n && n < 5);
|
||||
|
||||
ASSERT_MAYBE (0 == n);
|
||||
ASSERT_MAYBE (1 == n);
|
||||
ASSERT_MAYBE (2 == n);
|
||||
ASSERT_MAYBE (3 == n);
|
||||
ASSERT_MAYBE (4 == n);
|
||||
}
|
||||
|
||||
{
|
||||
const char *s = i < 0 ? a->a4 : 0 < i ? "12" : a->a5;
|
||||
|
||||
int n = __builtin_snprintf (0, 0, "%-s", s);
|
||||
|
||||
ASSERT (0 <= n && n < 5);
|
||||
|
||||
ASSERT_MAYBE (0 == n);
|
||||
ASSERT_MAYBE (1 == n);
|
||||
ASSERT_MAYBE (2 == n);
|
||||
ASSERT_MAYBE (3 == n);
|
||||
ASSERT_MAYBE (4 == n);
|
||||
}
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-not "failure_on_line" "optimized"} }
|
||||
{ dg-final { scan-tree-dump-times "keep_call_on_line" 21 "optimized"} } */
|
Loading…
Add table
Reference in a new issue