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.
This commit is contained in:
parent
dc9b92facf
commit
90f2a11141
@ -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. */
|
||||
|
||||
|
32
gcc/testsuite/gdc.dg/asan/attr_no_sanitize1.d
Normal file
32
gcc/testsuite/gdc.dg/asan/attr_no_sanitize1.d
Normal file
@ -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" } }
|
39
gcc/testsuite/gdc.dg/ubsan/attr_no_sanitize2.d
Normal file
39
gcc/testsuite/gdc.dg/ubsan/attr_no_sanitize2.d
Normal file
@ -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" } }
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user