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) \
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,
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. */
--- /dev/null
+// { 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" } }
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
* which is (currently) performed by interprocedural constant propagation.
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
* mutually exclusive.