PR middle-end/78245 - missing -Wformat-length on an overflow of a dynamically allocated buffer

gcc/testsuite/ChangeLog:

	PR middle-end/78245
	* gcc.dg/tree-ssa/builtin-sprintf-warn-3.c: Add tests.

gcc/ChangeLog:

	PR middle-end/78245
	* gimple-ssa-sprintf.c (get_destination_size): Call
	{init,fini}object_sizes.
	* tree-object-size.c (addr_object_size): Adjust.
	(pass_through_call): Adjust.
	(pass_object_sizes::execute): Adjust.
	* tree-object-size.h (fini_object_sizes): Declare.

From-SVN: r244293
This commit is contained in:
Martin Sebor 2017-01-10 14:54:15 -07:00
parent b9f4757f8e
commit eb07c7cffb
4 changed files with 118 additions and 14 deletions

View File

@ -2723,6 +2723,9 @@ get_destination_size (tree dest)
a member array as opposed to the whole enclosing object), otherwise
use type-zero object size to determine the size of the enclosing
object (the function fails without optimization in this type). */
init_object_sizes ();
int ost = optimize > 0;
unsigned HOST_WIDE_INT size;
if (compute_builtin_object_size (dest, ost, &size))
@ -3120,6 +3123,8 @@ pass_sprintf_length::execute (function *fun)
}
}
fini_object_sizes ();
return 0;
}

View File

@ -1,5 +1,10 @@
/* { dg-do compile } */
/* { dg-options "-O2 -Wformat -Wformat-length=1 -ftrack-macro-expansion=0" } */
/* Verify that all sprintf built-ins detect overflow involving directives
with non-constant arguments known to be constrained by some range of
values, and even when writing into dynamically allocated buffers.
-O2 (-ftree-vrp) is necessary for the tests involving ranges to pass,
otherwise -O1 is sufficient.
{ dg-do compile }
{ dg-options "-O2 -Wformat -Wformat-length=1 -ftrack-macro-expansion=0" } */
typedef __SIZE_TYPE__ size_t;
@ -9,18 +14,26 @@ typedef __SIZE_TYPE__ size_t;
#define bos(x) __builtin_object_size (x, 0)
#define T(bufsize, fmt, ...) \
do { \
if (!LINE || __LINE__ == LINE) \
{ \
char *d = (char *)__builtin_malloc (bufsize); \
__builtin___sprintf_chk (d, 0, bos (d), fmt, __VA_ARGS__); \
sink (d); \
} \
} while (0)
/* Defined (and redefined) to the allocation function to use, either
malloc, or alloca, or a VLA. */
#define ALLOC(p, n) (p) = __builtin_malloc (n)
void
sink (void*);
/* Defined (and redefined) to the sprintf function to exercise. */
#define TEST_SPRINTF(d, maxsize, objsize, fmt, ...) \
__builtin___sprintf_chk (d, 0, objsize, fmt, __VA_ARGS__)
#define T(bufsize, fmt, ...) \
do { \
if (!LINE || __LINE__ == LINE) \
{ \
char *d; \
ALLOC (d, bufsize); \
TEST_SPRINTF (d, 0, bos (d), fmt, __VA_ARGS__); \
sink (d); \
} \
} while (0)
void sink (void*);
/* Identity function to verify that the checker figures out the value
of the operand even when it's not constant (i.e., makes use of
@ -362,3 +375,88 @@ void test_too_large (char *d, int x, __builtin_va_list va)
__builtin___vsnprintf_chk (d, ptrmax_m1, 0, ptrmax_m1, "%c", va); /* { dg-warning "specified bound \[0-9\]+ exceeds .INT_MAX." "PTRDIFF_MAX - 1" { target lp64 } } */
__builtin___vsnprintf_chk (d, ptrmax, 0, ptrmax, "%c", va); /* { dg-warning "specified bound \[0-9\]+ exceeds .INT_MAX." "PTRDIFF_MAX" { target lp64 } } */
}
/* Exercise ordinary sprintf with malloc. */
#undef TEST_SPRINTF
#define TEST_SPRINTF(d, maxsize, objsize, fmt, ...) \
__builtin_sprintf (d, fmt, __VA_ARGS__)
void test_sprintf_malloc (const char *s, const char *t)
{
#define x x ()
T (1, "%-s", x ? "" : "1"); /* { dg-warning "nul past the end" } */
T (1, "%-s", x ? "1" : ""); /* { dg-warning "nul past the end" } */
T (1, "%-s", x ? s : "1"); /* { dg-warning "nul past the end" } */
T (1, "%-s", x ? "1" : s); /* { dg-warning "nul past the end" } */
T (1, "%-s", x ? s : t);
T (2, "%-s", x ? "" : "1");
T (2, "%-s", x ? "" : s);
T (2, "%-s", x ? "1" : "");
T (2, "%-s", x ? s : "");
T (2, "%-s", x ? "1" : "2");
T (2, "%-s", x ? "" : "12"); /* { dg-warning "nul past the end" } */
T (2, "%-s", x ? "12" : ""); /* { dg-warning "nul past the end" } */
T (2, "%-s", x ? "" : "123"); /* { dg-warning "into a region" } */
T (2, "%-s", x ? "123" : ""); /* { dg-warning "into a region" } */
#undef x
}
/* Exercise ordinary sprintf with alloca. */
#undef ALLOC
#define ALLOC(p, n) (p) = __builtin_alloca (n)
void test_sprintf_alloca (const char *s, const char *t)
{
#define x x ()
T (1, "%-s", x ? "" : "1"); /* { dg-warning "nul past the end" } */
T (1, "%-s", x ? "1" : ""); /* { dg-warning "nul past the end" } */
T (1, "%-s", x ? s : "1"); /* { dg-warning "nul past the end" } */
T (1, "%-s", x ? "1" : s); /* { dg-warning "nul past the end" } */
T (1, "%-s", x ? s : t);
T (2, "%-s", x ? "" : "1");
T (2, "%-s", x ? "" : s);
T (2, "%-s", x ? "1" : "");
T (2, "%-s", x ? s : "");
T (2, "%-s", x ? "1" : "2");
T (2, "%-s", x ? "" : "12"); /* { dg-warning "nul past the end" } */
T (2, "%-s", x ? "12" : ""); /* { dg-warning "nul past the end" } */
T (2, "%-s", x ? "" : "123"); /* { dg-warning "into a region" } */
T (2, "%-s", x ? "123" : ""); /* { dg-warning "into a region" } */
#undef x
}
/* Exercise ordinary sprintf with a VLA. */
#undef ALLOC
#define ALLOC(p, n) char vla [i (n)]; (p) = vla
void test_sprintf_vla (const char *s, const char *t)
{
#define x x ()
T (1, "%-s", x ? "" : "1"); /* { dg-warning "nul past the end" } */
T (1, "%-s", x ? "1" : ""); /* { dg-warning "nul past the end" } */
T (1, "%-s", x ? s : "1"); /* { dg-warning "nul past the end" } */
T (1, "%-s", x ? "1" : s); /* { dg-warning "nul past the end" } */
T (1, "%-s", x ? s : t);
T (2, "%-s", x ? "" : "1");
T (2, "%-s", x ? "" : s);
T (2, "%-s", x ? "1" : "");
T (2, "%-s", x ? s : "");
T (2, "%-s", x ? "1" : "2");
T (2, "%-s", x ? "" : "12"); /* { dg-warning "nul past the end" } */
T (2, "%-s", x ? "12" : ""); /* { dg-warning "nul past the end" } */
T (2, "%-s", x ? "" : "123"); /* { dg-warning "into a region" } */
T (2, "%-s", x ? "123" : ""); /* { dg-warning "into a region" } */
#undef x
}

View File

@ -1235,7 +1235,7 @@ init_object_sizes (void)
/* Destroy data structures after the object size computation. */
static void
void
fini_object_sizes (void)
{
int object_size_type;

View File

@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
#define GCC_TREE_OBJECT_SIZE_H
extern void init_object_sizes (void);
extern void fini_object_sizes (void);
extern bool compute_builtin_object_size (tree, int, unsigned HOST_WIDE_INT *);
#endif // GCC_TREE_OBJECT_SIZE_H