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

Reply via email to