Implement no_stack_protector attribute.
authorMartin Liska <mliska@suse.cz>
Fri, 15 May 2020 12:42:12 +0000 (14:42 +0200)
committerMartin Liska <mliska@suse.cz>
Thu, 22 Oct 2020 08:10:50 +0000 (10:10 +0200)
gcc/ChangeLog:

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

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

gcc/ada/ChangeLog:

2020-05-18  Martin Liska  <mliska@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_protector function.

gcc/c-family/ChangeLog:

2020-05-18  Martin Liska  <mliska@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_protector function.

gcc/testsuite/ChangeLog:

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

PR c/94722
* g++.dg/no-stack-protector-attr-2.C: New test.
* g++.dg/no-stack-protector-attr-3.C: New test.
* g++.dg/no-stack-protector-attr.C: New test.

gcc/ada/gcc-interface/utils.c
gcc/c-family/c-attribs.c
gcc/cfgexpand.c
gcc/doc/extend.texi
gcc/testsuite/g++.dg/no-stack-protector-attr-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/no-stack-protector-attr-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/no-stack-protector-attr.C [new file with mode: 0644]

index 048a0cf..d50872f 100644 (file)
@@ -92,6 +92,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_protector_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 *);
@@ -116,6 +117,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_protector", 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 *);
@@ -141,7 +149,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_protector",0, 0, true,  false, false, false,
+    handle_no_stack_protector_attribute,
+    attr_stack_protect_exclusions },
   { "noinline",     0, 0,  true,  false, false, false,
     handle_noinline_attribute, NULL },
   { "noclone",      0, 0,  true,  false, false, false,
@@ -6560,6 +6572,23 @@ handle_stack_protect_attribute (tree *node, tree name, tree, int,
   return NULL_TREE;
 }
 
+/* Handle a "no_stack_protector" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_no_stack_protector_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.  */
 
index 8283e95..a3b2b3d 100644 (file)
@@ -65,6 +65,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_protector_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 *);
@@ -248,6 +250,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_protector", 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.  */
@@ -275,7 +285,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_protector",     0, 0, true, false, false, false,
+                             handle_no_stack_protector_function_attribute,
+                             attr_stack_protect_exclusions },
   { "noinline",               0, 0, true,  false, false, false,
                              handle_noinline_attribute,
                              attr_noinline_exclusions },
@@ -1156,6 +1170,22 @@ handle_stack_protect_attribute (tree *node, tree name, tree, int,
   return NULL_TREE;
 }
 
+/* Handle a "no_stack_protector" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_no_stack_protector_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.  */
 
index 2ac9aef..f3f17d3 100644 (file)
@@ -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_protector", 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_protector", 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_protector", 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_protector", 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);
        }
 
index 62549b0..4a7c858 100644 (file)
@@ -3680,6 +3680,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_protector
+@cindex @code{no_stack_protector} 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-protector-attr-2.C b/gcc/testsuite/g++.dg/no-stack-protector-attr-2.C
new file mode 100644 (file)
index 0000000..6db6fef
--- /dev/null
@@ -0,0 +1,7 @@
+/* PR c/94722 */
+/* { dg-do compile } */
+
+int __attribute__((no_stack_protector, stack_protect)) c() /* { dg-warning "ignoring attribute 'stack_protect' because it conflicts with attribute 'no_stack_protector'" } */
+{
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/no-stack-protector-attr-3.C b/gcc/testsuite/g++.dg/no-stack-protector-attr-3.C
new file mode 100644 (file)
index 0000000..dd9cd49
--- /dev/null
@@ -0,0 +1,23 @@
+/* PR c/94722 */
+/* Test that stack protection is disabled via no_stack_protector attribute. */
+
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-O2 -fstack-protector-explicit" } */
+
+/* { dg-do compile } */
+
+int __attribute__((no_stack_protector)) 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-protector-attr.C b/gcc/testsuite/g++.dg/no-stack-protector-attr.C
new file mode 100644 (file)
index 0000000..e5105bf
--- /dev/null
@@ -0,0 +1,16 @@
+/* PR c/94722 */
+/* Test that stack protection is disabled via no_stack_protector attribute. */
+
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-O2 -fstack-protector-all" } */
+
+/* { dg-do compile } */
+
+int __attribute__((no_stack_protector)) c()
+{
+  int a;
+  char b[34];
+  return 0;
+}
+
+/* { dg-final { scan-assembler-not "stack_chk_fail" } } */