diff mbox series

[XEN,v3] xen/include: avoid using a compiler extension for BUILD_BUG_ON_ZERO.

Message ID db883456d7d210e2ea9ac4a7b402dda73c3ea8cd.1687421893.git.nicola.vetrini@bugseng.com (mailing list archive)
State Superseded
Headers show
Series [XEN,v3] xen/include: avoid using a compiler extension for BUILD_BUG_ON_ZERO. | expand

Commit Message

Nicola Vetrini June 22, 2023, 8:24 a.m. UTC
Redefine BUILD_BUG_ON_ZERO to avoid using a compiler extension
that gives an acceptable semantics to C99 undefined behavior 58
("A structure or union is defined as containing no named members
(6.7.2.1)").

The chosen ill-formed construct is a negative bitwidth in a
bitfield within a struct containing at least one named member,
which prevents the UB while keeping the semantics of the construct.

Signed-off-by: Nicola Vetrini <nicola.vetrini@bugseng.com>
---
Changes in V2:
- Avoid using a VLA as the compile-time assertion
- Do not drop _Static_assert
Changes in V3:
- Changed the operation to bring the result to 0 when the
construct does not lead to a compilation error
---
 xen/include/xen/lib.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

Comments

Jan Beulich June 22, 2023, 8:56 a.m. UTC | #1
On 22.06.2023 10:24, Nicola Vetrini wrote:
> --- a/xen/include/xen/lib.h
> +++ b/xen/include/xen/lib.h
> @@ -51,9 +51,10 @@
>     e.g. in a structure initializer (or where-ever else comma expressions
>     aren't permitted). */
>  #define BUILD_BUG_ON_ZERO(cond) \
> -    sizeof(struct { _Static_assert(!(cond), "!(" #cond ")"); })
> +    (sizeof(struct { char c; _Static_assert(!(cond), "!(" #cond ")"); }) & 0U)
>  #else
> -#define BUILD_BUG_ON_ZERO(cond) sizeof(struct { int:-!!(cond); })
> +#define BUILD_BUG_ON_ZERO(cond) \
> +    (sizeof(struct { unsigned u : (cond) ? -1 : 1; }) & 0U)

Given your remark on named bitfields not being allowed to be zero length
(which hopefully holds universally, i.e. isn't subject to compiler
extensions), how about

#define BUILD_BUG_ON_ZERO(cond) (sizeof(struct { int _:!(cond); }) & 0)

? (Implicitly, as said before, I question the value of the U suffixes here.
Even better might be to make sure the expression is explicitly not of
unsigned type, to avoid surprises if someone used ~BUILD_BUG_ON_ZERO()
somewhere.)

Jan
Nicola Vetrini June 22, 2023, 9:34 a.m. UTC | #2
On 22/06/23 10:56, Jan Beulich wrote:
> On 22.06.2023 10:24, Nicola Vetrini wrote:
>> --- a/xen/include/xen/lib.h
>> +++ b/xen/include/xen/lib.h
>> @@ -51,9 +51,10 @@
>>      e.g. in a structure initializer (or where-ever else comma expressions
>>      aren't permitted). */
>>   #define BUILD_BUG_ON_ZERO(cond) \
>> -    sizeof(struct { _Static_assert(!(cond), "!(" #cond ")"); })
>> +    (sizeof(struct { char c; _Static_assert(!(cond), "!(" #cond ")"); }) & 0U)
>>   #else
>> -#define BUILD_BUG_ON_ZERO(cond) sizeof(struct { int:-!!(cond); })
>> +#define BUILD_BUG_ON_ZERO(cond) \
>> +    (sizeof(struct { unsigned u : (cond) ? -1 : 1; }) & 0U)
> 
> Given your remark on named bitfields not being allowed to be zero length
> (which hopefully holds universally, i.e. isn't subject to compiler
> extensions), how about
> 
> #define BUILD_BUG_ON_ZERO(cond) (sizeof(struct { int _:!(cond); }) & 0)

Well, the reason for the change is to drop any assumption on 
compiler-specific quirks that may arise (it would be a surprise if this 
wasn't the case, though)

> 
> ? (Implicitly, as said before, I question the value of the U suffixes here.
> Even better might be to make sure the expression is explicitly not of
> unsigned type, to avoid surprises if someone used ~BUILD_BUG_ON_ZERO()
> somewhere.)
> 
> Jan

The documentation for the macro definition states that the expression 
must have value 0 and type size_t when cond is false. If I understand 
correctly what you're saying here, then this is not allowed by the 
documentation.

Regards,
Jan Beulich June 22, 2023, 12:41 p.m. UTC | #3
On 22.06.2023 11:34, Nicola Vetrini wrote:
> 
> 
> On 22/06/23 10:56, Jan Beulich wrote:
>> On 22.06.2023 10:24, Nicola Vetrini wrote:
>>> --- a/xen/include/xen/lib.h
>>> +++ b/xen/include/xen/lib.h
>>> @@ -51,9 +51,10 @@
>>>      e.g. in a structure initializer (or where-ever else comma expressions
>>>      aren't permitted). */
>>>   #define BUILD_BUG_ON_ZERO(cond) \
>>> -    sizeof(struct { _Static_assert(!(cond), "!(" #cond ")"); })
>>> +    (sizeof(struct { char c; _Static_assert(!(cond), "!(" #cond ")"); }) & 0U)
>>>   #else
>>> -#define BUILD_BUG_ON_ZERO(cond) sizeof(struct { int:-!!(cond); })
>>> +#define BUILD_BUG_ON_ZERO(cond) \
>>> +    (sizeof(struct { unsigned u : (cond) ? -1 : 1; }) & 0U)
>>
>> Given your remark on named bitfields not being allowed to be zero length
>> (which hopefully holds universally, i.e. isn't subject to compiler
>> extensions), how about
>>
>> #define BUILD_BUG_ON_ZERO(cond) (sizeof(struct { int _:!(cond); }) & 0)
> 
> Well, the reason for the change is to drop any assumption on 
> compiler-specific quirks that may arise (it would be a surprise if this 
> wasn't the case, though)

And the reason for my suggestion was that it's shorter, and typically I
view "shorter" as also "easier to read/follow".

>> ? (Implicitly, as said before, I question the value of the U suffixes here.
>> Even better might be to make sure the expression is explicitly not of
>> unsigned type, to avoid surprises if someone used ~BUILD_BUG_ON_ZERO()
>> somewhere.)
> 
> The documentation for the macro definition states that the expression 
> must have value 0 and type size_t when cond is false. If I understand 
> correctly what you're saying here, then this is not allowed by the 
> documentation.

Well, it's the comment that says this, yes. Question is whether the
comment mandates the behavior or merely describes the current
implementation. Imo it's the latter ... But anyway, switching the
result type is independent of the present goal.

Jan
diff mbox series

Patch

diff --git a/xen/include/xen/lib.h b/xen/include/xen/lib.h
index 67fc7c1d7e..d5f9c4a18a 100644
--- a/xen/include/xen/lib.h
+++ b/xen/include/xen/lib.h
@@ -51,9 +51,10 @@ 
    e.g. in a structure initializer (or where-ever else comma expressions
    aren't permitted). */
 #define BUILD_BUG_ON_ZERO(cond) \
-    sizeof(struct { _Static_assert(!(cond), "!(" #cond ")"); })
+    (sizeof(struct { char c; _Static_assert(!(cond), "!(" #cond ")"); }) & 0U)
 #else
-#define BUILD_BUG_ON_ZERO(cond) sizeof(struct { int:-!!(cond); })
+#define BUILD_BUG_ON_ZERO(cond) \
+    (sizeof(struct { unsigned u : (cond) ? -1 : 1; }) & 0U)
 #define BUILD_BUG_ON(cond) ((void)BUILD_BUG_ON_ZERO(cond))
 #endif