Bug 80364 - sanitizer detects signed integer overflow in gimple-ssa-sprintf.c, points out a runtime error (integer overflow when negating LONG_MIN) triggered by the undefined saniziter for an invalid test case recently added to the test suite. The test case passes an argument of type long as the width and precision specified by the asterisk where the argument is required to be an int.
The attached fix avoids this error by using the expected type (int) rather than the type of actual argument. This is a 7.0 P1 regression so I'm looking for approval to commit the patch to the trunk. Martin
PR middle-end/80364 - sanitizer detects signed integer overflow in gimple-ssa-sprintf.c gcc/ChangeLog: PR middle-end/80364 * gimple-ssa-sprintf.c (get_int_range): Use the specified type when recursing, not that of the argument. gcc/testsuite/ChangeLog: PR middle-end/80364 * gcc.dg/tree-ssa/builtin-sprintf-warn-16.c: New test. diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c index 2474391..fbcf5c7 100644 --- a/gcc/gimple-ssa-sprintf.c +++ b/gcc/gimple-ssa-sprintf.c @@ -961,10 +961,10 @@ get_int_range (tree arg, tree type, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax, /* True if the argument's range cannot be determined. */ bool unknown = true; - type = TREE_TYPE (arg); + tree argtype = TREE_TYPE (arg); if (TREE_CODE (arg) == SSA_NAME - && TREE_CODE (type) == INTEGER_TYPE) + && TREE_CODE (argtype) == INTEGER_TYPE) { /* Try to determine the range of values of the integer argument. */ wide_int min, max; @@ -972,11 +972,11 @@ get_int_range (tree arg, tree type, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax, if (range_type == VR_RANGE) { HOST_WIDE_INT type_min - = (TYPE_UNSIGNED (type) - ? tree_to_uhwi (TYPE_MIN_VALUE (type)) - : tree_to_shwi (TYPE_MIN_VALUE (type))); + = (TYPE_UNSIGNED (argtype) + ? tree_to_uhwi (TYPE_MIN_VALUE (argtype)) + : tree_to_shwi (TYPE_MIN_VALUE (argtype))); - HOST_WIDE_INT type_max = tree_to_uhwi (TYPE_MAX_VALUE (type)); + HOST_WIDE_INT type_max = tree_to_uhwi (TYPE_MAX_VALUE (argtype)); *pmin = min.to_shwi (); *pmax = max.to_shwi (); @@ -1004,6 +1004,9 @@ get_int_range (tree arg, tree type, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax, *pmin = *pmax = -*pmin; else { + /* Make sure signed overlow is avoided. */ + gcc_assert (*pmin != HOST_WIDE_INT_MIN); + HOST_WIDE_INT tmp = -*pmin; *pmin = 0; if (*pmax < tmp) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-16.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-16.c new file mode 100644 index 0000000..92112b5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-16.c @@ -0,0 +1,166 @@ +/* PR middle-end/80364 - sanitizer detects signed integer overflow + in gimple-ssa-sprintf.c + { dg-do compile } + { dg-options "-O2 -Wall -Wformat-overflow=1 -ftrack-macro-expansion=0" } + { dg-require-effective-target int32plus } */ + +typedef __SIZE_TYPE__ size_t; +typedef __WCHAR_TYPE__ wchar_t; + +void sink (void*); +void* get_value (void); + +/* Return a random width as type T. */ +#define W(T) *(T*)get_value () + +/* Return a random precision as type T. */ +#define P(T) *(T*)get_value () + +/* Return a random value as type T. */ +#define V(T) *(T*)get_value () + +extern char buf[1]; + +/* Test convenience macro. */ +#define T(fmt, ...) \ + __builtin_sprintf (buf + 1, fmt, __VA_ARGS__); \ + sink (buf) + +typedef signed char schar_t; +typedef unsigned char uchar_t; +typedef signed short sshort_t; +typedef unsigned short ushort_t; +typedef signed int sint_t; +typedef unsigned int uint_t; +typedef signed long slong_t; +typedef unsigned long ulong_t; +typedef signed long long sllong_t; +typedef unsigned long long ullong_t; + +#if __SIZEOF_INT128__ +typedef __int128_t sint128_t; +typedef __uint128_t uint128_t; +#else +/* When __int128_t is not available, repeat the same tests with long long. + This is to avoid having to guard the tests below and to avoid making + the dg-warning directives conditional. */ +typedef signed long long sint128_t; +typedef unsigned long long uint128_t; +#endif + +void test_width_cst (void) +{ + T ("%*i", W (schar_t), 1); /* { dg-warning "between 1 and 128 " } */ + T ("%*i", W (uchar_t), 12); /* { dg-warning "between 2 and 255 " } */ + + T ("%*i", W (sshort_t), 123); /* { dg-warning "between 3 and 32768 " } */ + T ("%*i", W (ushort_t), 1234); /* { dg-warning "between 4 and 65535 " } */ + + T ("%*i", W (sint_t), 12345); /* { dg-warning "between 5 and 2147483648" } */ + T ("%*i", W (uint_t), 123456); /* { dg-warning "between 6 and 2147483648" } */ + + /* Exercise calls with invalid arguments (to verify there is no ICE). */ + T ("%*li", W (slong_t), 1234567L); /* { dg-warning "between 7 and 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + T ("%*li", W (ulong_t), 12345678L); /* { dg-warning "between 8 and 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + + T ("%*lli", W (sllong_t), 123456789LL); /* { dg-warning "between 9 and 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + T ("%*lli", W (ullong_t), 1234567890LL); /* { dg-warning "between 10 and 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + + T ("%*i", W (sint128_t), 0); /* { dg-warning "between 1 and 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + T ("%*i", W (uint128_t), 1); /* { dg-warning "between 1 and 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + + T ("%*i", W (float), 2); /* { dg-warning "between 1 and 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + T ("%*i", W (double), 3); /* { dg-warning "between 1 and 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ +} + +void test_width_var (void) +{ + T ("%*i", W (schar_t), V (schar_t)); /* { dg-warning "between 1 and 128 " } */ + T ("%*i", W (uchar_t), V (uchar_t)); /* { dg-warning "between 1 and 255 " } */ + + T ("%*i", W (sshort_t), V (sshort_t)); /* { dg-warning "between 1 and 32768 " } */ + T ("%*i", W (ushort_t), V (ushort_t)); /* { dg-warning "between 1 and 65535 " } */ + + T ("%*i", W (sint_t), V (sint_t)); /* { dg-warning "between 1 and 2147483648" } */ + T ("%*i", W (uint_t), V (uint_t)); /* { dg-warning "between 1 and 2147483648" } */ + + /* Exercise calls with invalid arguments (to verify there is no ICE). */ + T ("%*li", W (slong_t), V (slong_t)); /* { dg-warning "between 1 and 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + T ("%*li", W (ulong_t), V (ulong_t)); /* { dg-warning "between 1 and 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + + T ("%*lli", W (sllong_t), V (sllong_t)); /* { dg-warning "between 1 and 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + T ("%*lli", W (ullong_t), V (ullong_t)); /* { dg-warning "between 1 and 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + + T ("%*i", W (float), V (int)); /* { dg-warning "between 1 and 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + T ("%*i", W (double), V (int)); /* { dg-warning "between 1 and 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ +} + +void test_precision_cst (void) +{ + T ("%.*i", P (schar_t), 1); /* { dg-warning "between 1 and 127 " } */ + T ("%.*i", P (uchar_t), 12); /* { dg-warning "between 2 and 255 " } */ + + T ("%.*i", P (sshort_t), 123); /* { dg-warning "between 3 and 32767 " } */ + T ("%.*i", P (ushort_t), 1234); /* { dg-warning "between 4 and 65535 " } */ + + T ("%.*i", P (sint_t), 12345); /* { dg-warning "between 5 and 2147483647" } */ + T ("%.*i", P (uint_t), 123456); /* { dg-warning "between 6 and 2147483647" } */ + + /* Exercise calls with invalid arguments (to verify there is no ICE). */ + T ("%.*li", P (slong_t), 1234567L); /* { dg-warning "between 7 and 2147483647" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + T ("%.*li", P (ulong_t), 12345678L); /* { dg-warning "between 8 and 2147483647" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + + T ("%.*lli", P (sllong_t), 123456789LL); /* { dg-warning "between 9 and 2147483647" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + T ("%.*lli", P (ullong_t), 1234567890LL); /* { dg-warning "between 10 and 2147483647" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + + T ("%.*i", W (float), 0); /* { dg-warning "up to 2147483647" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + T ("%.*i", W (double), 1); /* { dg-warning "between 1 and 2147483647" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ +} + +void test_precision_var (void) +{ + T ("%.*i", P (schar_t), V (schar_t)); /* { dg-warning "up to 128 " } */ + T ("%.*i", P (uchar_t), V (uchar_t)); /* { dg-warning "up to 255 " } */ + + T ("%.*i", P (sshort_t), V (sshort_t)); /* { dg-warning "up to 32768 " } */ + T ("%.*i", P (ushort_t), V (ushort_t)); /* { dg-warning "up to 65535 " } */ + + T ("%.*i", P (sint_t), V (sint_t)); /* { dg-warning "up to 2147483648 " } */ + T ("%.*i", P (uint_t), V (uint_t)); /* { dg-warning "up to 2147483648 " } */ + + /* Exercise calls with invalid arguments (to verify there is no ICE). */ + T ("%.*li", P (slong_t), V (slong_t)); /* { dg-warning "up to 2147483648 " } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + T ("%.*li", P (ulong_t), V (ulong_t)); /* { dg-warning "up to 2147483648 " } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + + T ("%.*lli", P (sllong_t), V (sllong_t)); /* { dg-warning "up to 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + T ("%.*lli", P (ullong_t), V (ullong_t)); /* { dg-warning "up to 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + + T ("%.*i", P (float), V (int)); /* { dg-warning "up to 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ + T ("%.*i", P (double), V (int)); /* { dg-warning "up to 2147483648" } */ + /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */ +}