public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
From: Iain Buclaw <ibuclaw@gcc.gnu.org>
To: gcc-cvs@gcc.gnu.org
Subject: [gcc r13-1115] d: Add `@no_sanitize' attribute to compiler and library.
Date: Wed, 15 Jun 2022 21:16:42 +0000 (GMT)	[thread overview]
Message-ID: <20220615211642.9DA613858288@sourceware.org> (raw)

https://gcc.gnu.org/g:90f2a111413a6d4264335046d68ffa19725864b6

commit r13-1115-g90f2a111413a6d4264335046d68ffa19725864b6
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date:   Wed Jun 15 22:51:52 2022 +0200

    d: Add `@no_sanitize' attribute to compiler and library.
    
    The `@no_sanitize' attribute disables a particular sanitizer for this
    function, analogous to `__attribute__((no_sanitize))'.  The library also
    defines `@noSanitize' to be compatible with the LLVM D compiler's
    `ldc.attributes'.
    
    gcc/d/ChangeLog:
    
            * d-attribs.cc (d_langhook_attribute_table): Add no_sanitize.
            (d_handle_no_sanitize_attribute): New function.
    
    libphobos/ChangeLog:
    
            * libdruntime/gcc/attributes.d (no_sanitize): Define.
            (noSanitize): Define.
    
    gcc/testsuite/ChangeLog:
    
            * gdc.dg/asan/attr_no_sanitize1.d: New test.
            * gdc.dg/ubsan/attr_no_sanitize2.d: New test.

Diff:
---
 gcc/d/d-attribs.cc                             | 52 ++++++++++++++++++++++++++
 gcc/testsuite/gdc.dg/asan/attr_no_sanitize1.d  | 32 ++++++++++++++++
 gcc/testsuite/gdc.dg/ubsan/attr_no_sanitize2.d | 39 +++++++++++++++++++
 libphobos/libdruntime/gcc/attributes.d         | 35 +++++++++++++++++
 4 files changed, 158 insertions(+)

diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc
index 4c6e7a7a4bd..4b54426be39 100644
--- a/gcc/d/d-attribs.cc
+++ b/gcc/d/d-attribs.cc
@@ -78,6 +78,7 @@ static tree d_handle_cold_attribute (tree *, tree, tree, int, bool *);
 static tree d_handle_restrict_attribute (tree *, tree, tree, int, bool *);
 static tree d_handle_used_attribute (tree *, tree, tree, int, bool *);
 static tree d_handle_visibility_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_no_sanitize_attribute (tree *, tree, tree, int, bool *);
 
 /* Helper to define attribute exclusions.  */
 #define ATTR_EXCL(name, function, type, variable)	\
@@ -220,6 +221,8 @@ const attribute_spec d_langhook_attribute_table[] =
 	     d_handle_alloc_size_attribute, attr_alloc_exclusions),
   ATTR_SPEC ("cold", 0, 0, true, false, false, false,
 	     d_handle_cold_attribute, attr_cold_hot_exclusions),
+  ATTR_SPEC ("no_sanitize", 1, -1, true, false, false, false,
+	     d_handle_no_sanitize_attribute, NULL),
   ATTR_SPEC ("restrict", 0, 0, true, false, false, false,
 	     d_handle_restrict_attribute, NULL),
   ATTR_SPEC ("used", 0, 0, true, false, false, false,
@@ -1364,6 +1367,55 @@ d_handle_cold_attribute (tree *node, tree name, tree, int, bool *no_add_attrs)
   return NULL_TREE;
 }
 
+/* Handle a "no_sanitize" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+d_handle_no_sanitize_attribute (tree *node, tree name, tree args, int,
+				bool *no_add_attrs)
+{
+  *no_add_attrs = true;
+
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      return NULL_TREE;
+    }
+
+  unsigned int flags = 0;
+  for (; args; args = TREE_CHAIN (args))
+    {
+      tree id = TREE_VALUE (args);
+      if (TREE_CODE (id) != STRING_CST)
+	{
+	  error ("%qE argument not a string", name);
+	  return NULL_TREE;
+	}
+
+      char *string = ASTRDUP (TREE_STRING_POINTER (id));
+      flags |= parse_no_sanitize_attribute (string);
+    }
+
+  /* Store the flags argument back into no_sanitize attribute as an integer,
+     merge existing flags if no_sanitize was previously handled.  */
+  if (tree attr = lookup_attribute ("no_sanitize", DECL_ATTRIBUTES (*node)))
+    {
+      unsigned int old_value = tree_to_uhwi (TREE_VALUE (attr));
+      flags |= old_value;
+
+      if (flags != old_value)
+	TREE_VALUE (attr) = build_int_cst (d_uint_type, flags);
+    }
+  else
+    {
+      DECL_ATTRIBUTES (*node) = tree_cons (get_identifier ("no_sanitize"),
+		      			   build_int_cst (d_uint_type, flags),
+		      			   DECL_ATTRIBUTES (*node));
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "restrict" attribute; arguments as in
    struct attribute_spec.handler.  */
 
diff --git a/gcc/testsuite/gdc.dg/asan/attr_no_sanitize1.d b/gcc/testsuite/gdc.dg/asan/attr_no_sanitize1.d
new file mode 100644
index 00000000000..28908d4cbc0
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/asan/attr_no_sanitize1.d
@@ -0,0 +1,32 @@
+// { dg-options "-fsanitize=address -O3 -fdump-tree-optimized" }
+// { dg-do compile }
+
+import gcc.attributes;
+
+@no_sanitize("address")
+__gshared int globalvar1; // { dg-warning "attribute ignored" }
+
+pragma(inline, true)
+@no_sanitize("address")
+void test_no_address()
+{
+    counter++;
+}
+
+pragma(inline, true)
+void test_sanitize()()
+{
+    counter++;
+}
+
+void func1()
+{
+  counter++;
+  test_no_address();
+  test_sanitize();
+}
+
+private int counter;
+
+// { dg-final { scan-tree-dump-times "Function test_no_address" 1 "optimized" } }
+// { dg-final { scan-tree-dump-times "Function test_sanitize" 0 "optimized" } }
diff --git a/gcc/testsuite/gdc.dg/ubsan/attr_no_sanitize2.d b/gcc/testsuite/gdc.dg/ubsan/attr_no_sanitize2.d
new file mode 100644
index 00000000000..c6e47845cd5
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/ubsan/attr_no_sanitize2.d
@@ -0,0 +1,39 @@
+// { dg-options "-fsanitize=undefined -O3 -fdump-tree-optimized" }
+// { dg-do compile }
+
+import gcc.attributes;
+
+@no_sanitize("invalid_name")
+void func1() { } // { dg-warning "attribute directive ignored" }
+
+@no_sanitize("address")
+@no_sanitize("thread")
+@no_sanitize("address,thread")
+@no_sanitize("address", "undefined")
+@no_sanitize("undefined", "leak", "return,null,bounds")
+void func2() { }
+
+pragma(inline, true)
+@no_sanitize("undefined")
+void test_no_undefined()()
+{
+    counter++;
+}
+
+pragma(inline, true)
+void test_sanitize()()
+{
+    counter++;
+}
+
+void func3()
+{
+  counter++;
+  test_no_undefined();
+  test_sanitize();
+}
+
+private __gshared int counter;
+
+// { dg-final { scan-tree-dump-times "Function test_no_undefined" 1 "optimized" } }
+// { dg-final { scan-tree-dump-times "Function test_sanitize" 0 "optimized" } }
diff --git a/libphobos/libdruntime/gcc/attributes.d b/libphobos/libdruntime/gcc/attributes.d
index ca066cef822..710e8ab8a59 100644
--- a/libphobos/libdruntime/gcc/attributes.d
+++ b/libphobos/libdruntime/gcc/attributes.d
@@ -181,6 +181,33 @@ enum flatten = attribute("flatten");
  */
 enum no_icf = attribute("no_icf");
 
+/**
+ * The `@no_sanitize` attribute on functions is used to inform the compiler
+ * that it should not do sanitization of any option mentioned in
+ * sanitize_option.  A list of values acceptable by the `-fsanitize` option
+ * can be provided.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @no_sanitize("alignment", "object-size") void func1() { }
+ * @no_sanitize("alignment,object-size") void func2() { }
+ * ---
+ */
+
+auto no_sanitize(A...)(A arguments)
+    if (allSatisfy!(isStringValue, arguments))
+{
+    return attribute("no_sanitize", arguments);
+}
+
+auto no_sanitize(A...)(A arguments)
+    if (!allSatisfy!(isStringValue, arguments))
+{
+    assert(false, "no_sanitize attribute argument not a string constant");
+}
+
 /**
  * The `@noclone` attribute prevents a function from being considered for
  * cloning - a mechanism that produces specialized copies of functions and
@@ -594,6 +621,14 @@ enum hidden = visibility("hidden");
  */
 enum naked = attribute("naked");
 
+/**
+ * Disables a particular sanitizer for this function.
+ * Valid sanitizer names are all names accepted by `-fsanitize=` commandline option.
+ * Multiple sanitizers can be disabled by applying this UDA multiple times, e.g.
+ * `@noSanitize("address") `@noSanitize("thread")` to disable both ASan and TSan.
+ */
+alias noSanitize = no_sanitize;
+
 /**
  * Sets the optimization strategy for a function.
  * Valid strategies are "none", "optsize", "minsize". The strategies are


                 reply	other threads:[~2022-06-15 21:16 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220615211642.9DA613858288@sourceware.org \
    --to=ibuclaw@gcc.gnu.org \
    --cc=gcc-cvs@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).