From 4d31723724098575c1b98ba0201b41d2832b33cd Mon Sep 17 00:00:00 2001 From: msebor Date: Thu, 4 May 2017 20:54:43 +0000 Subject: [PATCH] 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@247618 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 13 +++ gcc/builtins.c | 105 ++++++++++++++++++++-- gcc/testsuite/ChangeLog | 12 +++ gcc/testsuite/gcc.dg/pr78138.c | 2 +- gcc/testsuite/gcc.dg/pr79214.c | 88 ++++++++++++++++++ gcc/testsuite/gcc.dg/pr79214.h | 13 +++ gcc/testsuite/gcc.dg/pr79222.c | 13 +++ gcc/testsuite/gcc.dg/pr79223.c | 37 ++++++++ gcc/testsuite/gfortran.dg/unconstrained_commons.f | 1 + 9 files changed, 276 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr79214.c create mode 100644 gcc/testsuite/gcc.dg/pr79214.h create mode 100644 gcc/testsuite/gcc.dg/pr79222.c create mode 100644 gcc/testsuite/gcc.dg/pr79223.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 536e137c76a..856c3d3c371 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2017-05-04 Martin Sebor + + 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 * tree-ssa-loop-ivopts.c (struct cost_pair): Remove field inv_expr diff --git a/gcc/builtins.c b/gcc/builtins.c index 5567fd2dcab..9f2e447a2fd 100644 --- a/gcc/builtins.c +++ b/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) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a4d3c322c0c..89ed4db4e3e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,17 @@ 2017-05-04 Martin Sebor + 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 + PR translation/80280 * g++.dg/abi/Wabi-2-3.C: Adjust. * g++.dg/abi/Wabi-3-2.C: Ditto. diff --git a/gcc/testsuite/gcc.dg/pr78138.c b/gcc/testsuite/gcc.dg/pr78138.c index 6129c91809c..5145cb437c8 100644 --- a/gcc/testsuite/gcc.dg/pr78138.c +++ b/gcc/testsuite/gcc.dg/pr78138.c @@ -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" } */ }; diff --git a/gcc/testsuite/gcc.dg/pr79214.c b/gcc/testsuite/gcc.dg/pr79214.c new file mode 100644 index 00000000000..fbdecf49612 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr79214.c @@ -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\]+" } */ +} diff --git a/gcc/testsuite/gcc.dg/pr79214.h b/gcc/testsuite/gcc.dg/pr79214.h new file mode 100644 index 00000000000..14816811787 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr79214.h @@ -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 diff --git a/gcc/testsuite/gcc.dg/pr79222.c b/gcc/testsuite/gcc.dg/pr79222.c new file mode 100644 index 00000000000..7483a5e1e55 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr79222.c @@ -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" } */ +} diff --git a/gcc/testsuite/gcc.dg/pr79223.c b/gcc/testsuite/gcc.dg/pr79223.c new file mode 100644 index 00000000000..5bfb1d9c59c --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr79223.c @@ -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" } */ +} diff --git a/gcc/testsuite/gfortran.dg/unconstrained_commons.f b/gcc/testsuite/gfortran.dg/unconstrained_commons.f index bee67ab7d5b..cb84e7fc26f 100644 --- a/gcc/testsuite/gfortran.dg/unconstrained_commons.f +++ b/gcc/testsuite/gfortran.dg/unconstrained_commons.f @@ -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" } -- 2.11.4.GIT