diff options
author | Peter Zijlstra <peterz@infradead.org> | 2021-11-10 13:01:03 +0300 |
---|---|---|
committer | Peter Zijlstra <peterz@infradead.org> | 2021-12-11 11:09:45 +0300 |
commit | bff8c3848e071d387d8b0784dc91fa49cd563774 (patch) | |
tree | 15b9247051bbfac2551bcbace278c62106474395 /include/linux/bitfield.h | |
parent | e463a09af2f0677b9485a7e8e4e70b396b2ffb6f (diff) | |
download | linux-bff8c3848e071d387d8b0784dc91fa49cd563774.tar.xz |
bitfield.h: Fix "type of reg too small for mask" test
The test: 'mask > (typeof(_reg))~0ull' only works correctly when both
sides are unsigned, consider:
- 0xff000000 vs (int)~0ull
- 0x000000ff vs (int)~0ull
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/r/20211110101324.950210584@infradead.org
Diffstat (limited to 'include/linux/bitfield.h')
-rw-r--r-- | include/linux/bitfield.h | 19 |
1 files changed, 18 insertions, 1 deletions
diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h index 4e035aca6f7e..6093fa6db260 100644 --- a/include/linux/bitfield.h +++ b/include/linux/bitfield.h @@ -41,6 +41,22 @@ #define __bf_shf(x) (__builtin_ffsll(x) - 1) +#define __scalar_type_to_unsigned_cases(type) \ + unsigned type: (unsigned type)0, \ + signed type: (unsigned type)0 + +#define __unsigned_scalar_typeof(x) typeof( \ + _Generic((x), \ + char: (unsigned char)0, \ + __scalar_type_to_unsigned_cases(char), \ + __scalar_type_to_unsigned_cases(short), \ + __scalar_type_to_unsigned_cases(int), \ + __scalar_type_to_unsigned_cases(long), \ + __scalar_type_to_unsigned_cases(long long), \ + default: (x))) + +#define __bf_cast_unsigned(type, x) ((__unsigned_scalar_typeof(type))(x)) + #define __BF_FIELD_CHECK(_mask, _reg, _val, _pfx) \ ({ \ BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \ @@ -49,7 +65,8 @@ BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \ ~((_mask) >> __bf_shf(_mask)) & (_val) : 0, \ _pfx "value too large for the field"); \ - BUILD_BUG_ON_MSG((_mask) > (typeof(_reg))~0ull, \ + BUILD_BUG_ON_MSG(__bf_cast_unsigned(_mask, _mask) > \ + __bf_cast_unsigned(_reg, ~0ull), \ _pfx "type of reg too small for mask"); \ __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \ (1ULL << __bf_shf(_mask))); \ |