This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 2/4] enhance overflow and truncation detection in strncpy and strncat (PR 81117)


Part 2 of the series adds attribute nostring to annotate arrays
of and pointers to char with that are intended to store sequences
of characters that aren't necessarily valid (nul-terminated)
strings.  In the subsequent patch the attribute is relied on to
avoid diagnosing strcncpy calls that truncate strings and create
such copies.  In the future I'd like to also use the attribute
to diagnose when arrays or pointers with the attribute are passed
to functions that expect nul-terminated strings (such as strlen
or strcpy).

Martin

PR c/81117 - Improve buffer overflow checking in strncpy

gcc/ChangeLog:

	PR c/81117
	* builtin-attrs.def (attribute nonstring): New.
	* doc/extend.texi (attribute nonstring): Document new attribute.

gcc/c-family/ChangeLog:

	PR c/81117
	* c-attribs.c (c_common_attribute_table): Add nonstring entry.
	(handle_nonstring_attribute): New function.

gcc/testsuite/ChangeLog:

	PR c/81117
	* c-c++-common/attr-nonstring-1.c: New test.

--- a/gcc/builtin-attrs.def
+++ b/gcc/builtin-attrs.def
@@ -93,6 +93,7 @@ DEF_ATTR_IDENT (ATTR_FORMAT, "format")
 DEF_ATTR_IDENT (ATTR_FORMAT_ARG, "format_arg")
 DEF_ATTR_IDENT (ATTR_MALLOC, "malloc")
 DEF_ATTR_IDENT (ATTR_NONNULL, "nonnull")
+DEF_ATTR_IDENT (ATTR_NONSTRING, "nonstring")
 DEF_ATTR_IDENT (ATTR_NORETURN, "noreturn")
 DEF_ATTR_IDENT (ATTR_NOTHROW, "nothrow")
 DEF_ATTR_IDENT (ATTR_LEAF, "leaf")
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 0d9ab2d..69d020c 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -116,6 +116,7 @@ static tree handle_deprecated_attribute (tree *, tree, tree, int,
 static tree handle_vector_size_attribute (tree *, tree, tree, int,
 					  bool *);
 static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
+static tree handle_nonstring_attribute (tree *, tree, tree, int, bool *);
 static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
 static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *);
 static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
@@ -270,6 +271,8 @@ const struct attribute_spec c_common_attribute_table[] =
 			      handle_tls_model_attribute, false },
   { "nonnull",                0, -1, false, true, true,
 			      handle_nonnull_attribute, false },
+  { "nonstring",              0, 0, true, false, false,
+			      handle_nonstring_attribute, false },
   { "nothrow",                0, 0, true,  false, false,
 			      handle_nothrow_attribute, false },
   { "may_alias",	      0, 0, false, true, false, NULL, false },
@@ -2970,6 +2973,48 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
   return NULL_TREE;
 }
 
+/* Handle the "nonstring" variable attribute.  */
+
+static tree
+handle_nonstring_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+			    int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  gcc_assert (!args);
+  tree_code code = TREE_CODE (*node);
+
+  if (VAR_P (*node)
+      || code == FIELD_DECL
+      || code == PARM_DECL)
+    {
+      tree type = TREE_TYPE (*node);
+
+      if (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
+	{
+	  tree eltype = TREE_TYPE (type);
+	  if (eltype == char_type_node)
+	    return NULL_TREE;
+	}
+
+      warning (OPT_Wattributes,
+	       "%qE attribute ignored on objects of type %qT",
+	       name, type);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  if (code == FUNCTION_DECL)
+    warning (OPT_Wattributes,
+	     "%qE attribute does not apply to functions", name);
+  else if (code == TYPE_DECL)
+    warning (OPT_Wattributes,
+	     "%qE attribute does not apply to types", name);
+  else
+    warning (OPT_Wattributes, "%qE attribute ignored", name);
+
+  *no_add_attrs = true;
+  return NULL_TREE;
+}
+
 /* Handle a "nothrow" attribute; arguments as in
    struct attribute_spec.handler.  */
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index b253ccc..1954ca5 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -5835,6 +5835,30 @@ The @code{deprecated} attribute can also be used for functions and
 types (@pxref{Common Function Attributes},
 @pxref{Common Type Attributes}).
 
+@item nonstring (@var{nonstring})
+@cindex @code{nonstring} variable attribute
+The @code{nonstring} variable attribute specifies that an object or member
+declaration with type array of @code{char} or pointer to @code{char} is
+intended to store character arrays that do not necessarily contain
+a terminating @code{NUL} character.  This is useful to avoid warnings
+when such an array or pointer is used as an argument to a bounded string
+manipulation function such as @code{strncpy}.  For example, without the
+attribute, GCC will issue a warning for the call below because it may
+truncate the copy without appending the terminating NUL character.  Using
+the attribute makes it possible to suppress the warning.
+
+@smallexample
+struct Data
+@{
+  char name [32] __attribute__ ((nonstring));
+@};
+void f (struct Data *pd, const char *s)
+@{
+  strncpy (pd->name, s, sizeof pd->name);
+  @dots{}
+@}
+@end smallexample
+
 @item mode (@var{mode})
 @cindex @code{mode} variable attribute
 This attribute specifies the data type for the declaration---whichever
diff --git a/gcc/testsuite/c-c++-common/attr-nonstring-1.c b/gcc/testsuite/c-c++-common/attr-nonstring-1.c
new file mode 100644
index 0000000..10a6688
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/attr-nonstring-1.c
@@ -0,0 +1,60 @@
+/* Test to exercise attribute "nonstring" syntax.
+   { dg-do compile }
+   { dg-options "-Wattributes" }  */
+
+#define ATTR(list) __attribute__ (list)
+#define NONSTR     ATTR ((nonstring))
+
+/* Verify it's accepted on char arrays.  */
+extern NONSTR char nsx_1[];
+extern char NONSTR nsx_2[];
+extern char nsx_3[] NONSTR;
+
+extern NONSTR char ns1[1];
+extern char NONSTR ns3[3];
+extern char ns5[5] NONSTR;
+
+/* Verify it's accepted on char pointers.  */
+extern NONSTR char* pns_1;
+extern char NONSTR* pns_2;
+extern char* NONSTR pns_3;
+
+struct S
+{
+/* Verify it's accepted on char member pointers.  */
+  NONSTR char* mpns_1;
+  char NONSTR* mpns_2;
+  char* NONSTR mpns_3;
+
+/* Verify it's accepted on char member arrays.  */
+  NONSTR char mns1[1];
+  char NONSTR mns3[3];
+  char mns5[5] NONSTR;
+
+/* Verify it's accepted on char flexible array members.  */
+  char mnsx[] NONSTR;
+};
+
+/* Verify it's rejected on non-array and non-pointer objects.  */
+extern NONSTR char c1;         /* { dg-warning ".nonstring. attribute ignored on objects of type .char." } */
+
+extern NONSTR int i1;         /* { dg-warning ".nonstring. attribute ignored on objects of type .int." } */
+
+extern NONSTR int ia1[];      /* { dg-warning ".nonstring. attribute ignored on objects of type .int *\\\[\\\]." } */
+
+extern NONSTR int* pi1;       /* { dg-warning ".nonstring. attribute ignored on objects of type .int *\\*." } */
+
+extern NONSTR
+void f (void);                /* { dg-warning ".nonstring. attribute does not apply to functions" } */
+
+struct NONSTR
+NonStrType { int i; };        /* { dg-warning ".nonstring. attribute does not apply to types" } */
+
+typedef char NONSTR nschar_t; /* { dg-warning ".nonstring. attribute does not apply to types" } */
+
+void func (NONSTR char *pns1, char NONSTR *pns2, char* NONSTR pns3)
+{
+  (void)pns1;
+  (void)pns2;
+  (void)pns3;
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]