diff mbox

BUILD_BUG_ON: make it handle more cases

Message ID 200910201415.34361.rusty@rustcorp.com.au (mailing list archive)
State Not Applicable
Headers show

Commit Message

Rusty Russell Oct. 20, 2009, 3:45 a.m. UTC
BUILD_BUG_ON used to use the optimizer to do code elimination or fail
at link time; it was changed to first the size of a negative array (a
nicer compile time error), then (in
8c87df457cb58fe75b9b893007917cf8095660a0) to a bitfield.

bitfields: needs a literal constant at parse time, and can't be put under
	"if (__builtin_constant_p(x))" for example.
negative array: can handle anything, but if the compiler can't tell it's
	a constant, silently has no effect.
link time: breaks link if the compiler can't determine the value, but the
	linker output is not usually as informative as a compiler error.

If we use the negative-array-size method *and* the link time trick,
we get the ability to use BUILD_BUG_ON() under __builtin_constant_p()
branches, and maximal ability for the compiler to detect errors at
build time.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>

Comments

Cong Wang Oct. 20, 2009, 1:58 p.m. UTC | #1
On Tue, Oct 20, 2009 at 02:15:33PM +1030, Rusty Russell wrote:
>BUILD_BUG_ON used to use the optimizer to do code elimination or fail
>at link time; it was changed to first the size of a negative array (a
>nicer compile time error), then (in
>8c87df457cb58fe75b9b893007917cf8095660a0) to a bitfield.
>
>bitfields: needs a literal constant at parse time, and can't be put under
>	"if (__builtin_constant_p(x))" for example.
>negative array: can handle anything, but if the compiler can't tell it's
>	a constant, silently has no effect.
>link time: breaks link if the compiler can't determine the value, but the
>	linker output is not usually as informative as a compiler error.
>
>If we use the negative-array-size method *and* the link time trick,
>we get the ability to use BUILD_BUG_ON() under __builtin_constant_p()
>branches, and maximal ability for the compiler to detect errors at
>build time.
>
>Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
>
>diff --git a/include/linux/kernel.h b/include/linux/kernel.h
>--- a/include/linux/kernel.h
>+++ b/include/linux/kernel.h
>@@ -683,12 +683,6 @@ struct sysinfo {
> 	char _f[20-2*sizeof(long)-sizeof(int)];	/* Padding: libc5 uses this.. */
> };
> 
>-/* Force a compilation error if condition is true */
>-#define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition))
>-
>-/* Force a compilation error if condition is constant and true */
>-#define MAYBE_BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2 * !!(cond)]))
>-
> /* Force a compilation error if condition is true, but also produce a
>    result (of value 0 and type size_t), so the expression can be used
>    e.g. in a structure initializer (or where-ever else comma expressions
>@@ -696,6 +690,33 @@ struct sysinfo {
> #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
> #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
> 
>+/**
>+ * BUILD_BUG_ON - break compile if a condition is true.
>+ * @cond: the condition which the compiler should know is false.
>+ *
>+ * If you have some code which relies on certain constants being equal, or
>+ * other compile-time-evaluated condition, you should use BUILD_BUG_ON to
>+ * detect if someone changes it.
>+ *
>+ * The implementation uses gcc's reluctance to create a negative array, but
>+ * gcc (as of 4.4) only emits that error for obvious cases (eg. not arguments
>+ * to inline functions).  So as a fallback we use the optimizer; if it can't
>+ * prove the condition is false, it will cause a link error on the undefined
>+ * "__build_bug_on_failed".  This error message can be harder to track down
>+ * though, hence the two different methods.
>+ */
>+#ifndef __OPTIMIZE__
>+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
>+#else
>+extern int __build_bug_on_failed;

Hmm, what exactly is __build_bug_on_failed?

>+#define BUILD_BUG_ON(condition)					\
>+	do {							\
>+		((void)sizeof(char[1 - 2*!!(condition)]));	\
>+		if (condition) __build_bug_on_failed = 1;	\
>+	} while(0)
>+#endif
>+#define MAYBE_BUILD_BUG_ON(condition) BUILD_BUG_ON(condition)
>+
> /* Trap pasters of __FUNCTION__ at compile-time */
> #define __FUNCTION__ (__func__)
> 
>--
>To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html
>Please read the FAQ at  http://www.tux.org/lkml/
Alan Jenkins Oct. 20, 2009, 2:43 p.m. UTC | #2
On 10/20/09, Américo Wang <xiyou.wangcong@gmail.com> wrote:
> On Tue, Oct 20, 2009 at 02:15:33PM +1030, Rusty Russell wrote:
>>BUILD_BUG_ON used to use the optimizer to do code elimination or fail
>>at link time; it was changed to first the size of a negative array (a
>>nicer compile time error), then (in
>>8c87df457cb58fe75b9b893007917cf8095660a0) to a bitfield.
>>
>>bitfields: needs a literal constant at parse time, and can't be put under
>>	"if (__builtin_constant_p(x))" for example.
>>negative array: can handle anything, but if the compiler can't tell it's
>>	a constant, silently has no effect.
>>link time: breaks link if the compiler can't determine the value, but the
>>	linker output is not usually as informative as a compiler error.
>>
>>If we use the negative-array-size method *and* the link time trick,
>>we get the ability to use BUILD_BUG_ON() under __builtin_constant_p()
>>branches, and maximal ability for the compiler to detect errors at
>>build time.
>>
>>Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
>>
>>diff --git a/include/linux/kernel.h b/include/linux/kernel.h
>>--- a/include/linux/kernel.h
>>+++ b/include/linux/kernel.h
>>@@ -683,12 +683,6 @@ struct sysinfo {
>> 	char _f[20-2*sizeof(long)-sizeof(int)];	/* Padding: libc5 uses this.. */
>> };
>>
>>-/* Force a compilation error if condition is true */
>>-#define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition))
>>-
>>-/* Force a compilation error if condition is constant and true */
>>-#define MAYBE_BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2 * !!(cond)]))
>>-
>> /* Force a compilation error if condition is true, but also produce a
>>    result (of value 0 and type size_t), so the expression can be used
>>    e.g. in a structure initializer (or where-ever else comma expressions
>>@@ -696,6 +690,33 @@ struct sysinfo {
>> #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
>> #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
>>
>>+/**
>>+ * BUILD_BUG_ON - break compile if a condition is true.
>>+ * @cond: the condition which the compiler should know is false.
>>+ *
>>+ * If you have some code which relies on certain constants being equal, or
>>+ * other compile-time-evaluated condition, you should use BUILD_BUG_ON to
>>+ * detect if someone changes it.
>>+ *
>>+ * The implementation uses gcc's reluctance to create a negative array,
>> but
>>+ * gcc (as of 4.4) only emits that error for obvious cases (eg. not
>> arguments
>>+ * to inline functions).  So as a fallback we use the optimizer; if it
>> can't
>>+ * prove the condition is false, it will cause a link error on the
>> undefined
>>+ * "__build_bug_on_failed".  This error message can be harder to track
>> down
>>+ * though, hence the two different methods.
>>+ */
>>+#ifndef __OPTIMIZE__
>>+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
>>+#else
>>+extern int __build_bug_on_failed;
>
> Hmm, what exactly is __build_bug_on_failed?

Well, we haven't added a definition for it in this patch.  I'm sure
grep will tell you it wasn't defined before hand either.  So any
reference to it is an error - which will be reported at link time.

>>+#define BUILD_BUG_ON(condition)					\
>>+	do {							\
>>+		((void)sizeof(char[1 - 2*!!(condition)]));	\
>>+		if (condition) __build_bug_on_failed = 1;	\

If "condition" is known false at compile time, gcc -O will eliminate
the code which refers to __build_bug_on_failed.  If it's not proved to
be false - it will break the build, which is exactly what we want
BUILD_BUG_ON to do.

>>+	} while(0)
>>+#endif
>>+#define MAYBE_BUILD_BUG_ON(condition) BUILD_BUG_ON(condition)
>>+
>> /* Trap pasters of __FUNCTION__ at compile-time */
>> #define __FUNCTION__ (__func__)
>>
Hollis Blanchard Oct. 22, 2009, 9:04 p.m. UTC | #3
On Tue, 2009-10-20 at 14:15 +1030, Rusty Russell wrote:
> BUILD_BUG_ON used to use the optimizer to do code elimination or fail
> at link time; it was changed to first the size of a negative array (a
> nicer compile time error), then (in
> 8c87df457cb58fe75b9b893007917cf8095660a0) to a bitfield.
> 
> bitfields: needs a literal constant at parse time, and can't be put under
> 	"if (__builtin_constant_p(x))" for example.
> negative array: can handle anything, but if the compiler can't tell it's
> 	a constant, silently has no effect.
> link time: breaks link if the compiler can't determine the value, but the
> 	linker output is not usually as informative as a compiler error.
> 
> If we use the negative-array-size method *and* the link time trick,
> we get the ability to use BUILD_BUG_ON() under __builtin_constant_p()
> branches, and maximal ability for the compiler to detect errors at
> build time.
> 
> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>

Thanks Rusty, this indeed fixes the problem.

Acked-by: Hollis Blanchard <hollisb@us.ibm.com>
Cong Wang Oct. 23, 2009, 1:50 a.m. UTC | #4
On Tue, Oct 20, 2009 at 10:43 PM, Alan Jenkins
<sourcejedi.lkml@googlemail.com> wrote:
> On 10/20/09, Américo Wang <xiyou.wangcong@gmail.com> wrote:
>> On Tue, Oct 20, 2009 at 02:15:33PM +1030, Rusty Russell wrote:
>>>BUILD_BUG_ON used to use the optimizer to do code elimination or fail
>>>at link time; it was changed to first the size of a negative array (a
>>>nicer compile time error), then (in
>>>8c87df457cb58fe75b9b893007917cf8095660a0) to a bitfield.
>>>
>>>bitfields: needs a literal constant at parse time, and can't be put under
>>>      "if (__builtin_constant_p(x))" for example.
>>>negative array: can handle anything, but if the compiler can't tell it's
>>>      a constant, silently has no effect.
>>>link time: breaks link if the compiler can't determine the value, but the
>>>      linker output is not usually as informative as a compiler error.
>>>
>>>If we use the negative-array-size method *and* the link time trick,
>>>we get the ability to use BUILD_BUG_ON() under __builtin_constant_p()
>>>branches, and maximal ability for the compiler to detect errors at
>>>build time.
>>>
>>>Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
>>>
>>>diff --git a/include/linux/kernel.h b/include/linux/kernel.h
>>>--- a/include/linux/kernel.h
>>>+++ b/include/linux/kernel.h
>>>@@ -683,12 +683,6 @@ struct sysinfo {
>>>      char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
>>> };
>>>
>>>-/* Force a compilation error if condition is true */
>>>-#define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition))
>>>-
>>>-/* Force a compilation error if condition is constant and true */
>>>-#define MAYBE_BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2 * !!(cond)]))
>>>-
>>> /* Force a compilation error if condition is true, but also produce a
>>>    result (of value 0 and type size_t), so the expression can be used
>>>    e.g. in a structure initializer (or where-ever else comma expressions
>>>@@ -696,6 +690,33 @@ struct sysinfo {
>>> #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
>>> #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
>>>
>>>+/**
>>>+ * BUILD_BUG_ON - break compile if a condition is true.
>>>+ * @cond: the condition which the compiler should know is false.
>>>+ *
>>>+ * If you have some code which relies on certain constants being equal, or
>>>+ * other compile-time-evaluated condition, you should use BUILD_BUG_ON to
>>>+ * detect if someone changes it.
>>>+ *
>>>+ * The implementation uses gcc's reluctance to create a negative array,
>>> but
>>>+ * gcc (as of 4.4) only emits that error for obvious cases (eg. not
>>> arguments
>>>+ * to inline functions).  So as a fallback we use the optimizer; if it
>>> can't
>>>+ * prove the condition is false, it will cause a link error on the
>>> undefined
>>>+ * "__build_bug_on_failed".  This error message can be harder to track
>>> down
>>>+ * though, hence the two different methods.
>>>+ */
>>>+#ifndef __OPTIMIZE__
>>>+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
>>>+#else
>>>+extern int __build_bug_on_failed;
>>
>> Hmm, what exactly is __build_bug_on_failed?
>
> Well, we haven't added a definition for it in this patch.  I'm sure
> grep will tell you it wasn't defined before hand either.  So any
> reference to it is an error - which will be reported at link time.
>
>>>+#define BUILD_BUG_ON(condition)                                      \
>>>+     do {                                                    \
>>>+             ((void)sizeof(char[1 - 2*!!(condition)]));      \
>>>+             if (condition) __build_bug_on_failed = 1;       \
>
> If "condition" is known false at compile time, gcc -O will eliminate
> the code which refers to __build_bug_on_failed.  If it's not proved to
> be false - it will break the build, which is exactly what we want
> BUILD_BUG_ON to do.

Ah, clever trick! Got it.
Thanks!

Reviewed-by: WANG Cong <xiyou.wangcong@gmail.com>
Hollis Blanchard Oct. 29, 2009, 9:30 p.m. UTC | #5
On Tue, 2009-10-20 at 14:15 +1030, Rusty Russell wrote:
> BUILD_BUG_ON used to use the optimizer to do code elimination or fail
> at link time; it was changed to first the size of a negative array (a
> nicer compile time error), then (in
> 8c87df457cb58fe75b9b893007917cf8095660a0) to a bitfield.
> 
> bitfields: needs a literal constant at parse time, and can't be put under
> 	"if (__builtin_constant_p(x))" for example.
> negative array: can handle anything, but if the compiler can't tell it's
> 	a constant, silently has no effect.
> link time: breaks link if the compiler can't determine the value, but the
> 	linker output is not usually as informative as a compiler error.
> 
> If we use the negative-array-size method *and* the link time trick,
> we get the ability to use BUILD_BUG_ON() under __builtin_constant_p()
> branches, and maximal ability for the compiler to detect errors at
> build time.
> 
> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
> 
> diff --git a/include/linux/kernel.h b/include/linux/kernel.h
> --- a/include/linux/kernel.h
> +++ b/include/linux/kernel.h
> @@ -683,12 +683,6 @@ struct sysinfo {
>  	char _f[20-2*sizeof(long)-sizeof(int)];	/* Padding: libc5 uses this.. */
>  };
> 
> -/* Force a compilation error if condition is true */
> -#define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition))
> -
> -/* Force a compilation error if condition is constant and true */
> -#define MAYBE_BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2 * !!(cond)]))
> -
>  /* Force a compilation error if condition is true, but also produce a
>     result (of value 0 and type size_t), so the expression can be used
>     e.g. in a structure initializer (or where-ever else comma expressions
> @@ -696,6 +690,33 @@ struct sysinfo {
>  #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
>  #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
> 
> +/**
> + * BUILD_BUG_ON - break compile if a condition is true.
> + * @cond: the condition which the compiler should know is false.
> + *
> + * If you have some code which relies on certain constants being equal, or
> + * other compile-time-evaluated condition, you should use BUILD_BUG_ON to
> + * detect if someone changes it.
> + *
> + * The implementation uses gcc's reluctance to create a negative array, but
> + * gcc (as of 4.4) only emits that error for obvious cases (eg. not arguments
> + * to inline functions).  So as a fallback we use the optimizer; if it can't
> + * prove the condition is false, it will cause a link error on the undefined
> + * "__build_bug_on_failed".  This error message can be harder to track down
> + * though, hence the two different methods.
> + */
> +#ifndef __OPTIMIZE__
> +#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
> +#else
> +extern int __build_bug_on_failed;
> +#define BUILD_BUG_ON(condition)					\
> +	do {							\
> +		((void)sizeof(char[1 - 2*!!(condition)]));	\
> +		if (condition) __build_bug_on_failed = 1;	\
> +	} while(0)
> +#endif
> +#define MAYBE_BUILD_BUG_ON(condition) BUILD_BUG_ON(condition)
> +
>  /* Trap pasters of __FUNCTION__ at compile-time */
>  #define __FUNCTION__ (__func__)

What's the state of this patch?
Stephen Rothwell Nov. 5, 2009, 12:20 a.m. UTC | #6
Hi Rusty,

On Tue, 20 Oct 2009 14:15:33 +1030 Rusty Russell <rusty@rustcorp.com.au> wrote:
>
> +#ifndef __OPTIMIZE__
> +#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
> +#else
> +extern int __build_bug_on_failed;
> +#define BUILD_BUG_ON(condition)					\
> +	do {							\
> +		((void)sizeof(char[1 - 2*!!(condition)]));	\
> +		if (condition) __build_bug_on_failed = 1;	\
> +	} while(0)
> +#endif
> +#define MAYBE_BUILD_BUG_ON(condition) BUILD_BUG_ON(condition)
> +

I decided to try this in linux-next, but an x86_64 allmodconfig build
gave this (gcc 4.4.0):

ERROR: "__build_bug_on_failed" [drivers/net/virtio_net.ko] undefined!
ERROR: "__build_bug_on_failed" [drivers/block/virtio_blk.ko] undefined!

I assume that this is caused by the "MAYBE_BUILD_BUG_ON(fbit >= 32)" in
virtio_has_feature() (in include/linux/virtio_config.h) which is called
all over the place.  Unfortunately, virtio_has_feature() gets uninlined
in those two files ...

I have taken the patch back out again for today.
Benjamin Herrenschmidt Nov. 5, 2009, 6:01 a.m. UTC | #7
On Tue, 2009-10-20 at 14:15 +1030, Rusty Russell wrote:
> BUILD_BUG_ON used to use the optimizer to do code elimination or fail
> at link time; it was changed to first the size of a negative array (a
> nicer compile time error), then (in
> 8c87df457cb58fe75b9b893007917cf8095660a0) to a bitfield.

What's the status with this patch ? The lack of it breaks my KVM stuff
in powerpc...

Cheers,
Ben.

> bitfields: needs a literal constant at parse time, and can't be put under
> 	"if (__builtin_constant_p(x))" for example.
> negative array: can handle anything, but if the compiler can't tell it's
> 	a constant, silently has no effect.
> link time: breaks link if the compiler can't determine the value, but the
> 	linker output is not usually as informative as a compiler error.
> 
> If we use the negative-array-size method *and* the link time trick,
> we get the ability to use BUILD_BUG_ON() under __builtin_constant_p()
> branches, and maximal ability for the compiler to detect errors at
> build time.
> 
> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
> 
> diff --git a/include/linux/kernel.h b/include/linux/kernel.h
> --- a/include/linux/kernel.h
> +++ b/include/linux/kernel.h
> @@ -683,12 +683,6 @@ struct sysinfo {
>  	char _f[20-2*sizeof(long)-sizeof(int)];	/* Padding: libc5 uses this.. */
>  };
>  
> -/* Force a compilation error if condition is true */
> -#define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition))
> -
> -/* Force a compilation error if condition is constant and true */
> -#define MAYBE_BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2 * !!(cond)]))
> -
>  /* Force a compilation error if condition is true, but also produce a
>     result (of value 0 and type size_t), so the expression can be used
>     e.g. in a structure initializer (or where-ever else comma expressions
> @@ -696,6 +690,33 @@ struct sysinfo {
>  #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
>  #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
>  
> +/**
> + * BUILD_BUG_ON - break compile if a condition is true.
> + * @cond: the condition which the compiler should know is false.
> + *
> + * If you have some code which relies on certain constants being equal, or
> + * other compile-time-evaluated condition, you should use BUILD_BUG_ON to
> + * detect if someone changes it.
> + *
> + * The implementation uses gcc's reluctance to create a negative array, but
> + * gcc (as of 4.4) only emits that error for obvious cases (eg. not arguments
> + * to inline functions).  So as a fallback we use the optimizer; if it can't
> + * prove the condition is false, it will cause a link error on the undefined
> + * "__build_bug_on_failed".  This error message can be harder to track down
> + * though, hence the two different methods.
> + */
> +#ifndef __OPTIMIZE__
> +#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
> +#else
> +extern int __build_bug_on_failed;
> +#define BUILD_BUG_ON(condition)					\
> +	do {							\
> +		((void)sizeof(char[1 - 2*!!(condition)]));	\
> +		if (condition) __build_bug_on_failed = 1;	\
> +	} while(0)
> +#endif
> +#define MAYBE_BUILD_BUG_ON(condition) BUILD_BUG_ON(condition)
> +
>  /* Trap pasters of __FUNCTION__ at compile-time */
>  #define __FUNCTION__ (__func__)
>  
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
Rusty Russell Nov. 5, 2009, 6:28 a.m. UTC | #8
On Thu, 5 Nov 2009 10:50:20 am Stephen Rothwell wrote:
> Hi Rusty,
> 
> On Tue, 20 Oct 2009 14:15:33 +1030 Rusty Russell <rusty@rustcorp.com.au> wrote:
> >
> > +#ifndef __OPTIMIZE__
> > +#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
> > +#else
> > +extern int __build_bug_on_failed;
> > +#define BUILD_BUG_ON(condition)					\
> > +	do {							\
> > +		((void)sizeof(char[1 - 2*!!(condition)]));	\
> > +		if (condition) __build_bug_on_failed = 1;	\
> > +	} while(0)
> > +#endif
> > +#define MAYBE_BUILD_BUG_ON(condition) BUILD_BUG_ON(condition)
> > +
> 
> I decided to try this in linux-next, but an x86_64 allmodconfig build
> gave this (gcc 4.4.0):
> 
> ERROR: "__build_bug_on_failed" [drivers/net/virtio_net.ko] undefined!
> ERROR: "__build_bug_on_failed" [drivers/block/virtio_blk.ko] undefined!
> 
> I assume that this is caused by the "MAYBE_BUILD_BUG_ON(fbit >= 32)" in
> virtio_has_feature() (in include/linux/virtio_config.h) which is called
> all over the place.  Unfortunately, virtio_has_feature() gets uninlined
> in those two files ...

Huh?  virtio_has_feature does:

	if (__builtin_constant_p(fbit))
		BUILD_BUG_ON(fbit >= 32);
	else
		BUG_ON(fbit >= 32);

So, if it's not a constant, gcc should throw away that first branch.  If it
is, it should optimize it away (and no, these are not real bugs AFAICT).

I did a 4.3.3 allmodconfig with this patch on 64-bit a few days back and all
was fine.  Will try 4.4.0 now.

Thanks,
Rusty.
Rusty Russell Nov. 5, 2009, 6:37 a.m. UTC | #9
On Thu, 5 Nov 2009 04:58:36 pm Rusty Russell wrote:
> I did a 4.3.3 allmodconfig with this patch on 64-bit a few days back and all
> was fine.  Will try 4.4.0 now.

4.4.1 seems OK (Ubuntu).

This is annoying.  But I'll withdraw the patches; if there's another reason
that 4.4.0 is bad, we can ban it and reintroduce this.  I don't think that
breaking this hack is enough to declare 4.4.0 verboten.

Thanks,
Rusty.
Stephen Rothwell Nov. 5, 2009, 6:38 a.m. UTC | #10
Hi Rusty,

On Thu, 5 Nov 2009 16:58:36 +1030 Rusty Russell <rusty@rustcorp.com.au> wrote:
>
> Huh?  virtio_has_feature does:
> 
> 	if (__builtin_constant_p(fbit))
> 		BUILD_BUG_ON(fbit >= 32);
> 	else
> 		BUG_ON(fbit >= 32);

In Linus' tree (and linux-next) it looks like this:

static inline bool virtio_has_feature(const struct virtio_device *vdev,
				      unsigned int fbit)
{
	/* Did you forget to fix assumptions on max features? */
	MAYBE_BUILD_BUG_ON(fbit >= 32);

	if (fbit < VIRTIO_TRANSPORT_F_START)
		virtio_check_driver_offered_feature(vdev, fbit);

	return test_bit(fbit, vdev->features);
}

> So, if it's not a constant, gcc should throw away that first branch.  If it
> is, it should optimize it away (and no, these are not real bugs AFAICT).

Your version above may well fix the problem.  Alternatively marking it
__always_inline way work as well.

> I did a 4.3.3 allmodconfig with this patch on 64-bit a few days back and all
> was fine.  Will try 4.4.0 now.

4.4 is more problematic.
Rusty Russell Nov. 6, 2009, 6:30 a.m. UTC | #11
On Thu, 5 Nov 2009 05:08:42 pm Stephen Rothwell wrote:
> Hi Rusty,
> 
> On Thu, 5 Nov 2009 16:58:36 +1030 Rusty Russell <rusty@rustcorp.com.au> wrote:
> >
> > Huh?  virtio_has_feature does:
> > 
> > 	if (__builtin_constant_p(fbit))
> > 		BUILD_BUG_ON(fbit >= 32);
> > 	else
> > 		BUG_ON(fbit >= 32);
> 
> In Linus' tree (and linux-next) it looks like this:

Ah.  My patch series fixes that as part of removing MAYBE_BUILD_BUG_ON.

I've put both in for linux-next.

Cheers,
Rusty.
diff mbox

Patch

diff --git a/include/linux/kernel.h b/include/linux/kernel.h
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -683,12 +683,6 @@  struct sysinfo {
 	char _f[20-2*sizeof(long)-sizeof(int)];	/* Padding: libc5 uses this.. */
 };
 
-/* Force a compilation error if condition is true */
-#define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition))
-
-/* Force a compilation error if condition is constant and true */
-#define MAYBE_BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2 * !!(cond)]))
-
 /* Force a compilation error if condition is true, but also produce a
    result (of value 0 and type size_t), so the expression can be used
    e.g. in a structure initializer (or where-ever else comma expressions
@@ -696,6 +690,33 @@  struct sysinfo {
 #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
 #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
 
+/**
+ * BUILD_BUG_ON - break compile if a condition is true.
+ * @cond: the condition which the compiler should know is false.
+ *
+ * If you have some code which relies on certain constants being equal, or
+ * other compile-time-evaluated condition, you should use BUILD_BUG_ON to
+ * detect if someone changes it.
+ *
+ * The implementation uses gcc's reluctance to create a negative array, but
+ * gcc (as of 4.4) only emits that error for obvious cases (eg. not arguments
+ * to inline functions).  So as a fallback we use the optimizer; if it can't
+ * prove the condition is false, it will cause a link error on the undefined
+ * "__build_bug_on_failed".  This error message can be harder to track down
+ * though, hence the two different methods.
+ */
+#ifndef __OPTIMIZE__
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+#else
+extern int __build_bug_on_failed;
+#define BUILD_BUG_ON(condition)					\
+	do {							\
+		((void)sizeof(char[1 - 2*!!(condition)]));	\
+		if (condition) __build_bug_on_failed = 1;	\
+	} while(0)
+#endif
+#define MAYBE_BUILD_BUG_ON(condition) BUILD_BUG_ON(condition)
+
 /* Trap pasters of __FUNCTION__ at compile-time */
 #define __FUNCTION__ (__func__)