Skip to content

Commit ec6931b

Browse files
wildea01torvalds
authored andcommitted
word-at-a-time: avoid undefined behaviour in zero_bytemask macro
The asm-generic, big-endian version of zero_bytemask creates a mask of bytes preceding the first zero-byte by left shifting ~0ul based on the position of the first zero byte. Unfortunately, if the first (top) byte is zero, the output of prep_zero_mask has only the top bit set, resulting in undefined C behaviour as we shift left by an amount equal to the width of the type. As it happens, GCC doesn't manage to spot this through the call to fls(), but the issue remains if architectures choose to implement their shift instructions differently. An example would be arch/arm/ (AArch32), where LSL Rd, Rn, #32 results in Rd == 0x0, whilst on arch/arm64 (AArch64) LSL Xd, Xn, #64 results in Xd == Xn. Rather than check explicitly for the problematic shift, this patch adds an extra shift by 1, replacing fls with __fls. Since zero_bytemask is never called with a zero argument (has_zero() is used to check the data first), we don't need to worry about calling __fls(0), which is undefined. Cc: <[email protected]> Cc: Victor Kamensky <[email protected]> Signed-off-by: Will Deacon <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent ac6c9e2 commit ec6931b

File tree

1 file changed

+2
-6
lines changed

1 file changed

+2
-6
lines changed

include/asm-generic/word-at-a-time.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,7 @@ static inline bool has_zero(unsigned long val, unsigned long *data, const struct
5050
}
5151

5252
#ifndef zero_bytemask
53-
#ifdef CONFIG_64BIT
54-
#define zero_bytemask(mask) (~0ul << fls64(mask))
55-
#else
56-
#define zero_bytemask(mask) (~0ul << fls(mask))
57-
#endif /* CONFIG_64BIT */
58-
#endif /* zero_bytemask */
53+
#define zero_bytemask(mask) (~0ul << __fls(mask) << 1)
54+
#endif
5955

6056
#endif /* _ASM_WORD_AT_A_TIME_H */

0 commit comments

Comments
 (0)