PR preprocessor/79214 - -Wno-system-header defeats strncat buffer overflow warnings
PR preprocessor/79214 - -Wno-system-header defeats strncat buffer overflow warnings PR middle-end/79222 - missing -Wstringop-overflow= on a stpcpy overflow PR middle-end/79223 - missing -Wstringop-overflow on a memmove overflow gcc/ChangeLog: PR preprocessor/79214 PR middle-end/79222 PR middle-end/79223 * builtins.c (check_sizes): Add inlinining context and issue warnings even when -Wno-system-headers is set. (check_strncat_sizes): Same. (expand_builtin_strncat): Same. (expand_builtin_memmove): New function. (expand_builtin_stpncpy): Same. (expand_builtin): Handle memmove and stpncpy. gcc/testsuite/ChangeLog: PR preprocessor/79214 PR middle-end/79222 PR middle-end/79223 * gcc.dg/pr79214.c: New test. * gcc.dg/pr79214.h: New test header. * gcc.dg/pr79222.c: New test. * gcc.dg/pr79223.c: New test. * gcc.dg/pr78138.c: Adjust. * gfortran.dg/unconstrained_commons.f: Same. From-SVN: r247618
This commit is contained in:
parent
0f05d90543
commit
e50d56a502
9 changed files with 276 additions and 8 deletions
|
@ -1,3 +1,16 @@
|
|||
2017-05-04 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR preprocessor/79214
|
||||
PR middle-end/79222
|
||||
PR middle-end/79223
|
||||
* builtins.c (check_sizes): Add inlinining context and issue
|
||||
warnings even when -Wno-system-headers is set.
|
||||
(check_strncat_sizes): Same.
|
||||
(expand_builtin_strncat): Same.
|
||||
(expand_builtin_memmove): New function.
|
||||
(expand_builtin_stpncpy): Same.
|
||||
(expand_builtin): Handle memmove and stpncpy.
|
||||
|
||||
2017-05-04 Bin Cheng <bin.cheng@arm.com>
|
||||
|
||||
* tree-ssa-loop-ivopts.c (struct cost_pair): Remove field inv_expr
|
||||
|
|
105
gcc/builtins.c
105
gcc/builtins.c
|
@ -121,6 +121,7 @@ static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, machine_mode);
|
|||
static rtx expand_builtin_memcpy (tree, rtx);
|
||||
static rtx expand_builtin_memcpy_with_bounds (tree, rtx);
|
||||
static rtx expand_builtin_memcpy_args (tree, tree, tree, rtx, tree);
|
||||
static rtx expand_builtin_memmove (tree, rtx);
|
||||
static rtx expand_builtin_mempcpy (tree, rtx, machine_mode);
|
||||
static rtx expand_builtin_mempcpy_with_bounds (tree, rtx, machine_mode);
|
||||
static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx,
|
||||
|
@ -129,6 +130,7 @@ static rtx expand_builtin_strcat (tree, rtx);
|
|||
static rtx expand_builtin_strcpy (tree, rtx);
|
||||
static rtx expand_builtin_strcpy_args (tree, tree, rtx);
|
||||
static rtx expand_builtin_stpcpy (tree, rtx, machine_mode);
|
||||
static rtx expand_builtin_stpncpy (tree, rtx);
|
||||
static rtx expand_builtin_strncat (tree, rtx);
|
||||
static rtx expand_builtin_strncpy (tree, rtx);
|
||||
static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, machine_mode);
|
||||
|
@ -3125,6 +3127,7 @@ check_sizes (int opt, tree exp, tree size, tree maxlen, tree str, tree objsize)
|
|||
if (range[0] && tree_int_cst_lt (maxobjsize, range[0]))
|
||||
{
|
||||
location_t loc = tree_nonartificial_location (exp);
|
||||
loc = expansion_point_location_if_in_system_header (loc);
|
||||
|
||||
if (range[0] == range[1])
|
||||
warning_at (loc, opt,
|
||||
|
@ -3157,17 +3160,18 @@ check_sizes (int opt, tree exp, tree size, tree maxlen, tree str, tree objsize)
|
|||
unsigned HOST_WIDE_INT uwir0 = tree_to_uhwi (range[0]);
|
||||
|
||||
location_t loc = tree_nonartificial_location (exp);
|
||||
loc = expansion_point_location_if_in_system_header (loc);
|
||||
|
||||
if (at_least_one)
|
||||
warning_at (loc, opt,
|
||||
"%K%qD: writing at least %wu byte into a region "
|
||||
"%K%qD writing at least %wu byte into a region "
|
||||
"of size %wu overflows the destination",
|
||||
exp, get_callee_fndecl (exp), uwir0,
|
||||
tree_to_uhwi (objsize));
|
||||
else if (range[0] == range[1])
|
||||
warning_at (loc, opt,
|
||||
(uwir0 == 1
|
||||
? G_("%K%qD: writing %wu byte into a region "
|
||||
? G_("%K%qD writing %wu byte into a region "
|
||||
"of size %wu overflows the destination")
|
||||
: G_("%K%qD writing %wu bytes into a region "
|
||||
"of size %wu overflows the destination")),
|
||||
|
@ -3175,7 +3179,7 @@ check_sizes (int opt, tree exp, tree size, tree maxlen, tree str, tree objsize)
|
|||
tree_to_uhwi (objsize));
|
||||
else
|
||||
warning_at (loc, opt,
|
||||
"%K%qD: writing between %wu and %wu bytes "
|
||||
"%K%qD writing between %wu and %wu bytes "
|
||||
"into a region of size %wu overflows "
|
||||
"the destination",
|
||||
exp, get_callee_fndecl (exp), uwir0,
|
||||
|
@ -3196,6 +3200,7 @@ check_sizes (int opt, tree exp, tree size, tree maxlen, tree str, tree objsize)
|
|||
if (range[0] && objsize && tree_fits_uhwi_p (objsize))
|
||||
{
|
||||
location_t loc = tree_nonartificial_location (exp);
|
||||
loc = expansion_point_location_if_in_system_header (loc);
|
||||
|
||||
if (tree_int_cst_lt (maxobjsize, range[0]))
|
||||
{
|
||||
|
@ -3304,6 +3309,24 @@ expand_builtin_memcpy (tree exp, rtx target)
|
|||
return expand_builtin_memcpy_args (dest, src, len, target, exp);
|
||||
}
|
||||
|
||||
/* Check a call EXP to the memmove built-in for validity.
|
||||
Return NULL_RTX on both success and failure. */
|
||||
|
||||
static rtx
|
||||
expand_builtin_memmove (tree exp, rtx)
|
||||
{
|
||||
if (!validate_arglist (exp,
|
||||
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
|
||||
return NULL_RTX;
|
||||
|
||||
tree dest = CALL_EXPR_ARG (exp, 0);
|
||||
tree len = CALL_EXPR_ARG (exp, 2);
|
||||
|
||||
check_memop_sizes (exp, dest, len);
|
||||
|
||||
return NULL_RTX;
|
||||
}
|
||||
|
||||
/* Expand an instrumented call EXP to the memcpy builtin.
|
||||
Return NULL_RTX if we failed, the caller should emit a normal call,
|
||||
otherwise try to get the result in TARGET, if convenient (and in
|
||||
|
@ -3614,6 +3637,13 @@ expand_builtin_stpcpy (tree exp, rtx target, machine_mode mode)
|
|||
dst = CALL_EXPR_ARG (exp, 0);
|
||||
src = CALL_EXPR_ARG (exp, 1);
|
||||
|
||||
if (warn_stringop_overflow)
|
||||
{
|
||||
tree destsize = compute_dest_size (dst, warn_stringop_overflow - 1);
|
||||
check_sizes (OPT_Wstringop_overflow_,
|
||||
exp, /*size=*/NULL_TREE, /*maxlen=*/NULL_TREE, src, destsize);
|
||||
}
|
||||
|
||||
/* If return value is ignored, transform stpcpy into strcpy. */
|
||||
if (target == const0_rtx && builtin_decl_implicit (BUILT_IN_STRCPY))
|
||||
{
|
||||
|
@ -3674,6 +3704,47 @@ expand_builtin_stpcpy (tree exp, rtx target, machine_mode mode)
|
|||
}
|
||||
}
|
||||
|
||||
/* Check a call EXP to the stpncpy built-in for validity.
|
||||
Return NULL_RTX on both success and failure. */
|
||||
|
||||
static rtx
|
||||
expand_builtin_stpncpy (tree exp, rtx)
|
||||
{
|
||||
if (!validate_arglist (exp,
|
||||
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)
|
||||
|| !warn_stringop_overflow)
|
||||
return NULL_RTX;
|
||||
|
||||
tree dest = CALL_EXPR_ARG (exp, 0);
|
||||
tree src = CALL_EXPR_ARG (exp, 1);
|
||||
|
||||
/* The number of bytes to write (not the maximum). */
|
||||
tree len = CALL_EXPR_ARG (exp, 2);
|
||||
/* The length of the source sequence. */
|
||||
tree slen = c_strlen (src, 1);
|
||||
|
||||
/* Try to determine the range of lengths that the source expression
|
||||
refers to. */
|
||||
tree lenrange[2];
|
||||
if (slen)
|
||||
lenrange[0] = lenrange[1] = slen;
|
||||
else
|
||||
{
|
||||
get_range_strlen (src, lenrange);
|
||||
slen = lenrange[0];
|
||||
}
|
||||
|
||||
tree destsize = compute_dest_size (dest,
|
||||
warn_stringop_overflow - 1);
|
||||
|
||||
/* The number of bytes to write is LEN but check_sizes will also
|
||||
check SLEN if LEN's value isn't known. */
|
||||
check_sizes (OPT_Wstringop_overflow_,
|
||||
exp, len, /*maxlen=*/NULL_TREE, slen, destsize);
|
||||
|
||||
return NULL_RTX;
|
||||
}
|
||||
|
||||
/* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE)
|
||||
bytes from constant string DATA + OFFSET and return it as target
|
||||
constant. */
|
||||
|
@ -3729,9 +3800,13 @@ check_strncat_sizes (tree exp, tree objsize)
|
|||
if (tree_fits_uhwi_p (maxlen) && tree_fits_uhwi_p (objsize)
|
||||
&& tree_int_cst_equal (objsize, maxlen))
|
||||
{
|
||||
warning_at (EXPR_LOCATION (exp), OPT_Wstringop_overflow_,
|
||||
"specified bound %wu "
|
||||
location_t loc = tree_nonartificial_location (exp);
|
||||
loc = expansion_point_location_if_in_system_header (loc);
|
||||
|
||||
warning_at (loc, OPT_Wstringop_overflow_,
|
||||
"%K%qD: specified bound %wu "
|
||||
"equals the size of the destination",
|
||||
exp, get_callee_fndecl (exp),
|
||||
tree_to_uhwi (maxlen));
|
||||
|
||||
return false;
|
||||
|
@ -3793,9 +3868,13 @@ expand_builtin_strncat (tree exp, rtx)
|
|||
if (tree_fits_uhwi_p (maxlen) && tree_fits_uhwi_p (destsize)
|
||||
&& tree_int_cst_equal (destsize, maxlen))
|
||||
{
|
||||
warning_at (EXPR_LOCATION (exp), OPT_Wstringop_overflow_,
|
||||
"specified bound %wu "
|
||||
location_t loc = tree_nonartificial_location (exp);
|
||||
loc = expansion_point_location_if_in_system_header (loc);
|
||||
|
||||
warning_at (loc, OPT_Wstringop_overflow_,
|
||||
"%K%qD: specified bound %wu "
|
||||
"equals the size of the destination",
|
||||
exp, get_callee_fndecl (exp),
|
||||
tree_to_uhwi (maxlen));
|
||||
|
||||
return NULL_RTX;
|
||||
|
@ -6712,12 +6791,24 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
|
|||
return target;
|
||||
break;
|
||||
|
||||
case BUILT_IN_STPNCPY:
|
||||
target = expand_builtin_stpncpy (exp, target);
|
||||
if (target)
|
||||
return target;
|
||||
break;
|
||||
|
||||
case BUILT_IN_MEMCPY:
|
||||
target = expand_builtin_memcpy (exp, target);
|
||||
if (target)
|
||||
return target;
|
||||
break;
|
||||
|
||||
case BUILT_IN_MEMMOVE:
|
||||
target = expand_builtin_memmove (exp, target);
|
||||
if (target)
|
||||
return target;
|
||||
break;
|
||||
|
||||
case BUILT_IN_MEMPCPY:
|
||||
target = expand_builtin_mempcpy (exp, target, mode);
|
||||
if (target)
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
2017-05-04 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR preprocessor/79214
|
||||
PR middle-end/79222
|
||||
PR middle-end/79223
|
||||
* gcc.dg/pr79214.c: New test.
|
||||
* gcc.dg/pr79214.h: New test header.
|
||||
* gcc.dg/pr79222.c: New test.
|
||||
* gcc.dg/pr79223.c: New test.
|
||||
* gcc.dg/pr78138.c: Adjust.
|
||||
* gfortran.dg/unconstrained_commons.f: Same.
|
||||
|
||||
2017-05-04 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR translation/80280
|
||||
|
|
|
@ -20,5 +20,5 @@ void g (void *p)
|
|||
extern unsigned n;
|
||||
if (n < 17 || 32 < n) n = 7;
|
||||
|
||||
memcpy (d, p, n); /* { dg-warning ".memcpy.: writing between 7 and 32 bytes into a region of size 5" } */
|
||||
memcpy (d, p, n); /* { dg-warning ".memcpy. writing between 7 and 32 bytes into a region of size 5" } */
|
||||
};
|
||||
|
|
88
gcc/testsuite/gcc.dg/pr79214.c
Normal file
88
gcc/testsuite/gcc.dg/pr79214.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
/* PR preprocessor/79214 - -Wno-system-header defeats strncat buffer overflow
|
||||
warnings
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2" } */
|
||||
|
||||
#include "pr79214.h"
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
char d[3];
|
||||
char s[4];
|
||||
|
||||
size_t range (void)
|
||||
{
|
||||
extern size_t size ();
|
||||
size_t n = size ();
|
||||
if (n <= sizeof d)
|
||||
return sizeof d + 1;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void test_bzero (void)
|
||||
{
|
||||
bzero (d, range ()); /* { dg-warning ".__builtin_bzero. writing between 4 and \[0-9\]+ bytes into a region of size 3 overflows the destination" } */
|
||||
}
|
||||
|
||||
void test_memcpy (void)
|
||||
{
|
||||
memcpy (d, s, range ()); /* { dg-warning ".__builtin_memcpy. writing between 4 and \[0-9\]+ bytes into a region of size 3 overflows the destination" } */
|
||||
}
|
||||
|
||||
void test_memmove (void)
|
||||
{
|
||||
memmove (d, d + 1, range ()); /* { dg-warning ".__builtin_memmove. writing between 4 and \[0-9\]+ bytes into a region of size 3 overflows the destination" } */
|
||||
}
|
||||
|
||||
void test_mempcpy (void)
|
||||
{
|
||||
mempcpy (d, s, range ()); /* { dg-warning ".__builtin_mempcpy. writing between 4 and \[0-9\]+ bytes into a region of size 3 overflows the destination" } */
|
||||
}
|
||||
|
||||
void test_memset (int n)
|
||||
{
|
||||
memset (d, n, range ()); /* { dg-warning ".__builtin_memset. writing between 4 and \[0-9\]+ bytes into a region of size 3 overflows the destination" } */
|
||||
}
|
||||
|
||||
void test_strcat (int i)
|
||||
{
|
||||
const char *s = i < 0 ? "123" : "4567";
|
||||
|
||||
strcat (d, s); /* { dg-warning ".__builtin_strcat. writing 4 bytes into a region of size 3 overflows the destination" } */
|
||||
}
|
||||
|
||||
char* test_stpcpy (int i)
|
||||
{
|
||||
const char *s = i < 0 ? "123" : "4567";
|
||||
|
||||
return stpcpy (d, s); /* { dg-warning ".__builtin_stpcpy. writing 4 bytes into a region of size 3 overflows the destination" } */
|
||||
}
|
||||
|
||||
char* test_stpncpy (int i)
|
||||
{
|
||||
const char *s = i < 0 ? "123" : "4567";
|
||||
|
||||
return stpncpy (d, s, range ()); /* { dg-warning ".__builtin_stpncpy. writing between 4 and \[0-9\]+ bytes into a region of size 3 overflows the destination" } */
|
||||
}
|
||||
|
||||
char* test_strcpy (int i)
|
||||
{
|
||||
const char *s = i < 0 ? "123" : "4567";
|
||||
|
||||
return strcpy (d, s); /* { dg-warning ".__builtin_strcpy. writing 4 bytes into a region of size 3 overflows the destination" } */
|
||||
}
|
||||
|
||||
char* test_strncpy (int i)
|
||||
{
|
||||
const char *s = i < 0 ? "123" : "4567";
|
||||
|
||||
return strncpy (d, s, range ()); /* { dg-warning ".__builtin_strncpy. writing between 4 and \[0-9\]+ bytes into a region of size 3 overflows the destination" } */
|
||||
}
|
||||
|
||||
char* test_strncat (int i)
|
||||
{
|
||||
const char *s = i < 0 ? "123" : "4567";
|
||||
|
||||
return strncat (d, s, range ()); /* { dg-warning ".__builtin_strncat.: specified bound between 4 and \[0-9\]+" } */
|
||||
}
|
13
gcc/testsuite/gcc.dg/pr79214.h
Normal file
13
gcc/testsuite/gcc.dg/pr79214.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#pragma GCC system_header
|
||||
|
||||
#define bzero __builtin_bzero
|
||||
#define memcpy __builtin_memcpy
|
||||
#define memmove __builtin_memmove
|
||||
#define mempcpy __builtin_mempcpy
|
||||
#define memset __builtin_memset
|
||||
#define strcat __builtin_strcat
|
||||
#define stpcpy __builtin_stpcpy
|
||||
#define stpncpy __builtin_stpncpy
|
||||
#define strcpy __builtin_strcpy
|
||||
#define strncpy __builtin_strncpy
|
||||
#define strncat __builtin_strncat
|
13
gcc/testsuite/gcc.dg/pr79222.c
Normal file
13
gcc/testsuite/gcc.dg/pr79222.c
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* PR middle-end/79222 - missing -Wstringop-overflow= on a stpcpy overflow
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2" } */
|
||||
|
||||
extern char* stpcpy (char*, const char*);
|
||||
|
||||
char d[3];
|
||||
|
||||
char* f (int i)
|
||||
{
|
||||
const char *s = i < 0 ? "01234567" : "9876543210";
|
||||
return stpcpy (d, s); /* { dg-warning ".stpcpy. writing 9 bytes into a region of size 3 overflows the destination" } */
|
||||
}
|
37
gcc/testsuite/gcc.dg/pr79223.c
Normal file
37
gcc/testsuite/gcc.dg/pr79223.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* PR middle-end/79223 - missing -Wstringop-overflow on a memmove overflow
|
||||
{ dg-do compile }
|
||||
{ dg-additional-options "-O2 -Wall -std=gnu99" } */
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
extern void* memcpy (void*, const void*, size_t);
|
||||
extern void* mempcpy (void*, const void*, size_t);
|
||||
extern void* memmove (void*, const void*, size_t);
|
||||
|
||||
char d[3];
|
||||
char s[4];
|
||||
|
||||
size_t range (void)
|
||||
{
|
||||
extern size_t size ();
|
||||
size_t n = size ();
|
||||
if (n <= sizeof d)
|
||||
return sizeof d + 1;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void test_memcpy (void)
|
||||
{
|
||||
memcpy (d, s, range ()); /* { dg-warning ".memcpy. writing between 4 and \[0-9\]+ bytes into a region of size 3 overflows the destination" } */
|
||||
}
|
||||
|
||||
void test_mempcpy (void)
|
||||
{
|
||||
mempcpy (d, s, range ()); /* { dg-warning ".mempcpy. writing between 4 and \[0-9\]+ bytes into a region of size 3 overflows the destination" } */
|
||||
}
|
||||
|
||||
void test_memmove (void)
|
||||
{
|
||||
memmove (d + 1, d, range ()); /* { dg-warning ".memmove. writing between 4 and \[0-9\]+ bytes into a region of size 2 overflows the destination" } */
|
||||
}
|
|
@ -18,3 +18,4 @@
|
|||
! We should retain both a read and write of mycommon.x.
|
||||
! { dg-final { scan-tree-dump-times " _\[0-9\]+ = mycommon\\.x\\\[_\[0-9\]+\\\];" 1 "dom2" } }
|
||||
! { dg-final { scan-tree-dump-times " mycommon\\.x\\\[j?_\[0-9\]+\\\] = _\[0-9\]+;" 1 "dom2" } }
|
||||
! { dg-prune-output "overflows the destination" }
|
||||
|
|
Loading…
Add table
Reference in a new issue