From: Martin Sebor <msebor@gmail.com>
To: Gcc Patch List <gcc-patches@gcc.gnu.org>
Subject: [PATCH] avoid calling memset et al. with excessively large sizes (PR 79095)
Date: Tue, 17 Jan 2017 00:06:00 -0000 [thread overview]
Message-ID: <497e7848-5690-2c4e-7277-cab674a60a35@gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 424 bytes --]
The test case submitted in bug 79095 - [7 regression] spurious
stringop-overflow warning shows that GCC optimizes some loops
into calls to memset with size arguments in excess of the object
size limit. Since such calls will unavoidably lead to a buffer
overflow and memory corruption the attached patch detects them
and replaces them with a trap. That both prevents the buffer
overflow and eliminates the warning.
Martin
[-- Attachment #2: gcc-79095.diff --]
[-- Type: text/x-patch, Size: 4135 bytes --]
PR c++/79095 - [7 regression] spurious stringop-overflow warning
gcc/ChangeLog:
PR c++/79095
* tree-loop-distribution.c (maybe_emit_trap): New function.
(generate_memset_builtin): Call it.
(generate_memcpy_builtin): Same.
gcc/testsuite/ChangeLog:
PR c++/79095
* g++.dg/pr79095.C: New test.
Index: gcc/testsuite/g++.dg/pr79095.C
===================================================================
--- gcc/testsuite/g++.dg/pr79095.C (revision 0)
+++ gcc/testsuite/g++.dg/pr79095.C (working copy)
@@ -0,0 +1,41 @@
+/* PR c++/79095 - spurious stringop-overflow warning
+ { dg-do compile }
+ { dg-options "-O3 -Wall -fdump-tree-optimized" } */
+
+typedef long unsigned int size_t;
+
+inline void
+fill (int *p, size_t n, int)
+{
+ while (n--)
+ *p++ = 0;
+}
+
+struct B
+{
+ int* p0, *p1, *p2;
+
+ size_t size () const {
+ return size_t (p1 - p0);
+ }
+
+ void resize (size_t n) {
+ if (n > size())
+ append (n - size());
+ }
+
+ void append (size_t n)
+ {
+ if (size_t (p2 - p1) >= n) {
+ fill (p1, n, 0);
+ }
+ }
+};
+
+void foo (B &b)
+{
+ b.resize (b.size () - 1);
+}
+
+
+/* { dg-final { scan-tree-dump-not "memset" "optimized" } } */
Index: gcc/tree-loop-distribution.c
===================================================================
--- gcc/tree-loop-distribution.c (revision 244508)
+++ gcc/tree-loop-distribution.c (working copy)
@@ -796,6 +796,49 @@ const_with_all_bytes_same (tree val)
return buf[0];
}
+/* If NBYTES is greater than SSIZE_MAX emit a trap and return true.
+ Otherwise return false. FNCODE identifies the built-in function
+ being generated. */
+
+static bool
+maybe_emit_trap (gimple_stmt_iterator gsi, tree nbytes,
+ built_in_function fncode)
+{
+ if (TREE_CODE (nbytes) != INTEGER_CST
+ || tree_int_cst_le (nbytes, TYPE_MAX_VALUE (ssizetype)))
+ return false;
+
+ tree fn = builtin_decl_implicit (BUILT_IN_TRAP);
+ gimple *fn_call = gimple_build_call (fn, 0);
+ gsi_insert_after (&gsi, fn_call, GSI_CONTINUE_LINKING);
+ split_block (gimple_bb (fn_call), fn_call);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ const char *fname = 0;
+
+ switch (fncode)
+ {
+ case BUILT_IN_MEMCPY:
+ fname = "memcpy";
+ break;
+ case BUILT_IN_MEMMOVE:
+ fname = "memove";
+ break;
+ case BUILT_IN_MEMSET:
+ fname = "memset";
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ fprintf (dump_file, "generated trap for an out-of-bounds %s "
+ "with %wu size", fname, tree_to_uhwi (nbytes));
+ }
+
+ return true;
+}
+
/* Generate a call to memset for PARTITION in LOOP. */
static void
@@ -817,6 +860,13 @@ generate_memset_builtin (struct loop *loop, partit
partition->plus_one);
nb_bytes = force_gimple_operand_gsi (&gsi, nb_bytes, true, NULL_TREE,
false, GSI_CONTINUE_LINKING);
+
+ /* If the number of bytes is in excess of SSIZE_MAX avoid generating
+ the memset call that would certainly overflow and emit a trap
+ instead. */
+ if (maybe_emit_trap (gsi, nb_bytes, BUILT_IN_MEMSET))
+ return;
+
mem = build_addr_arg_loc (loc, partition->main_dr, nb_bytes);
mem = force_gimple_operand_gsi (&gsi, mem, true, NULL_TREE,
false, GSI_CONTINUE_LINKING);
@@ -873,6 +923,7 @@ generate_memcpy_builtin (struct loop *loop, partit
partition->plus_one);
nb_bytes = force_gimple_operand_gsi (&gsi, nb_bytes, true, NULL_TREE,
false, GSI_CONTINUE_LINKING);
+
dest = build_addr_arg_loc (loc, partition->main_dr, nb_bytes);
src = build_addr_arg_loc (loc, partition->secondary_dr, nb_bytes);
if (partition->kind == PKIND_MEMCPY
@@ -881,6 +932,12 @@ generate_memcpy_builtin (struct loop *loop, partit
else
kind = BUILT_IN_MEMMOVE;
+ /* If the number of bytes is in excess of SSIZE_MAX avoid generating
+ the mem(cpy|move) call that would certainly overflow and instead
+ emit a trap. */
+ if (maybe_emit_trap (gsi, nb_bytes, kind))
+ return;
+
dest = force_gimple_operand_gsi (&gsi, dest, true, NULL_TREE,
false, GSI_CONTINUE_LINKING);
src = force_gimple_operand_gsi (&gsi, src, true, NULL_TREE,
next reply other threads:[~2017-01-17 0:06 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-01-17 0:06 Martin Sebor [this message]
2017-01-17 7:38 ` Jakub Jelinek
2017-01-18 3:38 ` Martin Sebor
2017-01-18 7:54 ` Jeff Law
2017-01-18 8:55 ` Jakub Jelinek
2017-01-18 18:08 ` Martin Sebor
2017-01-20 23:32 ` Jeff Law
2017-01-21 6:42 ` A + B CMP A -> A CMP' CST' match.pd patterns [was [PATCH] avoid calling memset et al. with excessively large sizes (PR 79095)] Jeff Law
2017-01-21 8:18 ` Marc Glisse
2017-01-24 0:21 ` Jeff Law
2017-01-24 10:49 ` Richard Biener
2017-01-24 14:46 ` Marc Glisse
2017-01-24 15:21 ` Jeff Law
2017-01-24 16:02 ` Marc Glisse
2017-01-24 16:28 ` Richard Biener
2017-01-25 10:36 ` Richard Biener
2017-01-25 17:45 ` Jeff Law
2017-01-23 9:14 ` Richard Biener
2017-01-23 21:13 ` Jeff Law
2017-01-20 23:32 ` [PATCH] avoid calling memset et al. with excessively large sizes (PR 79095) Jeff Law
2017-01-20 23:39 ` Jakub Jelinek
2017-01-21 0:19 ` Jeff Law
2017-01-17 15:26 ` Jeff Law
2017-01-17 16:14 ` Martin Sebor
2017-01-17 18:00 ` Jeff Law
2017-01-18 3:19 ` Martin Sebor
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=497e7848-5690-2c4e-7277-cab674a60a35@gmail.com \
--to=msebor@gmail.com \
--cc=gcc-patches@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).