linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] word-at-a-time: avoid undefined behaviour in zero_bytemask macro
@ 2014-04-23 16:52 Will Deacon
  2014-04-30 21:22 ` H. Peter Anvin
  0 siblings, 1 reply; 3+ messages in thread
From: Will Deacon @ 2014-04-23 16:52 UTC (permalink / raw)
  To: torvalds; +Cc: linux-kernel, Will Deacon, stable, Victor Kamensky

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: <stable@vger.kernel.org>
Cc: Victor Kamensky <victor.kamensky@linaro.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---

Hi Linus,

Victor reported this with a big-endian arm64 system. This is the
cleanest, most efficient solution I could come up with, but it would be
helpful if you could please confirm my assumption that zero_bytemask(0)
is nonsensical.

Cheers,

Will

 include/asm-generic/word-at-a-time.h | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/include/asm-generic/word-at-a-time.h b/include/asm-generic/word-at-a-time.h
index d3909effd725..d96deb443f18 100644
--- a/include/asm-generic/word-at-a-time.h
+++ b/include/asm-generic/word-at-a-time.h
@@ -50,11 +50,7 @@ static inline bool has_zero(unsigned long val, unsigned long *data, const struct
 }
 
 #ifndef zero_bytemask
-#ifdef CONFIG_64BIT
-#define zero_bytemask(mask)	(~0ul << fls64(mask))
-#else
-#define zero_bytemask(mask)	(~0ul << fls(mask))
-#endif /* CONFIG_64BIT */
-#endif /* zero_bytemask */
+#define zero_bytemask(mask) (~0ul << __fls(mask) << 1)
+#endif
 
 #endif /* _ASM_WORD_AT_A_TIME_H */
-- 
1.9.2


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

* Re: [PATCH] word-at-a-time: avoid undefined behaviour in zero_bytemask macro
  2014-04-23 16:52 [PATCH] word-at-a-time: avoid undefined behaviour in zero_bytemask macro Will Deacon
@ 2014-04-30 21:22 ` H. Peter Anvin
  2014-05-01  9:04   ` Will Deacon
  0 siblings, 1 reply; 3+ messages in thread
From: H. Peter Anvin @ 2014-04-30 21:22 UTC (permalink / raw)
  To: Will Deacon, torvalds; +Cc: linux-kernel, stable, Victor Kamensky

On 04/23/2014 09:52 AM, Will Deacon wrote:
> 
> diff --git a/include/asm-generic/word-at-a-time.h b/include/asm-generic/word-at-a-time.h
> index d3909effd725..d96deb443f18 100644
> --- a/include/asm-generic/word-at-a-time.h
> +++ b/include/asm-generic/word-at-a-time.h
> @@ -50,11 +50,7 @@ static inline bool has_zero(unsigned long val, unsigned long *data, const struct
>  }
>  
>  #ifndef zero_bytemask
> -#ifdef CONFIG_64BIT
> -#define zero_bytemask(mask)	(~0ul << fls64(mask))
> -#else
> -#define zero_bytemask(mask)	(~0ul << fls(mask))
> -#endif /* CONFIG_64BIT */
> -#endif /* zero_bytemask */
> +#define zero_bytemask(mask) (~0ul << __fls(mask) << 1)
> +#endif
>  
>  #endif /* _ASM_WORD_AT_A_TIME_H */
> 

Why not:

#define zero_bytemask(mask) (~1ul << __fls(mask))

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

* Re: [PATCH] word-at-a-time: avoid undefined behaviour in zero_bytemask macro
  2014-04-30 21:22 ` H. Peter Anvin
@ 2014-05-01  9:04   ` Will Deacon
  0 siblings, 0 replies; 3+ messages in thread
From: Will Deacon @ 2014-05-01  9:04 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: torvalds, linux-kernel, stable, Victor Kamensky

Hi Peter,

On Wed, Apr 30, 2014 at 10:22:19PM +0100, H. Peter Anvin wrote:
> On 04/23/2014 09:52 AM, Will Deacon wrote:
> > diff --git a/include/asm-generic/word-at-a-time.h b/include/asm-generic/word-at-a-time.h
> > index d3909effd725..d96deb443f18 100644
> > --- a/include/asm-generic/word-at-a-time.h
> > +++ b/include/asm-generic/word-at-a-time.h
> > @@ -50,11 +50,7 @@ static inline bool has_zero(unsigned long val, unsigned long *data, const struct
> >  }
> >  
> >  #ifndef zero_bytemask
> > -#ifdef CONFIG_64BIT
> > -#define zero_bytemask(mask)	(~0ul << fls64(mask))
> > -#else
> > -#define zero_bytemask(mask)	(~0ul << fls(mask))
> > -#endif /* CONFIG_64BIT */
> > -#endif /* zero_bytemask */
> > +#define zero_bytemask(mask) (~0ul << __fls(mask) << 1)
> > +#endif
> >  
> >  #endif /* _ASM_WORD_AT_A_TIME_H */
> > 
> 
> Why not:
> 
> #define zero_bytemask(mask) (~1ul << __fls(mask))

Yup, that'll work too -- it produces an identical disassembly for arm64.

Will

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

end of thread, other threads:[~2014-05-01  9:04 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-23 16:52 [PATCH] word-at-a-time: avoid undefined behaviour in zero_bytemask macro Will Deacon
2014-04-30 21:22 ` H. Peter Anvin
2014-05-01  9:04   ` Will Deacon

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).