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

View File

@ -1,5 +1,10 @@
/* { dg-do compile } */ /* Verify that all sprintf built-ins detect overflow involving directives
/* { dg-options "-O2 -Wformat -Wformat-length=1 -ftrack-macro-expansion=0" } */ 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; typedef __SIZE_TYPE__ size_t;
@ -9,18 +14,26 @@ typedef __SIZE_TYPE__ size_t;
#define bos(x) __builtin_object_size (x, 0) #define bos(x) __builtin_object_size (x, 0)
#define T(bufsize, fmt, ...) \ /* Defined (and redefined) to the allocation function to use, either
do { \ malloc, or alloca, or a VLA. */
if (!LINE || __LINE__ == LINE) \ #define ALLOC(p, n) (p) = __builtin_malloc (n)
{ \
char *d = (char *)__builtin_malloc (bufsize); \
__builtin___sprintf_chk (d, 0, bos (d), fmt, __VA_ARGS__); \
sink (d); \
} \
} while (0)
void /* Defined (and redefined) to the sprintf function to exercise. */
sink (void*); #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 /* 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 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_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 } } */ __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. */ /* Destroy data structures after the object size computation. */
static void void
fini_object_sizes (void) fini_object_sizes (void)
{ {
int object_size_type; 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 #define GCC_TREE_OBJECT_SIZE_H
extern void init_object_sizes (void); extern void init_object_sizes (void);
extern void fini_object_sizes (void);
extern bool compute_builtin_object_size (tree, int, unsigned HOST_WIDE_INT *); extern bool compute_builtin_object_size (tree, int, unsigned HOST_WIDE_INT *);
#endif // GCC_TREE_OBJECT_SIZE_H #endif // GCC_TREE_OBJECT_SIZE_H