diff mbox

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

Message ID 164d8b08-ced6-f2b2-ae6e-ee96afebb52e@gmail.com
State New
Headers show

Commit Message

Martin Sebor Aug. 6, 2017, 8:07 p.m. UTC
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

Comments

Jeff Law Aug. 10, 2017, 5 a.m. UTC | #1
On 08/06/2017 02:07 PM, Martin Sebor wrote:
> 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
> 
> 
> gcc-81117-2.diff
> 
> 
> 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")
So all the attributes here are associated with functions I believe.
You're defining a variable attribute.  In fact, I'm not even sure that
variable attributes get a DEF_ATTR_<whatever>




> 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.
[ ... ]
I think this is in the wrong section, I believe it belongs in the
"Variable Attributes" section.


Assuming you don't actually need the ATTR_NONSTRING, this patch is fine
with that hunk removed and the documentation moved into the right section.

jeff
Martin Sebor Aug. 14, 2017, 5:12 p.m. UTC | #2
On 08/09/2017 11:00 PM, Jeff Law wrote:
> On 08/06/2017 02:07 PM, Martin Sebor wrote:
>> 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
>>
>>
>> gcc-81117-2.diff
>>
>>
>> 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")
> So all the attributes here are associated with functions I believe.
> You're defining a variable attribute.  In fact, I'm not even sure that
> variable attributes get a DEF_ATTR_<whatever>

I assumed every attribute needed to define an identifier but
nothing broke after I removed it so it looks like you're right
variable attributes don't need one.  Go figure.  It would be
nice if there was a comment above the block that mentioned that.
I'll try to remember to add one separately.

>> 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.
> [ ... ]
> I think this is in the wrong section, I believe it belongs in the
> "Variable Attributes" section.

It is in the Variable Attributes section. The "pxref{Common Type
Attributes})." reference above is just a cross-reference to the
Type Attributes section.

> Assuming you don't actually need the ATTR_NONSTRING, this patch is fine
> with that hunk removed and the documentation moved into the right section.

Okay, thanks.

Martin
Joseph Myers Aug. 14, 2017, 6:09 p.m. UTC | #3
On Mon, 14 Aug 2017, Martin Sebor wrote:

> I assumed every attribute needed to define an identifier but
> nothing broke after I removed it so it looks like you're right
> variable attributes don't need one.  Go figure.  It would be
> nice if there was a comment above the block that mentioned that.
> I'll try to remember to add one separately.

builtin-attrs.def is only for attributes used in defining built-in 
functions.  If no built-in function uses an attribute, it should not be 
defined there.
Marc Glisse Nov. 10, 2017, 10:52 p.m. UTC | #4
On Sun, 6 Aug 2017, Martin Sebor wrote:

> +@item nonstring (@var{nonstring})

Hello,

what is the "(@var{nonstring})" for? This attribute does not seem to take 
any argument...
Martin Sebor Nov. 11, 2017, 6:04 p.m. UTC | #5
On 11/10/2017 03:52 PM, Marc Glisse wrote:
> On Sun, 6 Aug 2017, Martin Sebor wrote:
>
>> +@item nonstring (@var{nonstring})
>
> Hello,
>
> what is the "(@var{nonstring})" for? This attribute does not seem to
> take any argument...

It's a copy and paste typo.  I removed it in r254659.

Thanks for pointing it out.

Martin
diff mbox

Patch

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;
+}