linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn
@ 2021-10-14 13:23 Miguel Ojeda
  2021-10-14 15:01 ` Peter Zijlstra
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: Miguel Ojeda @ 2021-10-14 13:23 UTC (permalink / raw)
  To: Nathan Chancellor, Nick Desaulniers
  Cc: Kees Cook, Peter Zijlstra, Miguel Ojeda, linux-kernel, llvm

`__compiletime_assert` declares a fake `extern` function
which appears (to the compiler) to be called when the test fails.

Therefore, compilers may emit possibly-uninitialized warnings
in some cases, even if it will be an error anyway (for compilers
supporting the `error` attribute, e.g. GCC and Clang >= 14)
or a link failure (for those that do not, e.g. Clang < 14).

Annotating the fake function as `__noreturn` gives them
the information they need to avoid the warning,
e.g. see https://godbolt.org/z/x1v69jjYY.

Link: https://lore.kernel.org/llvm/202110100514.3h9CI4s0-lkp@intel.com/
Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 include/linux/compiler_types.h | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
index b6ff83a714ca..ca1a66b8cd2f 100644
--- a/include/linux/compiler_types.h
+++ b/include/linux/compiler_types.h
@@ -298,7 +298,13 @@ struct ftrace_likely_data {
 #ifdef __OPTIMIZE__
 # define __compiletime_assert(condition, msg, prefix, suffix)		\
 	do {								\
-		extern void prefix ## suffix(void) __compiletime_error(msg); \
+		/*							\
+		 * __noreturn is needed to give the compiler enough	\
+		 * information to avoid certain possibly-uninitialized	\
+		 * warnings (regardless of the build failing).		\
+		 */							\
+		__noreturn extern void prefix ## suffix(void)		\
+			__compiletime_error(msg);			\
 		if (!(condition))					\
 			prefix ## suffix();				\
 	} while (0)
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn
  2021-10-14 13:23 [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn Miguel Ojeda
@ 2021-10-14 15:01 ` Peter Zijlstra
  2021-10-14 17:48   ` Nick Desaulniers
  2021-10-14 17:26 ` Nathan Chancellor
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Peter Zijlstra @ 2021-10-14 15:01 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Nathan Chancellor, Nick Desaulniers, Kees Cook, linux-kernel, llvm

On Thu, Oct 14, 2021 at 03:23:31PM +0200, Miguel Ojeda wrote:
> `__compiletime_assert` declares a fake `extern` function
> which appears (to the compiler) to be called when the test fails.
> 
> Therefore, compilers may emit possibly-uninitialized warnings
> in some cases, even if it will be an error anyway (for compilers
> supporting the `error` attribute, e.g. GCC and Clang >= 14)
> or a link failure (for those that do not, e.g. Clang < 14).
> 
> Annotating the fake function as `__noreturn` gives them
> the information they need to avoid the warning,
> e.g. see https://godbolt.org/z/x1v69jjYY.
> 
> Link: https://lore.kernel.org/llvm/202110100514.3h9CI4s0-lkp@intel.com/
> Reported-by: kernel test robot <lkp@intel.com>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
> ---
>  include/linux/compiler_types.h | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
> index b6ff83a714ca..ca1a66b8cd2f 100644
> --- a/include/linux/compiler_types.h
> +++ b/include/linux/compiler_types.h
> @@ -298,7 +298,13 @@ struct ftrace_likely_data {
>  #ifdef __OPTIMIZE__
>  # define __compiletime_assert(condition, msg, prefix, suffix)		\
>  	do {								\
> -		extern void prefix ## suffix(void) __compiletime_error(msg); \
> +		/*							\
> +		 * __noreturn is needed to give the compiler enough	\
> +		 * information to avoid certain possibly-uninitialized	\
> +		 * warnings (regardless of the build failing).		\
> +		 */							\
> +		__noreturn extern void prefix ## suffix(void)		\
> +			__compiletime_error(msg);			\
>  		if (!(condition))					\
>  			prefix ## suffix();				\
>  	} while (0)

Should we not convert this to _Static_assert, now that all supported
compilers are of recent enough vintage to support that?

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn
  2021-10-14 13:23 [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn Miguel Ojeda
  2021-10-14 15:01 ` Peter Zijlstra
@ 2021-10-14 17:26 ` Nathan Chancellor
  2021-10-14 17:36 ` Nick Desaulniers
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 15+ messages in thread
From: Nathan Chancellor @ 2021-10-14 17:26 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Nick Desaulniers, Kees Cook, Peter Zijlstra, linux-kernel, llvm

On Thu, Oct 14, 2021 at 03:23:31PM +0200, Miguel Ojeda wrote:
> `__compiletime_assert` declares a fake `extern` function
> which appears (to the compiler) to be called when the test fails.
> 
> Therefore, compilers may emit possibly-uninitialized warnings
> in some cases, even if it will be an error anyway (for compilers
> supporting the `error` attribute, e.g. GCC and Clang >= 14)
> or a link failure (for those that do not, e.g. Clang < 14).
> 
> Annotating the fake function as `__noreturn` gives them
> the information they need to avoid the warning,
> e.g. see https://godbolt.org/z/x1v69jjYY.
> 
> Link: https://lore.kernel.org/llvm/202110100514.3h9CI4s0-lkp@intel.com/
> Reported-by: kernel test robot <lkp@intel.com>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

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

> ---
>  include/linux/compiler_types.h | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
> index b6ff83a714ca..ca1a66b8cd2f 100644
> --- a/include/linux/compiler_types.h
> +++ b/include/linux/compiler_types.h
> @@ -298,7 +298,13 @@ struct ftrace_likely_data {
>  #ifdef __OPTIMIZE__
>  # define __compiletime_assert(condition, msg, prefix, suffix)		\
>  	do {								\
> -		extern void prefix ## suffix(void) __compiletime_error(msg); \
> +		/*							\
> +		 * __noreturn is needed to give the compiler enough	\
> +		 * information to avoid certain possibly-uninitialized	\
> +		 * warnings (regardless of the build failing).		\
> +		 */							\
> +		__noreturn extern void prefix ## suffix(void)		\
> +			__compiletime_error(msg);			\
>  		if (!(condition))					\
>  			prefix ## suffix();				\
>  	} while (0)
> -- 
> 2.33.1
> 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn
  2021-10-14 13:23 [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn Miguel Ojeda
  2021-10-14 15:01 ` Peter Zijlstra
  2021-10-14 17:26 ` Nathan Chancellor
@ 2021-10-14 17:36 ` Nick Desaulniers
  2021-10-21 23:20 ` Miguel Ojeda
  2021-12-02  6:12 ` Dan Carpenter
  4 siblings, 0 replies; 15+ messages in thread
From: Nick Desaulniers @ 2021-10-14 17:36 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Nathan Chancellor, Kees Cook, Peter Zijlstra, linux-kernel, llvm,
	Marc Zyngier

On Thu, Oct 14, 2021 at 6:25 AM Miguel Ojeda <ojeda@kernel.org> wrote:
>
> `__compiletime_assert` declares a fake `extern` function
> which appears (to the compiler) to be called when the test fails.
>
> Therefore, compilers may emit possibly-uninitialized warnings
> in some cases, even if it will be an error anyway (for compilers
> supporting the `error` attribute, e.g. GCC and Clang >= 14)
> or a link failure (for those that do not, e.g. Clang < 14).
>
> Annotating the fake function as `__noreturn` gives them
> the information they need to avoid the warning,
> e.g. see https://godbolt.org/z/x1v69jjYY.

Thanks for the patch!
Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>

>
> Link: https://lore.kernel.org/llvm/202110100514.3h9CI4s0-lkp@intel.com/
> Reported-by: kernel test robot <lkp@intel.com>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
> ---
>  include/linux/compiler_types.h | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
> index b6ff83a714ca..ca1a66b8cd2f 100644
> --- a/include/linux/compiler_types.h
> +++ b/include/linux/compiler_types.h
> @@ -298,7 +298,13 @@ struct ftrace_likely_data {
>  #ifdef __OPTIMIZE__
>  # define __compiletime_assert(condition, msg, prefix, suffix)          \
>         do {                                                            \
> -               extern void prefix ## suffix(void) __compiletime_error(msg); \
> +               /*                                                      \
> +                * __noreturn is needed to give the compiler enough     \
> +                * information to avoid certain possibly-uninitialized  \
> +                * warnings (regardless of the build failing).          \
> +                */                                                     \
> +               __noreturn extern void prefix ## suffix(void)           \
> +                       __compiletime_error(msg);                       \
>                 if (!(condition))                                       \
>                         prefix ## suffix();                             \
>         } while (0)
> --
> 2.33.1
>
>


-- 
Thanks,
~Nick Desaulniers

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn
  2021-10-14 15:01 ` Peter Zijlstra
@ 2021-10-14 17:48   ` Nick Desaulniers
  2021-10-14 18:33     ` Miguel Ojeda
  2021-10-15  8:11     ` Rasmus Villemoes
  0 siblings, 2 replies; 15+ messages in thread
From: Nick Desaulniers @ 2021-10-14 17:48 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Miguel Ojeda, Nathan Chancellor, Kees Cook, linux-kernel, llvm,
	Rasmus Villemoes, Linus Torvalds

On Thu, Oct 14, 2021 at 8:02 AM Peter Zijlstra <peterz@infradead.org> wrote:
>
> On Thu, Oct 14, 2021 at 03:23:31PM +0200, Miguel Ojeda wrote:
> > `__compiletime_assert` declares a fake `extern` function
> > which appears (to the compiler) to be called when the test fails.
> >
> > Therefore, compilers may emit possibly-uninitialized warnings
> > in some cases, even if it will be an error anyway (for compilers
> > supporting the `error` attribute, e.g. GCC and Clang >= 14)
> > or a link failure (for those that do not, e.g. Clang < 14).
> >
> > Annotating the fake function as `__noreturn` gives them
> > the information they need to avoid the warning,
> > e.g. see https://godbolt.org/z/x1v69jjYY.
> >
> > Link: https://lore.kernel.org/llvm/202110100514.3h9CI4s0-lkp@intel.com/
> > Reported-by: kernel test robot <lkp@intel.com>
> > Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
> > ---
> >  include/linux/compiler_types.h | 8 +++++++-
> >  1 file changed, 7 insertions(+), 1 deletion(-)
> >
> > diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
> > index b6ff83a714ca..ca1a66b8cd2f 100644
> > --- a/include/linux/compiler_types.h
> > +++ b/include/linux/compiler_types.h
> > @@ -298,7 +298,13 @@ struct ftrace_likely_data {
> >  #ifdef __OPTIMIZE__
> >  # define __compiletime_assert(condition, msg, prefix, suffix)                \
> >       do {                                                            \
> > -             extern void prefix ## suffix(void) __compiletime_error(msg); \
> > +             /*                                                      \
> > +              * __noreturn is needed to give the compiler enough     \
> > +              * information to avoid certain possibly-uninitialized  \
> > +              * warnings (regardless of the build failing).          \
> > +              */                                                     \
> > +             __noreturn extern void prefix ## suffix(void)           \
> > +                     __compiletime_error(msg);                       \
> >               if (!(condition))                                       \
> >                       prefix ## suffix();                             \
> >       } while (0)
>
> Should we not convert this to _Static_assert, now that all supported
> compilers are of recent enough vintage to support that?

It's a good question; I'm pretty sure we had a thread with Rasmus on
the idea a while ago, and IIRC the answer is no.

Basically, we can't convert BUILD_BUG_ON to _Static_assert because
_Static_assert requires integer constant expressions (ICE) while many
expressions passed to BUILD_BUG_ON in the kernel require that
optimizations such as inlining run (they are not ICEs); BUILD_BUG_ON
is more flexible.  So you can't replace the guts of BUILD_BUG_ON
wholesale with _Static_assert (without doing anything else); it would
be preferable for kernel developers to use _Static_assert (I think we
have a macro, static_assert, too) in cases where they have ICEs rather
than BUILD_BUG_ON (though it flips the condition of the expression;
_Static_assert errors if the expression evaluates to false;
BUILD_BUG_ON when true), but I think there's too much muscle memory
around just using BUILD_BUG_ON that if you introduced something new,
folks wouldn't know to use that instead.

Probably a better demonstration would be to try it and observe some of
the spooky failures at build time that result.  We may be able to
separate the macro into two; BUILD_BUG_ON and BUILD_BUG_ON_OPT (or
whatever color bikeshed), where the former uses _Static_assert under
the hood, and the latter uses __attribute__((error)). Then we could go
about converting cases that could not use _Static_assert to use the
new macro, while the old macro is what folks still reach for first.

I'm not sure how worthwhile that yakshave would be, but at least the
front end of the compiler would error sooner in the case of
_Static_assert, FWIW (not much).  But I don't think we can ever
eliminate __attribute__((error)) from the kernel unless we're ok
outright removing asserts that aren't ICEs.  I would not recommend
that.  I would like to see more usage of static_assert, but I'm not
sure how best to promote that, and if it's worth discussing the subtle
distinction between BUILD_BUG_ON vs _Static_assert again and again and
again every time.
-- 
Thanks,
~Nick Desaulniers

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn
  2021-10-14 17:48   ` Nick Desaulniers
@ 2021-10-14 18:33     ` Miguel Ojeda
  2021-10-14 18:41       ` Miguel Ojeda
  2021-10-15  8:11     ` Rasmus Villemoes
  1 sibling, 1 reply; 15+ messages in thread
From: Miguel Ojeda @ 2021-10-14 18:33 UTC (permalink / raw)
  To: Nick Desaulniers
  Cc: Peter Zijlstra, Miguel Ojeda, Nathan Chancellor, Kees Cook,
	linux-kernel, llvm, Rasmus Villemoes, Linus Torvalds

On Thu, Oct 14, 2021 at 7:49 PM Nick Desaulniers
<ndesaulniers@google.com> wrote:
>
> It's a good question; I'm pretty sure we had a thread with Rasmus on
> the idea a while ago, and IIRC the answer is no.

Yeah, I remember that too.

> Basically, we can't convert BUILD_BUG_ON to _Static_assert because
> _Static_assert requires integer constant expressions (ICE) while many
> expressions passed to BUILD_BUG_ON in the kernel require that
> optimizations such as inlining run (they are not ICEs); BUILD_BUG_ON
> is more flexible.  So you can't replace the guts of BUILD_BUG_ON
> wholesale with _Static_assert (without doing anything else); it would
> be preferable for kernel developers to use _Static_assert (I think we
> have a macro, static_assert, too) in cases where they have ICEs rather
> than BUILD_BUG_ON (though it flips the condition of the expression;
> _Static_assert errors if the expression evaluates to false;
> BUILD_BUG_ON when true), but I think there's too much muscle memory
> around just using BUILD_BUG_ON that if you introduced something new,
> folks wouldn't know to use that instead.

Indeed, `BUILD_BUG_ON` requires the optimizer to see through whatever
you are trying to do. Way more powerful, but finicky too.

Another difference is that `_Static_assert` can be used in more places
(file scope, inside `struct`s...) for tests about e.g. sizes, i.e.
`BUILD_BUG_ON` is not a complete replacement either.

> Probably a better demonstration would be to try it and observe some of
> the spooky failures at build time that result.  We may be able to
> separate the macro into two; BUILD_BUG_ON and BUILD_BUG_ON_OPT (or
> whatever color bikeshed), where the former uses _Static_assert under
> the hood, and the latter uses __attribute__((error)). Then we could go
> about converting cases that could not use _Static_assert to use the
> new macro, while the old macro is what folks still reach for first.

That would be a nice to do, but I am not sure about introducing one
more macro about this... I think it would be simpler to submit patches
for moves into `static_assert` even if we have to "flip" the meaning.

> I'm not sure how worthwhile that yakshave would be, but at least the
> front end of the compiler would error sooner in the case of
> _Static_assert, FWIW (not much).  But I don't think we can ever
> eliminate __attribute__((error)) from the kernel unless we're ok
> outright removing asserts that aren't ICEs.  I would not recommend
> that.  I would like to see more usage of static_assert, but I'm not
> sure how best to promote that, and if it's worth discussing the subtle
> distinction between BUILD_BUG_ON vs _Static_assert again and again and
> again every time.

Perhaps we should add a comment in `BUILD_BUG*` about checking out
`static_assert` -- we have the comment in the latter, but those
reading the former will not realize the may be able to use the
latter...

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn
  2021-10-14 18:33     ` Miguel Ojeda
@ 2021-10-14 18:41       ` Miguel Ojeda
  2021-10-14 18:55         ` Nick Desaulniers
  0 siblings, 1 reply; 15+ messages in thread
From: Miguel Ojeda @ 2021-10-14 18:41 UTC (permalink / raw)
  To: Nick Desaulniers
  Cc: Peter Zijlstra, Miguel Ojeda, Nathan Chancellor, Kees Cook,
	linux-kernel, llvm, Rasmus Villemoes, Linus Torvalds

On Thu, Oct 14, 2021 at 8:33 PM Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
>
> That would be a nice to do, but I am not sure about introducing one
> more macro about this... I think it would be simpler to submit patches
> for moves into `static_assert` even if we have to "flip" the meaning.

Actually, what would be ideal is a compiler-backed lint that checks
whether it could be an `static_assert`, perhaps in clang-tidy?

It would also ensure things are kept clean.

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn
  2021-10-14 18:41       ` Miguel Ojeda
@ 2021-10-14 18:55         ` Nick Desaulniers
  2021-10-14 19:33           ` Miguel Ojeda
  2021-10-15  7:55           ` Rasmus Villemoes
  0 siblings, 2 replies; 15+ messages in thread
From: Nick Desaulniers @ 2021-10-14 18:55 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Peter Zijlstra, Miguel Ojeda, Nathan Chancellor, Kees Cook,
	linux-kernel, llvm, Rasmus Villemoes, Linus Torvalds,
	Joe Perches

On Thu, Oct 14, 2021 at 11:41 AM Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
>
> On Thu, Oct 14, 2021 at 8:33 PM Miguel Ojeda
> <miguel.ojeda.sandonis@gmail.com> wrote:
> >
> > That would be a nice to do, but I am not sure about introducing one
> > more macro about this... I think it would be simpler to submit patches
> > for moves into `static_assert` even if we have to "flip" the meaning.

$ grep -r BUILD_BUG_ON | wc -l
3405

> Actually, what would be ideal is a compiler-backed lint that checks
> whether it could be an `static_assert`, perhaps in clang-tidy?

Oh, that is a good idea.  There is one already for recommending the
use of static_assert instead of assert.  That's actually very nice.

I was playing with trying to adapt clang-tidy's C++11 `auto` fixit to
work on GNU C code to automate the replacement of:

__typeof(x) y = (x);

with:

__auto_type y = (x);

in macros.  That's perhaps interesting, too.  Given the volume of code
in the kernel, I wouldn't waste time with one off patches; rather I'd
work on automation (since clang-tidy can be taught "fixits" to fix the
code in place, not just warn) so that we can better enable treewide
changes AND keep new instances from sneaking back in easier.

Let's see if I get an intern in 2022, maybe I can have them focus on
clang-tidy+kernel.

>
> It would also ensure things are kept clean.
>
> Cheers,
> Miguel



-- 
Thanks,
~Nick Desaulniers

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn
  2021-10-14 18:55         ` Nick Desaulniers
@ 2021-10-14 19:33           ` Miguel Ojeda
  2021-10-15  7:55           ` Rasmus Villemoes
  1 sibling, 0 replies; 15+ messages in thread
From: Miguel Ojeda @ 2021-10-14 19:33 UTC (permalink / raw)
  To: Nick Desaulniers
  Cc: Peter Zijlstra, Miguel Ojeda, Nathan Chancellor, Kees Cook,
	linux-kernel, llvm, Rasmus Villemoes, Linus Torvalds,
	Joe Perches

On Thu, Oct 14, 2021 at 8:55 PM Nick Desaulniers
<ndesaulniers@google.com> wrote:
>
> $ grep -r BUILD_BUG_ON | wc -l
> 3405

Definitely -- I am assuming a significant part of the macro
invocations cannot be static asserts so that we would ended up with
churn anyway...

> Oh, that is a good idea.  There is one already for recommending the
> use of static_assert instead of assert.  That's actually very nice.

Happy to help!

> in the kernel, I wouldn't waste time with one off patches; rather I'd
> work on automation (since clang-tidy can be taught "fixits" to fix the
> code in place, not just warn) so that we can better enable treewide
> changes AND keep new instances from sneaking back in easier.

For automatic fixing we would need to be a bit smart due to the
negation w.r.t. "style", i.e. in most cases it should be easy to apply
it to the expression, e.g. from `!(x == 42)` to `x != 42`, but in
others it may require some "human touch".

There is also the possible mismatch of the usual style rules even if
we apply e.g. `clang-format` after it (one more reason to avoid human
formatting...).

But yeah, I think we should be able to cover the vast majority of them
easily. We can always send them as RFC patches and let folks adapt the
patch, then enable the warning/error by default after one release or
two.

> Let's see if I get an intern in 2022, maybe I can have them focus on
> clang-tidy+kernel.

It would be great to have someone adding more `linuxkernel-` checks!

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn
  2021-10-14 18:55         ` Nick Desaulniers
  2021-10-14 19:33           ` Miguel Ojeda
@ 2021-10-15  7:55           ` Rasmus Villemoes
  1 sibling, 0 replies; 15+ messages in thread
From: Rasmus Villemoes @ 2021-10-15  7:55 UTC (permalink / raw)
  To: Nick Desaulniers, Miguel Ojeda
  Cc: Peter Zijlstra, Miguel Ojeda, Nathan Chancellor, Kees Cook,
	linux-kernel, llvm, Linus Torvalds, Joe Perches

On 14/10/2021 20.55, Nick Desaulniers wrote:
> On Thu, Oct 14, 2021 at 11:41 AM Miguel Ojeda
> <miguel.ojeda.sandonis@gmail.com> wrote:
>>
>> On Thu, Oct 14, 2021 at 8:33 PM Miguel Ojeda
>> <miguel.ojeda.sandonis@gmail.com> wrote:
>>>
>>> That would be a nice to do, but I am not sure about introducing one
>>> more macro about this... I think it would be simpler to submit patches
>>> for moves into `static_assert` even if we have to "flip" the meaning.
> 
> $ grep -r BUILD_BUG_ON | wc -l
> 3405
> 
>> Actually, what would be ideal is a compiler-backed lint that checks
>> whether it could be an `static_assert`, perhaps in clang-tidy?
> 
> Oh, that is a good idea.  There is one already for recommending the
> use of static_assert instead of assert.  That's actually very nice.

So I did

diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
index b6ff83a714ca..e212220216e8 100644
--- a/include/linux/compiler_types.h
+++ b/include/linux/compiler_types.h
@@ -295,12 +295,17 @@ struct ftrace_likely_data {
 # define __compiletime_object_size(obj) -1
 #endif

+#include <linux/const.h>
+
 #ifdef __OPTIMIZE__
 # define __compiletime_assert(condition, msg, prefix, suffix)          \
        do {                                                            \
                extern void prefix ## suffix(void)
__compiletime_error(msg); \
+               extern void prefix ## suffix ## ice(void)
__compiletime_warning("Ice ice baby"); \
                if (!(condition))                                       \
                        prefix ## suffix();                             \
+               if (__is_constexpr(condition))                          \
+                       prefix ## suffix ## ice();                      \
        } while (0)
 #else
 # define __compiletime_assert(condition, msg, prefix, suffix) do { }
while (0)

and that throws a gazillion warnings. Picking one at random shows that
container_of() has a BUILD_BUG_ON. So we could do

diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 2776423a587e..0a1969b11619 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -492,9 +492,9 @@ static inline void ftrace_dump(enum ftrace_dump_mode
oops_dump_mode) { }
  */
 #define container_of(ptr, type, member) ({                             \
        void *__mptr = (void *)(ptr);                                   \
-       BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) &&   \
-                        !__same_type(*(ptr), void),                    \
-                        "pointer type mismatch in container_of()");    \
+       static_assert(__same_type(*(ptr), ((type *)0)->member) ||       \
+                     __same_type(*(ptr), void),                        \
+                     "pointer type mismatch in container_of()");       \
        ((type *)(__mptr - offsetof(type, member))); })

 /**
@@ -507,9 +507,9 @@ static inline void ftrace_dump(enum ftrace_dump_mode
oops_dump_mode) { }
  */
 #define container_of_safe(ptr, type, member) ({
        \
        void *__mptr = (void *)(ptr);                                   \
-       BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) &&   \
-                        !__same_type(*(ptr), void),                    \
-                        "pointer type mismatch in container_of()");    \
+       static_assert(__same_type(*(ptr), ((type *)0)->member) ||       \
+                     __same_type(*(ptr), void),                        \
+                     "pointer type mismatch in container_of_safe()");  \
        IS_ERR_OR_NULL(__mptr) ? ERR_CAST(__mptr) :                     \
                ((type *)(__mptr - offsetof(type, member))); })

[fixing the copy-pasto in container_of_safe while at it].

Basically, all BUILD_BUG_ONs like that that do type checking are very
obviously candidates for using static_assert instead (they very
naturally go at the end of all the locally declared variables, so one
won't hit the declaration-after-statement problem that can otherwise
prevent using static_assert).

> I was playing with trying to adapt clang-tidy's C++11 `auto` fixit to
> work on GNU C code to automate the replacement of:
> 
> __typeof(x) y = (x);
> 
> with:
> 
> __auto_type y = (x);
> 
> in macros.  That's perhaps interesting, too.  Given the volume of code
> in the kernel, I wouldn't waste time with one off patches;

Well, for the kind of macros that are used _everywhere_ a few one-off
patches might be in order. It's also interesting if one could measure
any speedup from switching those core macros to static_assert.

Rasmus

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn
  2021-10-14 17:48   ` Nick Desaulniers
  2021-10-14 18:33     ` Miguel Ojeda
@ 2021-10-15  8:11     ` Rasmus Villemoes
  2021-10-15 12:36       ` Miguel Ojeda
  1 sibling, 1 reply; 15+ messages in thread
From: Rasmus Villemoes @ 2021-10-15  8:11 UTC (permalink / raw)
  To: Nick Desaulniers, Peter Zijlstra
  Cc: Miguel Ojeda, Nathan Chancellor, Kees Cook, linux-kernel, llvm,
	Linus Torvalds

On 14/10/2021 19.48, Nick Desaulniers wrote:
> On Thu, Oct 14, 2021 at 8:02 AM Peter Zijlstra <peterz@infradead.org> wrote:
>>

> I'm not sure how worthwhile that yakshave would be, 

A yakshave that would be worthwhile is to kill off the macro
compiletime_assert() completely - three is a crowd. It sounds like it
would be implemented in terms of _Static_assert, but it's actually
__attribute__(error). We can fold the definition of compiletime_assert
into BUILD_BUG_ON_MSG.

The users in rwonce.h should just be changed to static_assert, and then
there are very few random users left, which can either be static_assert
or BUILD_BUG_ON_MSG.

Why do we even have a no-op version if !__OPTIMIZE__? AFAIK there's no
CONFIG_O0 option, and such a build wouldn't be interesting at all - it
can't be expected to boot, and it would likely throw warnings left and
right.

Rasmus

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn
  2021-10-15  8:11     ` Rasmus Villemoes
@ 2021-10-15 12:36       ` Miguel Ojeda
  0 siblings, 0 replies; 15+ messages in thread
From: Miguel Ojeda @ 2021-10-15 12:36 UTC (permalink / raw)
  To: Rasmus Villemoes
  Cc: Nick Desaulniers, Peter Zijlstra, Miguel Ojeda,
	Nathan Chancellor, Kees Cook, linux-kernel, llvm, Linus Torvalds

On Fri, Oct 15, 2021 at 10:11 AM Rasmus Villemoes
<linux@rasmusvillemoes.dk> wrote:
>
> A yakshave that would be worthwhile is to kill off the macro
> compiletime_assert() completely - three is a crowd. It sounds like it
> would be implemented in terms of _Static_assert, but it's actually
> __attribute__(error). We can fold the definition of compiletime_assert
> into BUILD_BUG_ON_MSG.

Agreed, two should be enough.

> Why do we even have a no-op version if !__OPTIMIZE__? AFAIK there's no
> CONFIG_O0 option, and such a build wouldn't be interesting at all - it
> can't be expected to boot, and it would likely throw warnings left and
> right.

Yeah, I don't think it would compile as it is anyway.

Perhaps it is there for some kind of tooling? For a static analyzer or
something like sparse (if it didn't have its own define)...

But yeah, every use of it should have a comment explaining why it is
there, like crypto/jitterentropy.c does. There are a couple without
it.

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn
  2021-10-14 13:23 [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn Miguel Ojeda
                   ` (2 preceding siblings ...)
  2021-10-14 17:36 ` Nick Desaulniers
@ 2021-10-21 23:20 ` Miguel Ojeda
  2021-12-02  6:12 ` Dan Carpenter
  4 siblings, 0 replies; 15+ messages in thread
From: Miguel Ojeda @ 2021-10-21 23:20 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Nathan Chancellor, Nick Desaulniers, Kees Cook, Peter Zijlstra,
	linux-kernel, llvm

On Thu, Oct 14, 2021 at 3:25 PM Miguel Ojeda <ojeda@kernel.org> wrote:
>
> `__compiletime_assert` declares a fake `extern` function
> which appears (to the compiler) to be called when the test fails.

Queuing this one through my tree.

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn
  2021-10-14 13:23 [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn Miguel Ojeda
                   ` (3 preceding siblings ...)
  2021-10-21 23:20 ` Miguel Ojeda
@ 2021-12-02  6:12 ` Dan Carpenter
  2021-12-02  6:24   ` Dan Carpenter
  4 siblings, 1 reply; 15+ messages in thread
From: Dan Carpenter @ 2021-12-02  6:12 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Nathan Chancellor, Nick Desaulniers, Kees Cook, Peter Zijlstra,
	linux-kernel, llvm

On Thu, Oct 14, 2021 at 03:23:31PM +0200, Miguel Ojeda wrote:
> `__compiletime_assert` declares a fake `extern` function
> which appears (to the compiler) to be called when the test fails.
> 
> Therefore, compilers may emit possibly-uninitialized warnings
> in some cases, even if it will be an error anyway (for compilers
> supporting the `error` attribute, e.g. GCC and Clang >= 14)
> or a link failure (for those that do not, e.g. Clang < 14).
> 
> Annotating the fake function as `__noreturn` gives them
> the information they need to avoid the warning,
> e.g. see https://godbolt.org/z/x1v69jjYY.
> 
> Link: https://lore.kernel.org/llvm/202110100514.3h9CI4s0-lkp@intel.com/
> Reported-by: kernel test robot <lkp@intel.com>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

This patch is kind of a headache for Smatch.

The patch basically turns BUILD_BUG() into BUG().  That's fine.

But it also turn BUILD_BUG_ON(!__builtin_constant_p(foo) into a BUG_ON().
A lot of places call BUILD_BUG_ON() to ensure that functions are inlined
and the build breaks if not.  For example, the FIELD_GET() macro will
trigger a build bug if "mask" is not a compile time constant.

   295  static __always_inline u32 cal_read_field(struct cal_dev *cal, u32 offset, u32 mask)
   296  {
   297          return FIELD_GET(mask, cal_read(cal, offset));
   298  }

Unfortunately, Smatch doesn't respect the __always_inline annotation so
now it thinks cal_read_field calls BUG() and records it as a noreturn
function.  And all the callers get marked as noreturn functions as well.

Could we make it so that BUILD_BUG() is a noreturn function and
BUILD_BUG_ON() is left as it was?

regards,
dan carpenter


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn
  2021-12-02  6:12 ` Dan Carpenter
@ 2021-12-02  6:24   ` Dan Carpenter
  0 siblings, 0 replies; 15+ messages in thread
From: Dan Carpenter @ 2021-12-02  6:24 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Nathan Chancellor, Nick Desaulniers, Kees Cook, Peter Zijlstra,
	linux-kernel, llvm

Never mind.  I can just add some code to Smatch to ignore compile time
asserts.

regards,
dan carpenter


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2021-12-02  6:27 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-14 13:23 [PATCH] compiler_types: mark __compiletime_assert failure as __noreturn Miguel Ojeda
2021-10-14 15:01 ` Peter Zijlstra
2021-10-14 17:48   ` Nick Desaulniers
2021-10-14 18:33     ` Miguel Ojeda
2021-10-14 18:41       ` Miguel Ojeda
2021-10-14 18:55         ` Nick Desaulniers
2021-10-14 19:33           ` Miguel Ojeda
2021-10-15  7:55           ` Rasmus Villemoes
2021-10-15  8:11     ` Rasmus Villemoes
2021-10-15 12:36       ` Miguel Ojeda
2021-10-14 17:26 ` Nathan Chancellor
2021-10-14 17:36 ` Nick Desaulniers
2021-10-21 23:20 ` Miguel Ojeda
2021-12-02  6:12 ` Dan Carpenter
2021-12-02  6:24   ` Dan Carpenter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).