Submitted By: Robert Connolly <robert at linuxfromscratch dot org> (ashes)
Date: 2007-05-31
Initial Package Version: 4.1.2
Upstream Status: From Upstream
Origin:	http://gcc.gnu.org/ml/gcc-patches/2006-09/msg00722.html
	http://gcc.gnu.org/ml/gcc-cvs/2006-10/msg00659.html
	http://gcc.gnu.org/viewcvs?view=rev&revision=117980
Description: Glibc-2.4+ does 'run time' checking on strncat(3) for buffer
overflows, with -D_FORTIFY_SOURCE. This patch adds 'compile time' checking
for strncat(3).

2006-09-18  Jakub Jelinek  <jakub@redhat.com>

	* builtins.c (expand_builtin, maybe_emit_chk_warning): Handle
	BUILT_IN_STRNCAT_CHK.

	* gcc.dg/builtin-strncat-chk-1.c: New test.

diff -Naur gcc-4.1.2.orig/gcc/builtins.c gcc-4.1.2/gcc/builtins.c
--- gcc-4.1.2.orig/gcc/builtins.c	2006-10-06 17:06:52.000000000 +0000
+++ gcc-4.1.2/gcc/builtins.c	2007-05-31 15:55:33.000000000 +0000
@@ -6519,6 +6519,7 @@
     case BUILT_IN_STPCPY_CHK:
     case BUILT_IN_STRNCPY_CHK:
     case BUILT_IN_STRCAT_CHK:
+    case BUILT_IN_STRNCAT_CHK:
     case BUILT_IN_SNPRINTF_CHK:
     case BUILT_IN_VSNPRINTF_CHK:
       maybe_emit_chk_warning (exp, fcode);
@@ -10181,6 +10182,11 @@
       arg_mask = 6;
       is_strlen = 1;
       break;
+    case BUILT_IN_STRNCAT_CHK:
+    /* For __strncat_chk the warning will be emitted only if overflowing
+       by at least strlen (dest) + 1 bytes.  */
+      arg_mask = 12;
+      break;
     case BUILT_IN_STRNCPY_CHK:
       arg_mask = 12;
       break;
@@ -10218,6 +10224,22 @@
       if (! len || ! host_integerp (len, 1) || tree_int_cst_lt (len, size))
 	return;
     }
+  else if (fcode == BUILT_IN_STRNCAT_CHK)
+    {
+      tree src = TREE_VALUE (TREE_CHAIN (arglist));
+      if (! src || ! host_integerp (len, 1) || tree_int_cst_lt (len, size))
+	return;
+      src = c_strlen (src, 1);
+      if (! src || ! host_integerp (src, 1))
+	{
+	  locus = EXPR_LOCATION (exp);
+	  warning (0, "%Hcall to %D might overflow destination buffer",
+		   &locus, get_callee_fndecl (exp));
+	  return;
+	}
+      else if (tree_int_cst_lt (src, size))
+	return;
+    }
   else if (! host_integerp (len, 1) || ! tree_int_cst_lt (size, len))
     return;
 
diff -Naur gcc-4.1.2.orig/gcc/testsuite/gcc.dg/builtin-strncat-chk-1.c gcc-4.1.2/gcc/testsuite/gcc.dg/builtin-strncat-chk-1.c
--- gcc-4.1.2.orig/gcc/testsuite/gcc.dg/builtin-strncat-chk-1.c	1970-01-01 00:00:00.000000000 +0000
+++ gcc-4.1.2/gcc/testsuite/gcc.dg/builtin-strncat-chk-1.c	2007-05-31 15:55:33.000000000 +0000
@@ -0,0 +1,38 @@
+/* Test whether buffer overflow warnings for __strncat_chk builtin
+   are emitted properly.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -std=gnu99" } */
+
+extern void abort (void);
+
+#include "../gcc.c-torture/execute/builtins/chk.h"
+
+char buf1[20];
+char *q;
+
+void
+test (int arg, ...)
+{
+  char *p = &buf1[10];
+
+  *p = 0;
+  strncat (p, "abcdefg", 9);
+  *p = 0;
+  strncat (p, "abcdefghi", 9);
+  *p = 0;
+  strncat (p, "abcdefghij", 9);
+  *p = 0;
+  strncat (p, "abcdefghi", 10);
+  *p = 0;
+  strncat (p, "abcdefghij", 10); /* { dg-warning "will always overflow" } */
+  *p = 0;
+  strncat (p, "abcdefgh", 11);
+  *p = 0;
+  strncat (p, "abcdefghijkl", 11); /* { dg-warning "will always overflow" } */
+  *p = 0;
+  strncat (p, q, 9);
+  *p = 0;
+  strncat (p, q, 10); /* { dg-warning "might overflow" } */
+  *p = 0;
+  strncat (p, q, 11); /* { dg-warning "might overflow" } */
+}
