public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] avoid calling memset et al. with excessively large sizes (PR 79095)
@ 2017-01-17  0:06 Martin Sebor
  2017-01-17  7:38 ` Jakub Jelinek
  2017-01-17 15:26 ` Jeff Law
  0 siblings, 2 replies; 26+ messages in thread
From: Martin Sebor @ 2017-01-17  0:06 UTC (permalink / raw)
  To: Gcc Patch List

[-- 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,

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2017-01-25 17:32 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-17  0:06 [PATCH] avoid calling memset et al. with excessively large sizes (PR 79095) Martin Sebor
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

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).