Commit eb07c7cf by Martin Sebor

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
parent b9f4757f
...@@ -2723,6 +2723,9 @@ get_destination_size (tree dest) ...@@ -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) ...@@ -3120,6 +3123,8 @@ pass_sprintf_length::execute (function *fun)
} }
} }
fini_object_sizes ();
return 0; return 0;
} }
......
/* { 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; ...@@ -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) ...@@ -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
}
...@@ -1235,7 +1235,7 @@ init_object_sizes (void) ...@@ -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;
......
...@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment