From 346b302d09c1e6db56d9fe69048acb32fbb97845 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 15 May 2020 14:42:12 +0200 Subject: [PATCH] Implement no_stack_protector attribute. gcc/ChangeLog: 2020-05-18 Martin Liska 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 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 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 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 | 31 ++++++- gcc/c-family/c-attribs.c | 32 +++++++- gcc/cfgexpand.c | 82 ++++++++++--------- gcc/doc/extend.texi | 4 + .../g++.dg/no-stack-protector-attr-2.C | 7 ++ .../g++.dg/no-stack-protector-attr-3.C | 23 ++++++ .../g++.dg/no-stack-protector-attr.C | 16 ++++ 7 files changed, 154 insertions(+), 41 deletions(-) create mode 100644 gcc/testsuite/g++.dg/no-stack-protector-attr-2.C create mode 100644 gcc/testsuite/g++.dg/no-stack-protector-attr-3.C create mode 100644 gcc/testsuite/g++.dg/no-stack-protector-attr.C diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index 048a0cf13b4..d50872f81b0 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -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. */ diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 8283e959c89..a3b2b3d58bd 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -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. */ diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 2ac9aef389a..f3f17d38f9e 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_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); } diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 62549b02452..4a7c85822a7 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -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 index 00000000000..6db6fef58d1 --- /dev/null +++ b/gcc/testsuite/g++.dg/no-stack-protector-attr-2.C @@ -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 index 00000000000..dd9cd4991b6 --- /dev/null +++ b/gcc/testsuite/g++.dg/no-stack-protector-attr-3.C @@ -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 index 00000000000..e5105bf9478 --- /dev/null +++ b/gcc/testsuite/g++.dg/no-stack-protector-attr.C @@ -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" } } */ -- 2.30.2