[PATCH] mm/gfp: cast GFP_ZONE_TABLE entries to long to avoid shift overflow

Yankai Xu posted 1 patch 1 month, 4 weeks ago
There is a newer version of this series
include/linux/gfp.h | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
[PATCH] mm/gfp: cast GFP_ZONE_TABLE entries to long to avoid shift overflow
Posted by Yankai Xu 1 month, 4 weeks ago
When a new zone is added to enum zone_type in mmzone.h, the existing
GFP_ZONE_TABLE macro causes a compile-time shift overflow. This happens
because enum zone_type is of type int. The shift is logically
valid because it has been checked by 16 * GFP_ZONES_SHIFT > BITS_PER_LONG previously.

Fixed this by casting each value in GFP_ZONE_TABLE to type long.

Signed-off-by: Yankai Xu <815559068@qq.com>
---
 include/linux/gfp.h | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index b155929af..e694f3103 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -122,14 +122,14 @@ static inline bool gfpflags_allow_spinning(const gfp_t gfp_flags)
 #endif

 #define GFP_ZONE_TABLE ( \
-	(ZONE_NORMAL << 0 * GFP_ZONES_SHIFT)				       \
-	| (OPT_ZONE_DMA << ___GFP_DMA * GFP_ZONES_SHIFT)		       \
-	| (OPT_ZONE_HIGHMEM << ___GFP_HIGHMEM * GFP_ZONES_SHIFT)	       \
-	| (OPT_ZONE_DMA32 << ___GFP_DMA32 * GFP_ZONES_SHIFT)		       \
-	| (ZONE_NORMAL << ___GFP_MOVABLE * GFP_ZONES_SHIFT)		       \
-	| (OPT_ZONE_DMA << (___GFP_MOVABLE | ___GFP_DMA) * GFP_ZONES_SHIFT)    \
-	| (ZONE_MOVABLE << (___GFP_MOVABLE | ___GFP_HIGHMEM) * GFP_ZONES_SHIFT)\
-	| (OPT_ZONE_DMA32 << (___GFP_MOVABLE | ___GFP_DMA32) * GFP_ZONES_SHIFT)\
+	((long)ZONE_NORMAL << 0 * GFP_ZONES_SHIFT)				     \
+	| ((long)OPT_ZONE_DMA << ___GFP_DMA * GFP_ZONES_SHIFT)			     \
+	| ((long)OPT_ZONE_HIGHMEM << ___GFP_HIGHMEM * GFP_ZONES_SHIFT)		     \
+	| ((long)OPT_ZONE_DMA32 << ___GFP_DMA32 * GFP_ZONES_SHIFT)		     \
+	| ((long)ZONE_NORMAL << ___GFP_MOVABLE * GFP_ZONES_SHIFT)		     \
+	| ((long)OPT_ZONE_DMA << (___GFP_MOVABLE | ___GFP_DMA) * GFP_ZONES_SHIFT)    \
+	| ((long)ZONE_MOVABLE << (___GFP_MOVABLE | ___GFP_HIGHMEM) * GFP_ZONES_SHIFT)\
+	| ((long)OPT_ZONE_DMA32 << (___GFP_MOVABLE | ___GFP_DMA32) * GFP_ZONES_SHIFT)\
 )

 /*
--
2.43.0
Re: [PATCH] mm/gfp: cast GFP_ZONE_TABLE entries to long to avoid shift overflow
Posted by Andrew Morton 1 month, 4 weeks ago
On Thu, 11 Dec 2025 18:24:05 +0800 Yankai Xu <815559068@qq.com> wrote:

> 
> When a new zone is added to enum zone_type in mmzone.h, the existing
> GFP_ZONE_TABLE macro causes a compile-time shift overflow.

Thanks.

Please quote the compiler warning messages and describe how to
reproduce this.  Please include this info in the patch changelog and
maintain it.

> This happens
> because enum zone_type is of type int. The shift is logically
> valid because it has been checked by 16 * GFP_ZONES_SHIFT > BITS_PER_LONG previously.
> 
> Fixed this by casting each value in GFP_ZONE_TABLE to type long.
> 
> ...
>
>  #define GFP_ZONE_TABLE ( \
> -	(ZONE_NORMAL << 0 * GFP_ZONES_SHIFT)				\
> +	((long)ZONE_NORMAL << 0 * GFP_ZONES_SHIFT)			\

It would be nice to find something nicer than this.  Perhaps a type of
something was poorly chosen.
Re: [PATCH] mm/gfp: cast GFP_ZONE_TABLE entries to long to avoid shift overflow
Posted by Yankai Xu 1 month, 4 weeks ago
Hi Andrew,

Thanks for the review.

 > Please quote the compiler warning messages and describe how to
 > reproduce this.  Please include this info in the patch changelog and
 > maintain it.

I have included them in patch v2. Here's the LKML link for reference:
https://lore.kernel.org/lkml/tencent_DAB2E2BC61A449B6AC4FA9798C4D75BED705@qq.com/T/#/u

 > >  #define GFP_ZONE_TABLE ( \
 > > -    (ZONE_NORMAL << 0 * GFP_ZONES_SHIFT)     \
 > > +    ((long)ZONE_NORMAL << 0 * GFP_ZONES_SHIFT)       \
 >
 > It would be nice to find something nicer than this.  Perhaps a type of
 > something was poorly chosen.

ZONE_NORMAL, ZONE_DMA32, etc. are enum values, which has an underlying
type of int. Changing either the underlying type or the enum type
itself is not feasible. Moreover, the shift overflow only occurs inside
GFP_ZONE_TABLE, modifying other code might be unnecessary. Adding
explicit casts seems to be the most straightforward solution here.

Thanks,
Yankai