On 5/21/20 4:53 PM, Martin Sebor wrote:
On 5/21/20 5:28 AM, Martin Liška wrote:
On 5/18/20 10:37 PM, Martin Sebor wrote:
I know there are some somewhat complex cases the attribute exclusion
mechanism isn't general enough to handle but this seems simple enough
that it should work.  Unless I'm missing something that makes it not
feasible I would suggest to use it.

Hi Martin.

Do we have a better place where we check for attribute collision?

If by collision you mean the same thing as the mutual exclusion I was
talking about then that's done by creating an attribute_spec::exclusions
array like for instance attr_cold_hot_exclusions in c-attribs.c and
pointing to it from the attribute_spec entries for each of
the mutually exclusive attributes in the attribute table.  Everything
else is handled automatically by decl_attributes.

Martin

Thanks, I'm sending updated version of the patch that utilizes the conflict
detection.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin
>From b026a8684a0a82394ce2faf010257fa3f0978ca0 Mon Sep 17 00:00:00 2001
From: Martin Liska <mli...@suse.cz>
Date: Fri, 15 May 2020 14:42:12 +0200
Subject: [PATCH] Implement no_stack_protect attribute.

gcc/ChangeLog:

2020-05-18  Martin Liska  <mli...@suse.cz>

	PR c/94722
	* cfgexpand.c (stack_protect_decl_phase):
	Guard with lookup_attribute("no_stack_protect") at
	various places.
	(expand_used_vars): Likewise here.
	* doc/extend.texi: Document no_stack_protect attribute.

gcc/ada/ChangeLog:

2020-05-18  Martin Liska  <mli...@suse.cz>

	PR c/94722
	* gcc-interface/utils.c (handle_no_stack_protect_attribute):
	New.
	(handle_stack_protect_attribute): Add error message for a
	no_stack_protect function.

gcc/c-family/ChangeLog:

2020-05-18  Martin Liska  <mli...@suse.cz>

	PR c/94722
	* c-attribs.c (handle_no_stack_protect_function_attribute): New.
	(handle_stack_protect_attribute): Add error message for a
	no_stack_protect function.

gcc/testsuite/ChangeLog:

2020-05-18  Martin Liska  <mli...@suse.cz>

	PR c/94722
	* g++.dg/no-stack-protect-attr-2.C: New test.
	* g++.dg/no-stack-protect-attr-3.C: New test.
	* g++.dg/no-stack-protect-attr.C: New test.
---
 gcc/ada/gcc-interface/utils.c                 | 31 ++++++-
 gcc/c-family/c-attribs.c                      | 32 +++++++-
 gcc/cfgexpand.c                               | 82 ++++++++++---------
 gcc/doc/extend.texi                           |  4 +
 .../g++.dg/no-stack-protect-attr-2.C          |  7 ++
 .../g++.dg/no-stack-protect-attr-3.C          | 23 ++++++
 gcc/testsuite/g++.dg/no-stack-protect-attr.C  | 16 ++++
 7 files changed, 154 insertions(+), 41 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/no-stack-protect-attr-2.C
 create mode 100644 gcc/testsuite/g++.dg/no-stack-protect-attr-3.C
 create mode 100644 gcc/testsuite/g++.dg/no-stack-protect-attr.C

diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index fb08b6c90ed..b6a60eb1b11 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -91,6 +91,7 @@ static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
 static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
 static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *);
+static tree handle_no_stack_protect_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noicf_attribute (tree *, tree, tree, int, bool *);
@@ -115,6 +116,13 @@ static const struct attribute_spec::exclusions attr_cold_hot_exclusions[] =
   { NULL  , false, false, false }
 };
 
+static const struct attribute_spec::exclusions attr_stack_protect_exclusions[] =
+{
+  { "stack_protect", true, false, false },
+  { "no_stack_protect", true, false, false },
+  { NULL, false, false, false },
+};
+
 /* Fake handler for attributes we don't properly support, typically because
    they'd require dragging a lot of the common-c front-end circuitry.  */
 static tree fake_attribute_handler (tree *, tree, tree, int, bool *);
@@ -140,7 +148,11 @@ const struct attribute_spec gnat_internal_attribute_table[] =
   { "noreturn",     0, 0,  true,  false, false, false,
     handle_noreturn_attribute, NULL },
   { "stack_protect",0, 0, true,  false, false, false,
-    handle_stack_protect_attribute, NULL },
+    handle_stack_protect_attribute,
+    attr_stack_protect_exclusions },
+  { "no_stack_protect",0, 0, true,  false, false, false,
+    handle_no_stack_protect_attribute,
+    attr_stack_protect_exclusions },
   { "noinline",     0, 0,  true,  false, false, false,
     handle_noinline_attribute, NULL },
   { "noclone",      0, 0,  true,  false, false, false,
@@ -6524,6 +6536,23 @@ handle_stack_protect_attribute (tree *node, tree name, tree, int,
   return NULL_TREE;
 }
 
+/* Handle a "no_stack_protect" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_no_stack_protect_attribute (tree *node, tree name, tree, int,
+				   bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+
 /* Handle a "noinline" attribute; arguments as in
    struct attribute_spec.handler.  */
 
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 7a6fb9af6da..84bdb4fca04 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -63,6 +63,8 @@ static tree handle_no_sanitize_undefined_attribute (tree *, tree, tree, int,
 static tree handle_asan_odr_indicator_attribute (tree *, tree, tree, int,
 						 bool *);
 static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *);
+static tree handle_no_stack_protect_function_attribute (tree *, tree,
+							tree, int, bool *);
 static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
 static tree handle_nocf_check_attribute (tree *, tree, tree, int, bool *);
@@ -245,6 +247,14 @@ static const struct attribute_spec::exclusions attr_noinit_exclusions[] =
   ATTR_EXCL (NULL, false, false, false),
 };
 
+static const struct attribute_spec::exclusions attr_stack_protect_exclusions[] =
+{
+  ATTR_EXCL ("stack_protect", true, false, false),
+  ATTR_EXCL ("no_stack_protect", true, false, false),
+  ATTR_EXCL (NULL, false, false, false),
+};
+
+
 /* Table of machine-independent attributes common to all C-like languages.
 
    Current list of processed common attributes: nonnull.  */
@@ -272,7 +282,11 @@ const struct attribute_spec c_common_attribute_table[] =
   { "volatile",               0, 0, true,  false, false, false,
 			      handle_noreturn_attribute, NULL },
   { "stack_protect",          0, 0, true,  false, false, false,
-			      handle_stack_protect_attribute, NULL },
+			      handle_stack_protect_attribute,
+			      attr_stack_protect_exclusions },
+  { "no_stack_protect",	      0, 0, true, false, false, false,
+			      handle_no_stack_protect_function_attribute,
+			      attr_stack_protect_exclusions },
   { "noinline",               0, 0, true,  false, false, false,
 			      handle_noinline_attribute,
 	                      attr_noinline_exclusions },
@@ -1021,6 +1035,22 @@ handle_stack_protect_attribute (tree *node, tree name, tree, int,
   return NULL_TREE;
 }
 
+/* Handle a "no_stack_protect" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_no_stack_protect_function_attribute (tree *node, tree name, tree,
+					    int, bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "noipa" attribute; arguments as in
    struct attribute_spec.handler.  */
 
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index b66c3e5f7af..6e8687c392c 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -1831,11 +1831,12 @@ stack_protect_decl_phase (tree decl)
   if (bits & SPCT_HAS_SMALL_CHAR_ARRAY)
     has_short_buffer = true;
 
-  if (flag_stack_protect == SPCT_FLAG_ALL
-      || flag_stack_protect == SPCT_FLAG_STRONG
-      || (flag_stack_protect == SPCT_FLAG_EXPLICIT
-	  && lookup_attribute ("stack_protect",
-			       DECL_ATTRIBUTES (current_function_decl))))
+  tree attribs = DECL_ATTRIBUTES (current_function_decl);
+  if (!lookup_attribute ("no_stack_protect", attribs)
+      && (flag_stack_protect == SPCT_FLAG_ALL
+	  || flag_stack_protect == SPCT_FLAG_STRONG
+	  || (flag_stack_protect == SPCT_FLAG_EXPLICIT
+	      && lookup_attribute ("stack_protect", attribs))))
     {
       if ((bits & (SPCT_HAS_SMALL_CHAR_ARRAY | SPCT_HAS_LARGE_CHAR_ARRAY))
 	  && !(bits & SPCT_HAS_AGGREGATE))
@@ -2136,6 +2137,7 @@ expand_used_vars (void)
      set are actually used by the optimized function.  Lay them out.  */
   expand_used_vars_for_block (outer_block, true);
 
+  tree attribs = DECL_ATTRIBUTES (current_function_decl);
   if (stack_vars_num > 0)
     {
       bool has_addressable_vars = false;
@@ -2145,10 +2147,10 @@ expand_used_vars (void)
       /* If stack protection is enabled, we don't share space between
 	 vulnerable data and non-vulnerable data.  */
       if (flag_stack_protect != 0
+	  && !lookup_attribute ("no_stack_protect", attribs)
 	  && (flag_stack_protect != SPCT_FLAG_EXPLICIT
 	      || (flag_stack_protect == SPCT_FLAG_EXPLICIT
-		  && lookup_attribute ("stack_protect",
-				       DECL_ATTRIBUTES (current_function_decl)))))
+		  && lookup_attribute ("stack_protect", attribs))))
 	has_addressable_vars = add_stack_protection_conflicts ();
 
       if (flag_stack_protect == SPCT_FLAG_STRONG && has_addressable_vars)
@@ -2161,38 +2163,40 @@ expand_used_vars (void)
 	dump_stack_var_partition ();
     }
 
-  switch (flag_stack_protect)
-    {
-    case SPCT_FLAG_ALL:
-      create_stack_guard ();
-      break;
 
-    case SPCT_FLAG_STRONG:
-      if (gen_stack_protect_signal
-	  || cfun->calls_alloca
-	  || has_protected_decls
-	  || lookup_attribute ("stack_protect",
-			       DECL_ATTRIBUTES (current_function_decl)))
+  if (!lookup_attribute ("no_stack_protect", attribs))
+    switch (flag_stack_protect)
+      {
+      case SPCT_FLAG_ALL:
 	create_stack_guard ();
-      break;
+	break;
 
-    case SPCT_FLAG_DEFAULT:
-      if (cfun->calls_alloca
-	  || has_protected_decls
-	  || lookup_attribute ("stack_protect",
-			       DECL_ATTRIBUTES (current_function_decl)))
-	create_stack_guard ();
-      break;
+      case SPCT_FLAG_STRONG:
+	if (gen_stack_protect_signal
+	    || cfun->calls_alloca
+	    || has_protected_decls
+	    || lookup_attribute ("stack_protect",
+				 DECL_ATTRIBUTES (current_function_decl)))
+	  create_stack_guard ();
+	break;
 
-    case SPCT_FLAG_EXPLICIT:
-      if (lookup_attribute ("stack_protect",
-			    DECL_ATTRIBUTES (current_function_decl)))
-	create_stack_guard ();
-      break;
+      case SPCT_FLAG_DEFAULT:
+	if (cfun->calls_alloca
+	    || has_protected_decls
+	    || lookup_attribute ("stack_protect",
+				 DECL_ATTRIBUTES (current_function_decl)))
+	  create_stack_guard ();
+	break;
 
-    default:
-      break;
-    }
+      case SPCT_FLAG_EXPLICIT:
+	if (lookup_attribute ("stack_protect",
+			      DECL_ATTRIBUTES (current_function_decl)))
+	  create_stack_guard ();
+	break;
+
+      default:
+	break;
+      }
 
   /* Assign rtl to each variable based on these partitions.  */
   if (stack_vars_num > 0)
@@ -2213,11 +2217,11 @@ expand_used_vars (void)
 	  expand_stack_vars (stack_protect_decl_phase_1, &data);
 
 	  /* Phase 2 contains other kinds of arrays.  */
-	  if (flag_stack_protect == SPCT_FLAG_ALL
-	      || flag_stack_protect == SPCT_FLAG_STRONG
-	      || (flag_stack_protect == SPCT_FLAG_EXPLICIT
-		  && lookup_attribute ("stack_protect",
-				       DECL_ATTRIBUTES (current_function_decl))))
+	  if (!lookup_attribute ("no_stack_protect", attribs)
+	      && (flag_stack_protect == SPCT_FLAG_ALL
+		  || flag_stack_protect == SPCT_FLAG_STRONG
+		  || (flag_stack_protect == SPCT_FLAG_EXPLICIT
+		      && lookup_attribute ("stack_protect", attribs))))
 	    expand_stack_vars (stack_protect_decl_phase_2, &data);
 	}
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index a2ebef8cf8c..446f6e7faf4 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -3671,6 +3671,10 @@ This attribute adds stack protection code to the function if
 flags @option{-fstack-protector}, @option{-fstack-protector-strong}
 or @option{-fstack-protector-explicit} are set.
 
+@item no_stack_protect
+@cindex @code{no_stack_protect} function attribute
+This attribute prevents stack protection code for the function.
+
 @item target (@var{string}, @dots{})
 @cindex @code{target} function attribute
 Multiple target back ends implement the @code{target} attribute
diff --git a/gcc/testsuite/g++.dg/no-stack-protect-attr-2.C b/gcc/testsuite/g++.dg/no-stack-protect-attr-2.C
new file mode 100644
index 00000000000..b9a0439c23c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/no-stack-protect-attr-2.C
@@ -0,0 +1,7 @@
+/* PR c/94722 */
+/* { dg-do compile } */
+
+int __attribute__((no_stack_protect, stack_protect)) c() /* { dg-warning "ignoring attribute 'stack_protect' because it conflicts with attribute 'no_stack_protect'" } */
+{
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/no-stack-protect-attr-3.C b/gcc/testsuite/g++.dg/no-stack-protect-attr-3.C
new file mode 100644
index 00000000000..a6b702ba5ea
--- /dev/null
+++ b/gcc/testsuite/g++.dg/no-stack-protect-attr-3.C
@@ -0,0 +1,23 @@
+/* PR c/94722 */
+/* Test that stack protection is disabled via no_stack_protect attribute. */
+
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-O2 -fstack-protector-explicit" } */
+
+/* { dg-do compile } */
+
+int __attribute__((no_stack_protect)) foo()
+{
+  int a;
+  char b[34];
+  return 0;
+}
+
+int __attribute__((stack_protect)) bar()
+{
+  int a;
+  char b[34];
+  return 0;
+}
+
+/* { dg-final { scan-assembler-times "stack_chk_fail" 1 } } */
diff --git a/gcc/testsuite/g++.dg/no-stack-protect-attr.C b/gcc/testsuite/g++.dg/no-stack-protect-attr.C
new file mode 100644
index 00000000000..8332e5b276d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/no-stack-protect-attr.C
@@ -0,0 +1,16 @@
+/* PR c/94722 */
+/* Test that stack protection is disabled via no_stack_protect attribute. */
+
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-O2 -fstack-protector-all" } */
+
+/* { dg-do compile } */
+
+int __attribute__((no_stack_protect)) c()
+{
+  int a;
+  char b[34];
+  return 0;
+}
+
+/* { dg-final { scan-assembler-not "stack_chk_fail" } } */
-- 
2.26.2

Reply via email to