From: Guillaume Gomez <[email protected]>
gcc/ChangeLog:
* asan.h (sanitize_coverage_p): Add support of "coverage" in
`no_sanitize`.
* doc/extend.texi: Update documentation for `no_sanitize_coverage` and
mention that `no_sanitize` supports "coverage" string.
* flag-types.h (enum sanitize_code): Add `SANITIZE_COVERAGE` in the
`sanitize_code` enum.
* opts.cc (parse_no_sanitize_attribute): Add parsing of "coverage".
* tree-cfg.cc (print_no_sanitize_attr_value): Add display of "coverage"
if the flag is present.
gcc/c-family/ChangeLog:
* c-attribs.cc (handle_no_sanitize_coverage_attribute): Update
handling of `no_sanitize_coverage` to use `add_no_sanitize_value`.
---
I'm planning to make all `no_sanitize_*` attributes have their alias in
`no_sanitize` directly for the following reasons:
* I don't see any reason to keep them separate
* It would make my life a lot easier to implement this attribute in
`no_sanitize`: rather than having to support all `no_sanitize*` attributes, I
can now have one function and one enum to handle them all at once.
I kept `-fno-sanitize-coverage` separated from `no_sanitize("coverage")`
handling, hence why it's not added in `sanitizer_opts` and need some special
handling for it.
I can make it all in one patch or do one patch per attribute (like I'm
currently doing), as you prefer.
cc @jsm28 @pinskia
This is a forge pull request published on the gcc-patches mailing list mailing
list
as requested by Guillaume Gomez via Sourceware Forge
<[email protected]>.
Forge discussion: https://forge.sourceware.org/gcc/gcc/pulls/279
Get it locally using:
```
git fetch forge-upstream "+refs/versioned_pull/279/*:refs/versioned_pull/279/*"
git switch -c "pr-279-v1" "refs/versioned_pull/279/1/head"
```
Or, download the patch at: https://forge.sourceware.org/gcc/gcc/pulls/279.diff
Created on: 2026-11-13 19:03:01+00:00
Latest update: 2026-11-13 19:03:44+00:00
Changes: 8 changed files, 90 additions, 9 deletions
Head revision: imperio/gcc ref no_sanitize_coverage commit
5fb78dbc9decb3d1b8230b716b3a75b129b865ff
Base revision: gcc/gcc ref trunk commit
5417ceaa41c63fc747833a71111e7578bebcad20 r17-6231-g5417ceaa41c63f
Merge base: 5417ceaa41c63fc747833a71111e7578bebcad20
Requested Reviewers:
Changed files:
- A: gcc/testsuite/gcc.dg/sancov/attribute-2.c
- A: gcc/testsuite/gcc.dg/sancov/attribute-3.c
- M: gcc/asan.h
- M: gcc/c-family/c-attribs.cc
- M: gcc/doc/extend.texi
- M: gcc/flag-types.h
- M: gcc/opts.cc
- M: gcc/tree-cfg.cc
gcc/asan.h | 16 ++++++---
gcc/c-family/c-attribs.cc | 8 ++---
gcc/doc/extend.texi | 6 +++-
gcc/flag-types.h | 3 ++
gcc/opts.cc | 9 +++++
gcc/testsuite/gcc.dg/sancov/attribute-2.c | 40 +++++++++++++++++++++++
gcc/testsuite/gcc.dg/sancov/attribute-3.c | 9 +++++
gcc/tree-cfg.cc | 8 +++++
8 files changed, 90 insertions(+), 9 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/sancov/attribute-2.c
create mode 100644 gcc/testsuite/gcc.dg/sancov/attribute-3.c
diff --git a/gcc/asan.h b/gcc/asan.h
index 48499115539ce..5df88e96f1041 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -272,10 +272,18 @@ sanitize_flags_p (sanitize_code_type flag,
inline bool
sanitize_coverage_p (const_tree fn = current_function_decl)
{
- return (flag_sanitize_coverage
- && (fn == NULL_TREE
- || lookup_attribute ("no_sanitize_coverage",
- DECL_ATTRIBUTES (fn)) == NULL_TREE));
+ if (!flag_sanitize_coverage)
+ return false;
+
+ if (fn != NULL_TREE)
+ {
+ tree value = lookup_attribute ("no_sanitize", DECL_ATTRIBUTES (fn));
+ if (value
+ && (tree_to_uhwi (TREE_VALUE (value)) & SANITIZE_COVERAGE) != 0)
+ return false;
+ }
+
+ return true;
}
#endif /* TREE_ASAN */
diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 5d45a345d26c0..8812f81349bb9 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -1362,11 +1362,11 @@ static tree
handle_no_sanitize_coverage_attribute (tree *node, tree name, tree, int,
bool *no_add_attrs)
{
+ *no_add_attrs = true;
if (TREE_CODE (*node) != FUNCTION_DECL)
- {
- warning (OPT_Wattributes, "%qE attribute ignored", name);
- *no_add_attrs = true;
- }
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ else
+ add_no_sanitize_value (*node, (sanitize_code_type) SANITIZE_COVERAGE);
return NULL_TREE;
}
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index eb8dd1b04f430..18654f46b6190 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -3737,7 +3737,10 @@ This attribute applies to functions.
The @code{no_sanitize} attribute
informs the compiler that it should not do sanitization of any option
mentioned in @var{sanitize_option}. A list of values acceptable by
-the @option{-fsanitize} option can be provided.
+the @option{-fsanitize} option can be provided. In addition,
+@code{coverage} disables coverage-guided fuzzing code instrumentation
+(@option{-fsanitize-coverage}), like the @code{no_sanitize_coverage}
+attribute.
@smallexample
void __attribute__ ((no_sanitize ("alignment", "object-size")))
@@ -3768,6 +3771,7 @@ This attribute applies to functions.
The @code{no_sanitize_coverage} attribute
informs the compiler that it should not do coverage-guided
fuzzing code instrumentation (@option{-fsanitize-coverage}).
+It is equivalent to @code{no_sanitize ("coverage")}.
@atindex @code{no_sanitize_thread}
@cindex functions that should not be sanitized
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index c4eb8a0520a7e..7427f66cacdd7 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -340,6 +340,9 @@ enum sanitize_code {
SANITIZE_SHADOW_CALL_STACK = 1UL << 31,
/* Memory Tagging for Stack. */
SANITIZE_MEMTAG_STACK = 1ULL << 32,
+ /* This is only used by the `no_sanitize attribute`: `-fsanitize-coverage=`
+ is handled separately. */
+ SANITIZE_COVERAGE = 1ULL << 33,
/* Memory Tagging. */
SANITIZE_MEMTAG = SANITIZE_MEMTAG_STACK,
SANITIZE_SHIFT = SANITIZE_SHIFT_BASE | SANITIZE_SHIFT_EXPONENT,
diff --git a/gcc/opts.cc b/gcc/opts.cc
index ec98edc9a515d..430c4cab1e3b6 100644
--- a/gcc/opts.cc
+++ b/gcc/opts.cc
@@ -2447,6 +2447,15 @@ parse_no_sanitize_attribute (char *value)
while (q != NULL)
{
+ /* "coverage" is not a `-fsanitize=` option, so it is not part of
+ `sanitizer_opts` and so we need to handle it on its own. */
+ if (strcmp (q, "coverage") == 0)
+ {
+ flags |= SANITIZE_COVERAGE;
+ q = strtok (NULL, ",");
+ continue;
+ }
+
for (i = 0; sanitizer_opts[i].name != NULL; ++i)
if (strcmp (sanitizer_opts[i].name, q) == 0)
{
diff --git a/gcc/testsuite/gcc.dg/sancov/attribute-2.c
b/gcc/testsuite/gcc.dg/sancov/attribute-2.c
new file mode 100644
index 0000000000000..f336435a5c9cd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/sancov/attribute-2.c
@@ -0,0 +1,40 @@
+/* Test that no_sanitize ("coverage") behaves like no_sanitize_coverage. */
+/* { dg-do compile } */
+/* { dg-options "-fsanitize-coverage=trace-pc -fdump-tree-optimized" } */
+
+void foo(void)
+{
+}
+
+void
+__attribute__((no_sanitize ("coverage")))
+bar(void)
+{
+}
+
+static void inline
+__attribute__((always_inline))
+inline_fn(void)
+{
+}
+
+void
+__attribute__((no_sanitize ("coverage")))
+baz(void)
+{
+ inline_fn();
+}
+
+void
+__attribute__((no_sanitize ("address,coverage")))
+qux(void)
+{
+}
+
+void
+__attribute__((no_sanitize ("undefined", "coverage")))
+quux(void)
+{
+}
+
+/* { dg-final { scan-tree-dump-times "__builtin___sanitizer_cov_trace_pc
\\(\\)" 1 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/sancov/attribute-3.c
b/gcc/testsuite/gcc.dg/sancov/attribute-3.c
new file mode 100644
index 0000000000000..20cf190a96da2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/sancov/attribute-3.c
@@ -0,0 +1,9 @@
+/* Test that -fsanitize=coverage is still rejected: "coverage" is only
+ accepted by the no_sanitize attribute. */
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=coverage" } */
+/* { dg-error "unrecognized argument to '-fsanitize=' option: 'coverage'" "" {
target *-*-* } 0 } */
+
+void foo(void)
+{
+}
diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
index a851b6c21f057..5b986c10b0bf2 100644
--- a/gcc/tree-cfg.cc
+++ b/gcc/tree-cfg.cc
@@ -8290,6 +8290,14 @@ print_no_sanitize_attr_value (FILE *file, tree value)
first = false;
}
}
+ /* "coverage" is not a `-fsanitize=` option, so it is not part of
+ `sanitizer_opts` and so we need to handle it on its own. */
+ if (flags & SANITIZE_COVERAGE)
+ {
+ if (!first)
+ fprintf (file, " | ");
+ fprintf (file, "coverage");
+ }
}
/* Dump FUNCTION_DECL FN to file FILE using FLAGS (see TDF_* in dumpfile.h)
--
2.56.0