On Mon, Oct 20, 2025 at 3:01 PM Kees Cook <[email protected]> wrote: > > Introduce __counted_by_ptr(), which works like __counted_by(), but for > pointer struct members: > > struct foo { > int a, b, c; > char *buffer __counted_by_ptr(bytes); > short nr_bars; > struct bar *bars __counted_by_ptr(nr_bars); > size_t bytes; > }; > > Since "counted_by" can only be applied to pointer members in very recent > compiler versions, its application ends up needing to be distinct from > flexible array "counted_by" annotations, hence a separate macro. > > Unfortunately, this annotation cannot be used for "void *" members > (since such a member is considered a pointer to an incomplete type, > and neither Clang nor GCC developers could be convinced otherwise[1], > even in the face of the GNU extension that "void *" has size "1 byte" > for pointer arithmetic). For "void *" members, we must use the coming > "sized_by" attribute. > I'm pretty sure that "sized_by" is available in Clang right now.
-bw > Link: https://gcc.gnu.org/pipermail/gcc-patches/2025-May/683136.html [1] > Signed-off-by: Kees Cook <[email protected]> > --- > Cc: Miguel Ojeda <[email protected]> > Cc: Nathan Chancellor <[email protected]> > Cc: Nick Desaulniers <[email protected]> > Cc: Bill Wendling <[email protected]> > Cc: Justin Stitt <[email protected]> > Cc: Peter Zijlstra <[email protected]> > Cc: Marco Elver <[email protected]> > Cc: Przemek Kitszel <[email protected]> > Cc: Andrew Morton <[email protected]> > Cc: Masahiro Yamada <[email protected]> > Cc: Christophe Leroy <[email protected]> > Cc: Johannes Weiner <[email protected]> > Cc: <[email protected]> > --- > init/Kconfig | 11 +++++++++++ > Makefile | 4 ++++ > include/linux/compiler_types.h | 21 ++++++++++++++++++++- > include/uapi/linux/stddef.h | 4 ++++ > 4 files changed, 39 insertions(+), 1 deletion(-) > > diff --git a/init/Kconfig b/init/Kconfig > index cab3ad28ca49..54691b086bc6 100644 > --- a/init/Kconfig > +++ b/init/Kconfig > @@ -139,6 +139,17 @@ config CC_HAS_COUNTED_BY > # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108896 > default y if CC_IS_GCC && GCC_VERSION >= 150100 > > +config CC_HAS_COUNTED_BY_PTR_BARE > + def_bool $(success,echo 'struct foo { int *ptr > __attribute__((__counted_by__(count))); int count; };' | $(CC) $(CLANG_FLAGS) > -x c - -c -o /dev/null -Werror) > + > +config CC_HAS_COUNTED_BY_PTR_EXP > + def_bool $(success,echo 'struct foo { int *ptr > __attribute__((__counted_by__(count))); int count; };' | $(CC) $(CLANG_FLAGS) > -fexperimental-late-parse-attributes -x c - -c -o /dev/null -Werror) > + depends on !CC_HAS_COUNTED_BY_PTR_BARE > + > +config CC_HAS_COUNTED_BY_PTR > + def_bool y > + depends on CC_HAS_COUNTED_BY_PTR_BARE || CC_HAS_COUNTED_BY_PTR_EXP > + > config CC_HAS_MULTIDIMENSIONAL_NONSTRING > def_bool $(success,echo 'char tag[][4] __attribute__((__nonstring__)) > = { };' | $(CC) $(CLANG_FLAGS) -x c - -c -o /dev/null -Werror) > > diff --git a/Makefile b/Makefile > index d14824792227..1b297dcbb0df 100644 > --- a/Makefile > +++ b/Makefile > @@ -933,6 +933,10 @@ KBUILD_CFLAGS += $(CC_AUTO_VAR_INIT_ZERO_ENABLER) > endif > endif > > +ifdef CONFIG_CC_HAS_COUNTED_BY_PTR_EXP > +KBUILD_CFLAGS += -fexperimental-late-parse-attributes > +endif > + > # Explicitly clear padding bits during variable initialization > KBUILD_CFLAGS += $(call cc-option,-fzero-init-padding-bits=all) > > diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h > index 59288a2c1ad2..f197ea03b593 100644 > --- a/include/linux/compiler_types.h > +++ b/include/linux/compiler_types.h > @@ -353,11 +353,14 @@ struct ftrace_likely_data { > #endif > > /* > + * Runtime track number of flexible array member elements for use by > + * CONFIG_FORTIFY_SOURCE and CONFIG_UBSAN_BOUNDS. > + * > * Optional: only supported since gcc >= 15 > * Optional: only supported since clang >= 18 > * > * gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108896 > - * clang: https://github.com/llvm/llvm-project/pull/76348 > + * clang: > https://clang.llvm.org/docs/AttributeReference.html#counted-by-counted-by-or-null-sized-by-sized-by-or-null > * > * __bdos on clang < 19.1.2 can erroneously return 0: > * https://github.com/llvm/llvm-project/pull/110497 > @@ -371,6 +374,22 @@ struct ftrace_likely_data { > # define __counted_by(member) > #endif > > +/* > + * Runtime track number of objects pointed to by a pointer member for > + * use by CONFIG_FORTIFY_SOURCE and CONFIG_UBSAN_BOUNDS. > + * > + * Optional: only supported since gcc >= 16 > + * Optional: only supported since clang >= 20 > + * > + * gcc: https://gcc.gnu.org/pipermail/gcc-patches/2025-April/681727.html > + * clang: ... > + */ > +#ifdef CONFIG_CC_HAS_COUNTED_BY_PTR > +# define __counted_by_ptr(member) > __attribute__((__counted_by__(member))) > +#else > +# define __counted_by_ptr(member) > +#endif > + > /* > * Optional: only supported since gcc >= 15 > * Optional: not supported by Clang > diff --git a/include/uapi/linux/stddef.h b/include/uapi/linux/stddef.h > index 9a28f7d9a334..111b097ec00b 100644 > --- a/include/uapi/linux/stddef.h > +++ b/include/uapi/linux/stddef.h > @@ -72,6 +72,10 @@ > #define __counted_by_be(m) > #endif > > +#ifndef __counted_by_ptr > +#define __counted_by_ptr(m) > +#endif > + > #ifdef __KERNEL__ > #define __kernel_nonstring __nonstring > #else > -- > 2.34.1 >
