Skip to content
  • Rikard Falkeborn's avatar
    295bcca8
    linux/bits.h: add compile time sanity check of GENMASK inputs · 295bcca8
    Rikard Falkeborn authored
    GENMASK() and GENMASK_ULL() are supposed to be called with the high bit as
    the first argument and the low bit as the second argument.  Mixing them
    will return a mask with zero bits set.
    
    Recent commits show getting this wrong is not uncommon, see e.g.  commit
    aa4c0c90 ("net: stmmac: Fix misuses of GENMASK macro") and commit
    9bdd7bb3 ("clocksource/drivers/npcm: Fix misuse of GENMASK macro").
    
    To prevent such mistakes from appearing again, add compile time sanity
    checking to the arguments of GENMASK() and GENMASK_ULL().  If both
    arguments are known at compile time, and the low bit is higher than the
    high bit, break the build to detect the mistake immediately.
    
    Since GENMASK() is used in declarations, BUILD_BUG_ON_ZERO() must be used
    instead of BUILD_BUG_ON().
    
    __builtin_constant_p does not evaluate is argument, it only checks if it
    is a constant or not at compile time, and __builtin_choose_expr does not
    evaluate the expression that is not chosen.  Therefore, GENMASK(x++, 0)
    does only evaluate x++ once.
    
    Commit 95b980d6 ("linux/bits.h: make BIT(), GENMASK(), and friends
    available in assembly") made the macros in linux/bits.h available in
    assembly.  Since BUILD_BUG_OR_ZERO() is not asm compatible, disable the
    checks if the file is included in an asm file.
    
    Due to bugs in GCC versions before 4.9 [0], disable the check if building
    with a too old GCC compiler.
    
    [0]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=19449
    
    
    
    Signed-off-by: default avatarRikard Falkeborn <rikard.falkeborn@gmail.com>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Reviewed-by: default avatarMasahiro Yamada <yamada.masahiro@socionext.com>
    Reviewed-by: default avatarKees Cook <keescook@chromium.org>
    Cc: Borislav Petkov <bp@alien8.de>
    Cc: Geert Uytterhoeven <geert@linux-m68k.org>
    Cc: Haren Myneni <haren@us.ibm.com>
    Cc: Joe Perches <joe@perches.com>
    Cc: Johannes Berg <johannes@sipsolutions.net>
    Cc: lkml <linux-kernel@vger.kernel.org>
    Cc: Ingo Molnar <mingo@redhat.com>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Link: http://lkml.kernel.org/r/20200308193954.2372399-1-rikard.falkeborn@gmail.com
    
    
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    295bcca8
    linux/bits.h: add compile time sanity check of GENMASK inputs
    Rikard Falkeborn authored
    GENMASK() and GENMASK_ULL() are supposed to be called with the high bit as
    the first argument and the low bit as the second argument.  Mixing them
    will return a mask with zero bits set.
    
    Recent commits show getting this wrong is not uncommon, see e.g.  commit
    aa4c0c90 ("net: stmmac: Fix misuses of GENMASK macro") and commit
    9bdd7bb3 ("clocksource/drivers/npcm: Fix misuse of GENMASK macro").
    
    To prevent such mistakes from appearing again, add compile time sanity
    checking to the arguments of GENMASK() and GENMASK_ULL().  If both
    arguments are known at compile time, and the low bit is higher than the
    high bit, break the build to detect the mistake immediately.
    
    Since GENMASK() is used in declarations, BUILD_BUG_ON_ZERO() must be used
    instead of BUILD_BUG_ON().
    
    __builtin_constant_p does not evaluate is argument, it only checks if it
    is a constant or not at compile time, and __builtin_choose_expr does not
    evaluate the expression that is not chosen.  Therefore, GENMASK(x++, 0)
    does only evaluate x++ once.
    
    Commit 95b980d6 ("linux/bits.h: make BIT(), GENMASK(), and friends
    available in assembly") made the macros in linux/bits.h available in
    assembly.  Since BUILD_BUG_OR_ZERO() is not asm compatible, disable the
    checks if the file is included in an asm file.
    
    Due to bugs in GCC versions before 4.9 [0], disable the check if building
    with a too old GCC compiler.
    
    [0]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=19449
    
    
    
    Signed-off-by: default avatarRikard Falkeborn <rikard.falkeborn@gmail.com>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Reviewed-by: default avatarMasahiro Yamada <yamada.masahiro@socionext.com>
    Reviewed-by: default avatarKees Cook <keescook@chromium.org>
    Cc: Borislav Petkov <bp@alien8.de>
    Cc: Geert Uytterhoeven <geert@linux-m68k.org>
    Cc: Haren Myneni <haren@us.ibm.com>
    Cc: Joe Perches <joe@perches.com>
    Cc: Johannes Berg <johannes@sipsolutions.net>
    Cc: lkml <linux-kernel@vger.kernel.org>
    Cc: Ingo Molnar <mingo@redhat.com>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Link: http://lkml.kernel.org/r/20200308193954.2372399-1-rikard.falkeborn@gmail.com
    
    
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Loading