[PATCH 1/2] Compiler Attributes: Add __access macro

1 view
Skip to first unread message

Marco Elver

unread,
Apr 21, 2026, 3:04:07 PM (9 days ago) Apr 21
to el...@google.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, Arnd Bergmann, Miguel Ojeda, Dmitry Vyukov, Nathan Chancellor, ll...@lists.linux.dev
Add support for the `__access__` attribute, which is supported since gcc
>= 11 but not currently supported by clang.

The attribute allows specifying how a function accesses memory passed
via a pointer argument (read_only, write_only, read_write, none) and
optionally the size of the access. Per [1] these annotations only affect
diagnostics, and should not affect code generation:

"The access attribute enables the detection of invalid or unsafe
accesses by functions or their callers, as well as write-only
accesses to objects that are never read from. Such accesses may
be diagnosed by warnings such as -Wstringop-overflow,
-Wuninitialized, -Wunused, and others."

[1] https://gcc.gnu.org/onlinedocs/gcc/Common-Attributes.html#index-access

Signed-off-by: Marco Elver <el...@google.com>
---
include/linux/compiler_attributes.h | 12 ++++++++++++
1 file changed, 12 insertions(+)

diff --git a/include/linux/compiler_attributes.h b/include/linux/compiler_attributes.h
index c16d4199bf92..ef4e279e9872 100644
--- a/include/linux/compiler_attributes.h
+++ b/include/linux/compiler_attributes.h
@@ -20,6 +20,18 @@
* Provide links to the documentation of each supported compiler, if it exists.
*/

+/*
+ * Optional: only supported since gcc >= 11
+ * Optional: not supported by clang
+ *
+ * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Attributes.html#index-access
+ */
+#if __has_attribute(__access__)
+# define __access(x, ...) __attribute__((__access__(x, ## __VA_ARGS__)))
+#else
+# define __access(x, ...)
+#endif
+
/*
* gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-alias-function-attribute
*/
--
2.54.0.rc2.533.g4f5dca5207-goog

Marco Elver

unread,
Apr 21, 2026, 3:04:10 PM (9 days ago) Apr 21
to el...@google.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, Arnd Bergmann, Miguel Ojeda, Dmitry Vyukov, Nathan Chancellor, ll...@lists.linux.dev
Some subsystems enable -Wmaybe-uninitialized [1], which can trigger
false positives when KCSAN is enabled. Specifically, passing an
uninitialized variable to functions that instrument accesses (e.g.,
`copy_from_user()`) results in calls to `__kcsan_check_access()`.

Because `__kcsan_check_access()` takes a `const volatile void *ptr`, GCC
infers that the function may read the memory location, and thus warns if
the passed variable is uninitialized.

However, KCSAN is a dynamic analysis tool for data race detection. While
it does read the memory location to detect concurrent modifications, the
"initialized'ness" of the memory location is irrelevant for its
analysis.

Silence the warning by annotating `__kcsan_check_access()` with
`__access(none, 1)`. This tells the compiler that the pointer is not
used to access the referenced object, avoiding the false positive.

This fixes warnings like:

| CC fs/ntfs3/file.o
| In file included from include/asm-generic/rwonce.h:27,
| from arch/arm64/include/asm/rwonce.h:81,
| from include/linux/compiler.h:369,
| from include/linux/array_size.h:5,
| from include/linux/kernel.h:16,
| from include/linux/backing-dev.h:12,
| from fs/ntfs3/file.c:10:
| In function 'instrument_copy_from_user_before',
| inlined from '_inline_copy_from_user' at include/linux/uaccess.h:184:2,
| inlined from 'copy_from_user' at include/linux/uaccess.h:221:9,
| inlined from 'ntfs_ioctl_fitrim' at fs/ntfs3/file.c:77:6,
| inlined from 'ntfs_ioctl' at fs/ntfs3/file.c:164:10:
| include/linux/kcsan-checks.h:220:28: error: 'range' may be used uninitialized [-Werror=maybe-uninitialized]
| 220 | #define kcsan_check_access __kcsan_check_access
| | ^
| include/linux/kcsan-checks.h:311:9: note: in expansion of macro 'kcsan_check_access'
| 311 | kcsan_check_access(ptr, size, KCSAN_ACCESS_WRITE)
| | ^~~~~~~~~~~~~~~~~~
| include/linux/instrumented.h:147:9: note: in expansion of macro 'kcsan_check_write'
| 147 | kcsan_check_write(to, n);
| | ^~~~~~~~~~~~~~~~~
| include/linux/kcsan-checks.h: In function 'ntfs_ioctl':
| include/linux/kcsan-checks.h:37:6: note: by argument 1 of type 'const volatile void *' to '__kcsan_check_access' declared here
| 37 | void __kcsan_check_access(const volatile void *ptr, size_t size, int type);
| | ^~~~~~~~~~~~~~~~~~~~
| fs/ntfs3/file.c:65:29: note: 'range' declared here
| 65 | struct fstrim_range range;
| | ^~~~~

Link: https://lore.kernel.org/all/5da10cca-875b-418d...@app.fastmail.com/ [1]
Reported-by: Arnd Bergmann <ar...@arndb.de>
Signed-off-by: Marco Elver <el...@google.com>
---
include/linux/kcsan-checks.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/kcsan-checks.h b/include/linux/kcsan-checks.h
index 92f3843d9ebb..3a44f90ebd2b 100644
--- a/include/linux/kcsan-checks.h
+++ b/include/linux/kcsan-checks.h
@@ -34,7 +34,7 @@
* @size: size of access
* @type: access type modifier
*/
-void __kcsan_check_access(const volatile void *ptr, size_t size, int type);
+void __kcsan_check_access(const volatile void *ptr, size_t size, int type) __access(none, 1);

/*
* See definition of __tsan_atomic_signal_fence() in kernel/kcsan/core.c.
--
2.54.0.rc2.533.g4f5dca5207-goog

Miguel Ojeda

unread,
Apr 21, 2026, 3:15:48 PM (9 days ago) Apr 21
to Marco Elver, kasa...@googlegroups.com, linux-...@vger.kernel.org, Arnd Bergmann, Miguel Ojeda, Dmitry Vyukov, Nathan Chancellor, ll...@lists.linux.dev
On Tue, Apr 21, 2026 at 9:04 PM Marco Elver <el...@google.com> wrote:
>
> Add support for the `__access__` attribute, which is supported since gcc
> >= 11 but not currently supported by clang.

> + * Optional: only supported since gcc >= 11

From a quick try in Compiler Explorer, it seems GCC recognizes it
starting with GCC 10 rather than 11. It also seems to be in the docs.
Is there a reason for the 11?

Apart from that, the addition looks OK:

Acked-by: Miguel Ojeda <oj...@kernel.org>

Thanks!

Cheers,
Miguel

Marco Elver

unread,
Apr 21, 2026, 3:21:32 PM (9 days ago) Apr 21
to Miguel Ojeda, kasa...@googlegroups.com, linux-...@vger.kernel.org, Arnd Bergmann, Miguel Ojeda, Dmitry Vyukov, Nathan Chancellor, ll...@lists.linux.dev
On Tue, 21 Apr 2026 at 21:15, Miguel Ojeda
<miguel.oje...@gmail.com> wrote:
>
> On Tue, Apr 21, 2026 at 9:04 PM Marco Elver <el...@google.com> wrote:
> >
> > Add support for the `__access__` attribute, which is supported since gcc
> > >= 11 but not currently supported by clang.
>
> > + * Optional: only supported since gcc >= 11
>
> From a quick try in Compiler Explorer, it seems GCC recognizes it
> starting with GCC 10 rather than 11. It also seems to be in the docs.
> Is there a reason for the 11?

Oh, will fix. In the original report by Arnd we somehow concluded it
was 11, but I guess I should double check such things. :-)

Arnd Bergmann

unread,
Apr 21, 2026, 3:30:56 PM (9 days ago) Apr 21
to Marco Elver, Miguel Ojeda, kasa...@googlegroups.com, linux-...@vger.kernel.org, Miguel Ojeda, Dmitry Vyukov, Nathan Chancellor, ll...@lists.linux.dev
On Tue, Apr 21, 2026, at 21:20, Marco Elver wrote:
> On Tue, 21 Apr 2026 at 21:15, Miguel Ojeda
> <miguel.oje...@gmail.com> wrote:
>>
>> On Tue, Apr 21, 2026 at 9:04 PM Marco Elver <el...@google.com> wrote:
>> >
>> > Add support for the `__access__` attribute, which is supported since gcc
>> > >= 11 but not currently supported by clang.
>>
>> > + * Optional: only supported since gcc >= 11
>>
>> From a quick try in Compiler Explorer, it seems GCC recognizes it
>> starting with GCC 10 rather than 11. It also seems to be in the docs.
>> Is there a reason for the 11?
>
> Oh, will fix. In the original report by Arnd we somehow concluded it
> was 11, but I guess I should double check such things. :-)

gcc-10 knows the 'access' attribute, but not the 'none' variant:

echo 'int f(void *p) __attribute__((access(none, 1)));' | /home/arnd/cross/arm64/gcc-10.5.0-nolibc/aarch64-linux/bin/aarch64-linux-gcc -xc - -o /dev/null -c
<stdin>:1:1: error: attribute 'access' invalid mode 'none'; expected one of 'read_only', 'read_write', or 'write_only'

Arnd

Marco Elver

unread,
Apr 21, 2026, 3:36:38 PM (9 days ago) Apr 21
to Arnd Bergmann, Miguel Ojeda, kasa...@googlegroups.com, linux-...@vger.kernel.org, Miguel Ojeda, Dmitry Vyukov, Nathan Chancellor, ll...@lists.linux.dev
Good to know. KCSAN requires GCC 11+, so this is fine.

Nathan Chancellor

unread,
Apr 22, 2026, 1:50:27 AM (8 days ago) Apr 22
to Marco Elver, kasa...@googlegroups.com, linux-...@vger.kernel.org, Arnd Bergmann, Miguel Ojeda, Dmitry Vyukov, ll...@lists.linux.dev
On Tue, Apr 21, 2026 at 09:03:47PM +0200, Marco Elver wrote:
> Add support for the `__access__` attribute, which is supported since gcc
> >= 11 but not currently supported by clang.
>
> The attribute allows specifying how a function accesses memory passed
> via a pointer argument (read_only, write_only, read_write, none) and
> optionally the size of the access. Per [1] these annotations only affect
> diagnostics, and should not affect code generation:
>
> "The access attribute enables the detection of invalid or unsafe
> accesses by functions or their callers, as well as write-only
> accesses to objects that are never read from. Such accesses may
> be diagnosed by warnings such as -Wstringop-overflow,
> -Wuninitialized, -Wunused, and others."
>
> [1] https://gcc.gnu.org/onlinedocs/gcc/Common-Attributes.html#index-access
>
> Signed-off-by: Marco Elver <el...@google.com>

Reviewed-by: Nathan Chancellor <nat...@kernel.org>

David Laight

unread,
Apr 22, 2026, 6:01:21 AM (8 days ago) Apr 22
to Marco Elver, kasa...@googlegroups.com, linux-...@vger.kernel.org, Arnd Bergmann, Miguel Ojeda, Dmitry Vyukov, Nathan Chancellor, ll...@lists.linux.dev
No need to the initial 'x', you can just do:
# define __access(...) __attribute__((__access__(__VA_ARGS__)))

Putting the actual syntax in the comment would help, eg as:
__access__(read_only|read_write|write_only|none, param_number[, size])

David

Marco Elver

unread,
Apr 22, 2026, 6:21:36 AM (8 days ago) Apr 22
to David Laight, kasa...@googlegroups.com, linux-...@vger.kernel.org, Arnd Bergmann, Miguel Ojeda, Dmitry Vyukov, Nathan Chancellor, ll...@lists.linux.dev
Will add.

Arnd reports odd behaviour on gcc-11:
https://lore.kernel.org/all/4b36f629-9338-40e0...@app.fastmail.com/

The documentation says "When the optional size-index argument is
omitted for an argument of void* type, the actual pointer argument is
ignored." - but gcc 11 seems to not ignore it. Is it a known bug with
gcc 11? I.e. do we need to add a version check?

Miguel Ojeda

unread,
Apr 22, 2026, 6:25:41 AM (8 days ago) Apr 22
to Arnd Bergmann, Marco Elver, kasa...@googlegroups.com, linux-...@vger.kernel.org, Miguel Ojeda, Dmitry Vyukov, Nathan Chancellor, ll...@lists.linux.dev
On Tue, Apr 21, 2026 at 9:30 PM Arnd Bergmann <ar...@arndb.de> wrote:
>
> gcc-10 knows the 'access' attribute, but not the 'none' variant:
>
> echo 'int f(void *p) __attribute__((access(none, 1)));' | /home/arnd/cross/arm64/gcc-10.5.0-nolibc/aarch64-linux/bin/aarch64-linux-gcc -xc - -o /dev/null -c
> <stdin>:1:1: error: attribute 'access' invalid mode 'none'; expected one of 'read_only', 'read_write', or 'write_only'

Which is exactly the one we use in #2, indeed.

That makes sense, thanks!

We should still change the number here, because `__has_attribute` will
pass even with GCC 10, i.e. since someone using `none` without a gate
in Kconfig or elsewhere may not realize the mistake.

So we should probably add a comment that the access mode `none` is
only available in GCC 11 -- especially so if we add the docs David
suggests, because otherwise it seems like it is supported.

Cheers,
Miguel

Miguel Ojeda

unread,
Apr 22, 2026, 6:25:48 AM (8 days ago) Apr 22
to David Laight, Marco Elver, kasa...@googlegroups.com, linux-...@vger.kernel.org, Arnd Bergmann, Miguel Ojeda, Dmitry Vyukov, Nathan Chancellor, ll...@lists.linux.dev
On Wed, Apr 22, 2026 at 12:01 PM David Laight
<david.lai...@gmail.com> wrote:
>
> Putting the actual syntax in the comment would help, eg as:
> __access__(read_only|read_write|write_only|none, param_number[, size])

I guess you mean as a quick reminder for those that already know about
the attribute?

That sounds OK for an attribute like this, though generally speaking I
would avoid duplicating the compiler docs. (Hopefully people will
still read the actual docs... :)

By the way, that could be `__access`, i.e. documenting our side, i.e. the macro.

Cheers,
Miguel

Miguel Ojeda

unread,
Apr 22, 2026, 6:31:06 AM (8 days ago) Apr 22
to Arnd Bergmann, Marco Elver, kasa...@googlegroups.com, linux-...@vger.kernel.org, Miguel Ojeda, Dmitry Vyukov, Nathan Chancellor, ll...@lists.linux.dev
On Wed, Apr 22, 2026 at 12:25 PM Miguel Ojeda
<miguel.oje...@gmail.com> wrote:
>
> Which is exactly the one we use in #2, indeed.
>
> That makes sense, thanks!
>
> We should still change the number here, because `__has_attribute` will
> pass even with GCC 10, i.e. since someone using `none` without a gate
> in Kconfig or elsewhere may not realize the mistake.
>
> So we should probably add a comment that the access mode `none` is
> only available in GCC 11 -- especially so if we add the docs David
> suggests, because otherwise it seems like it is supported.

Either that or we simply move it to `compiler-gcc.h` or similar with a
`GCC_VERSION` check instead.

...which given what Marco is saying in a sibling comment, may be needed anyway.

Cheers,
Miguel

Marco Elver

unread,
Apr 22, 2026, 8:53:05 AM (8 days ago) Apr 22
to el...@google.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, Arnd Bergmann, Dmitry Vyukov
Some subsystems enable -Wmaybe-uninitialized [1], which can trigger
false positives when KCSAN is enabled. Specifically, passing an
uninitialized variable to functions that instrument accesses (e.g.,
copy_from_user()) results in calls to __kcsan_check_access().

Because __kcsan_check_access() takes a `const volatile void *ptr`, GCC
infers that the function may only read the memory location, and thus
warns if the passed variable is uninitialized.

However, KCSAN is a dynamic analysis tool for data race detection; while
it does read the memory location to detect concurrent modifications, the
"initialized'ness" of the memory location is irrelevant for its analysis.

Use absolute_pointer() in __kcsan_check_write(), kcsan_check_write(),
and kcsan_check_atomic_write() to hide the pointer from the compiler,
preventing it from concluding that the pointer passed points to
uninitialized memory.
Signed-off-by: Marco Elver <el...@google.com>
---
v2:
* Switch from __attribute__((access)) to absolute_pointer() to silence
the warnings instead of introducing new ones.
---
include/linux/kcsan-checks.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/linux/kcsan-checks.h b/include/linux/kcsan-checks.h
index 92f3843d9ebb..e135dacaa90f 100644
--- a/include/linux/kcsan-checks.h
+++ b/include/linux/kcsan-checks.h
@@ -282,7 +282,7 @@ static inline void __kcsan_disable_current(void) { }
* @size: size of access
*/
#define __kcsan_check_write(ptr, size) \
- __kcsan_check_access(ptr, size, KCSAN_ACCESS_WRITE)
+ __kcsan_check_access(absolute_pointer(ptr), size, KCSAN_ACCESS_WRITE)

/**
* __kcsan_check_read_write - check regular read-write access for races
@@ -308,7 +308,7 @@ static inline void __kcsan_disable_current(void) { }
* @size: size of access
*/
#define kcsan_check_write(ptr, size) \
- kcsan_check_access(ptr, size, KCSAN_ACCESS_WRITE)
+ kcsan_check_access(absolute_pointer(ptr), size, KCSAN_ACCESS_WRITE)

/**
* kcsan_check_read_write - check regular read-write access for races
@@ -331,7 +331,7 @@ static inline void __kcsan_disable_current(void) { }
#define kcsan_check_atomic_read(ptr, size) \
kcsan_check_access(ptr, size, KCSAN_ACCESS_ATOMIC)
#define kcsan_check_atomic_write(ptr, size) \
- kcsan_check_access(ptr, size, KCSAN_ACCESS_ATOMIC | KCSAN_ACCESS_WRITE)
+ kcsan_check_access(absolute_pointer(ptr), size, KCSAN_ACCESS_ATOMIC | KCSAN_ACCESS_WRITE)
#define kcsan_check_atomic_read_write(ptr, size) \
kcsan_check_access(ptr, size, KCSAN_ACCESS_ATOMIC | KCSAN_ACCESS_WRITE | KCSAN_ACCESS_COMPOUND)
#endif
--
2.54.0.rc2.533.g4f5dca5207-goog

David Laight

unread,
Apr 22, 2026, 9:02:40 AM (8 days ago) Apr 22
to Miguel Ojeda, Marco Elver, kasa...@googlegroups.com, linux-...@vger.kernel.org, Arnd Bergmann, Miguel Ojeda, Dmitry Vyukov, Nathan Chancellor, ll...@lists.linux.dev
On Wed, 22 Apr 2026 12:25:32 +0200
Miguel Ojeda <miguel.oje...@gmail.com> wrote:

> On Wed, Apr 22, 2026 at 12:01 PM David Laight
> <david.lai...@gmail.com> wrote:
> >
> > Putting the actual syntax in the comment would help, eg as:
> > __access__(read_only|read_write|write_only|none, param_number[, size])
>
> I guess you mean as a quick reminder for those that already know about
> the attribute?
>
> That sounds OK for an attribute like this, though generally speaking I
> would avoid duplicating the compiler docs. (Hopefully people will
> still read the actual docs... :)

It might save someone who is just 'wondering what it is about' from having
to read the gcc docs - particularly if reading the file where you don't have
a browser handy, or in an editor that doesn't support following links.

I also had to read a lot of the 'actual doc' to get a hint of what it
all meant.

> By the way, that could be `__access`, i.e. documenting our side, i.e. the macro.

True, and ', size' should be ', count'.

David

>
> Cheers,
> Miguel

Marco Elver

unread,
Apr 22, 2026, 9:07:07 AM (8 days ago) Apr 22
to linux-...@vger.kernel.org, David Laight, kasa...@googlegroups.com, Arnd Bergmann, Miguel Ojeda, Dmitry Vyukov, Nathan Chancellor, ll...@lists.linux.dev
FWIW, I found that even later GCC seem to complain when using access
'none' - https://godbolt.org/z/jGGG97MW3

I'm not sure if that's intended or not - either that, or the GCC docs
are misleading me here. To avoid this footgun, I'm going to drop this
patch and found a simpler solution using absolute_pointer():
https://lore.kernel.org/all/20260422125256...@google.com/

David Laight

unread,
Apr 22, 2026, 9:22:58 AM (8 days ago) Apr 22
to Miguel Ojeda, Arnd Bergmann, Marco Elver, kasa...@googlegroups.com, linux-...@vger.kernel.org, Miguel Ojeda, Dmitry Vyukov, Nathan Chancellor, ll...@lists.linux.dev
Especially since the gcc docs make it pretty impossible to find out when
anything was added. Trial and error on godbolt shouldn't really be needed.

(and I missed that the size/count is the argument number as well).

David

>
> Cheers,
> Miguel
>

Marco Elver

unread,
9:31 AM (3 hours ago) 9:31 AM
to el...@google.com, kasa...@googlegroups.com, linux-...@vger.kernel.org, Arnd Bergmann, Dmitry Vyukov
Arnd, are you ok with this version?

I don't think there's a simpler option - the name "absolute_pointer"
might be misleading, but the underlying RELOC_HIDE is what we need
here. Could use RELOC_HIDE directly.

The attribute would have been nice, but comes with a whole set of new
problems. :-/

Arnd Bergmann

unread,
9:35 AM (3 hours ago) 9:35 AM
to Marco Elver, kasa...@googlegroups.com, linux-...@vger.kernel.org, Dmitry Vyukov
On Thu, Apr 30, 2026, at 15:30, Marco Elver wrote:
> On Wed, 22 Apr 2026 at 14:53, Marco Elver <el...@google.com> wrote:

>>
>> Link: https://lore.kernel.org/all/5da10cca-875b-418d...@app.fastmail.com/ [1]
>> Reported-by: Arnd Bergmann <ar...@arndb.de>
>> Signed-off-by: Marco Elver <el...@google.com>
>
> Arnd, are you ok with this version?
>
> I don't think there's a simpler option - the name "absolute_pointer"
> might be misleading, but the underlying RELOC_HIDE is what we need
> here. Could use RELOC_HIDE directly.
>
> The attribute would have been nice, but comes with a whole set of new
> problems. :-/

Agreed, I had tried a few things but haven't been able to come up
with anything better than this or my original patch.

I've tested this version in my randconfig tree using gcc-16
and found no more regressions.

Reviewed-by: Arnd Bergmann <ar...@arndb.de>
Tested-by: Arnd Bergmann <ar...@arndb.de>

Marco Elver

unread,
9:55 AM (3 hours ago) 9:55 AM
to Arnd Bergmann, kasa...@googlegroups.com, linux-...@vger.kernel.org, Dmitry Vyukov
Thanks, I've applied it to the kcsan tree.
Reply all
Reply to author
Forward
0 new messages