This is a note to let you know that I've just added the patch titled

    minmax: allow min()/max()/clamp() if the arguments have the same signedness.

to the 5.10-stable tree which can be found at:
    
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     minmax-allow-min-max-clamp-if-the-arguments-have-the-same-signedness.patch
and it can be found in the queue-5.10 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <[email protected]> know about it.


>From [email protected] Fri Oct 17 11:08:35 2025
From: Eliav Farber <[email protected]>
Date: Fri, 17 Oct 2025 09:05:01 +0000
Subject: minmax: allow min()/max()/clamp() if the arguments have the same 
signedness.
To: <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <rajur@chelsio
 .com>, <[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>,
  <[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, 
<[email protected]>, <[email protected]>, <tipc-discussion@
 lists.sourceforge.net>
Cc: Christoph Hellwig <[email protected]>, Linus Torvalds 
<[email protected]>
Message-ID: <[email protected]>

From: David Laight <[email protected]>

[ Upstream commit d03eba99f5bf7cbc6e2fdde3b6fa36954ad58e09 ]

The type-check in min()/max() is there to stop unexpected results if a
negative value gets converted to a large unsigned value.  However it also
rejects 'unsigned int' v 'unsigned long' compares which are common and
never problematc.

Replace the 'same type' check with a 'same signedness' check.

The new test isn't itself a compile time error, so use static_assert() to
report the error and give a meaningful error message.

Due to the way builtin_choose_expr() works detecting the error in the
'non-constant' side (where static_assert() can be used) also detects
errors when the arguments are constant.

Link: 
https://lkml.kernel.org/r/[email protected]
Signed-off-by: David Laight <[email protected]>
Cc: Andy Shevchenko <[email protected]>
Cc: Christoph Hellwig <[email protected]>
Cc: Jason A. Donenfeld <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Matthew Wilcox (Oracle) <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Eliav Farber <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
 include/linux/minmax.h |   62 ++++++++++++++++++++++++++-----------------------
 1 file changed, 33 insertions(+), 29 deletions(-)

--- a/include/linux/minmax.h
+++ b/include/linux/minmax.h
@@ -12,9 +12,8 @@
  *
  * - avoid multiple evaluations of the arguments (so side-effects like
  *   "x++" happen only once) when non-constant.
- * - perform strict type-checking (to generate warnings instead of
- *   nasty runtime surprises). See the "unnecessary" pointer comparison
- *   in __typecheck().
+ * - perform signed v unsigned type-checking (to generate compile
+ *   errors instead of nasty runtime surprises).
  * - retain result as a constant expressions when called with only
  *   constant expressions (to avoid tripping VLA warnings in stack
  *   allocation usage).
@@ -22,23 +21,30 @@
 #define __typecheck(x, y) \
        (!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))
 
-#define __no_side_effects(x, y) \
-               (__is_constexpr(x) && __is_constexpr(y))
+/* is_signed_type() isn't a constexpr for pointer types */
+#define __is_signed(x)                                                         
        \
+       __builtin_choose_expr(__is_constexpr(is_signed_type(typeof(x))),        
\
+               is_signed_type(typeof(x)), 0)
 
-#define __safe_cmp(x, y) \
-               (__typecheck(x, y) && __no_side_effects(x, y))
+#define __types_ok(x, y) \
+       (__is_signed(x) == __is_signed(y))
 
-#define __cmp(x, y, op)        ((x) op (y) ? (x) : (y))
+#define __cmp_op_min <
+#define __cmp_op_max >
 
-#define __cmp_once(x, y, unique_x, unique_y, op) ({    \
+#define __cmp(op, x, y)        ((x) __cmp_op_##op (y) ? (x) : (y))
+
+#define __cmp_once(op, x, y, unique_x, unique_y) ({    \
                typeof(x) unique_x = (x);               \
                typeof(y) unique_y = (y);               \
-               __cmp(unique_x, unique_y, op); })
-
-#define __careful_cmp(x, y, op) \
-       __builtin_choose_expr(__safe_cmp(x, y), \
-               __cmp(x, y, op), \
-               __cmp_once(x, y, __UNIQUE_ID(__x), __UNIQUE_ID(__y), op))
+               static_assert(__types_ok(x, y),         \
+                       #op "(" #x ", " #y ") signedness error, fix types or 
consider u" #op "() before " #op "_t()"); \
+               __cmp(op, unique_x, unique_y); })
+
+#define __careful_cmp(op, x, y)                                        \
+       __builtin_choose_expr(__is_constexpr((x) - (y)),        \
+               __cmp(op, x, y),                                \
+               __cmp_once(op, x, y, __UNIQUE_ID(__x), __UNIQUE_ID(__y)))
 
 #define __clamp(val, lo, hi)   \
        ((val) >= (hi) ? (hi) : ((val) <= (lo) ? (lo) : (val)))
@@ -47,17 +53,15 @@
                typeof(val) unique_val = (val);                         \
                typeof(lo) unique_lo = (lo);                            \
                typeof(hi) unique_hi = (hi);                            \
+               static_assert(__builtin_choose_expr(__is_constexpr((lo) > 
(hi)),        \
+                               (lo) <= (hi), true),                            
        \
+                       "clamp() low limit " #lo " greater than high limit " 
#hi);      \
+               static_assert(__types_ok(val, lo), "clamp() 'lo' signedness 
error");    \
+               static_assert(__types_ok(val, hi), "clamp() 'hi' signedness 
error");    \
                __clamp(unique_val, unique_lo, unique_hi); })
 
-#define __clamp_input_check(lo, hi)                                    \
-        (BUILD_BUG_ON_ZERO(__builtin_choose_expr(                      \
-                __is_constexpr((lo) > (hi)), (lo) > (hi), false)))
-
 #define __careful_clamp(val, lo, hi) ({                                        
\
-       __clamp_input_check(lo, hi) +                                   \
-       __builtin_choose_expr(__typecheck(val, lo) && __typecheck(val, hi) && \
-                             __typecheck(hi, lo) && __is_constexpr(val) && \
-                             __is_constexpr(lo) && __is_constexpr(hi), \
+       __builtin_choose_expr(__is_constexpr((val) - (lo) + (hi)),      \
                __clamp(val, lo, hi),                                   \
                __clamp_once(val, lo, hi, __UNIQUE_ID(__val),           \
                             __UNIQUE_ID(__lo), __UNIQUE_ID(__hi))); })
@@ -67,14 +71,14 @@
  * @x: first value
  * @y: second value
  */
-#define min(x, y)      __careful_cmp(x, y, <)
+#define min(x, y)      __careful_cmp(min, x, y)
 
 /**
  * max - return maximum of two values of the same or compatible types
  * @x: first value
  * @y: second value
  */
-#define max(x, y)      __careful_cmp(x, y, >)
+#define max(x, y)      __careful_cmp(max, x, y)
 
 /**
  * umin - return minimum of two non-negative values
@@ -83,7 +87,7 @@
  * @y: second value
  */
 #define umin(x, y)     \
-       __careful_cmp((x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull, <)
+       __careful_cmp(min, (x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull)
 
 /**
  * umax - return maximum of two non-negative values
@@ -91,7 +95,7 @@
  * @y: second value
  */
 #define umax(x, y)     \
-       __careful_cmp((x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull, >)
+       __careful_cmp(max, (x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull)
 
 /**
  * min3 - return minimum of three values
@@ -143,7 +147,7 @@
  * @x: first value
  * @y: second value
  */
-#define min_t(type, x, y)      __careful_cmp((type)(x), (type)(y), <)
+#define min_t(type, x, y)      __careful_cmp(min, (type)(x), (type)(y))
 
 /**
  * max_t - return maximum of two values, using the specified type
@@ -151,7 +155,7 @@
  * @x: first value
  * @y: second value
  */
-#define max_t(type, x, y)      __careful_cmp((type)(x), (type)(y), >)
+#define max_t(type, x, y)      __careful_cmp(max, (type)(x), (type)(y))
 
 /*
  * Do not check the array parameter using __must_be_array().


Patches currently in stable-queue which might be from [email protected] are

queue-5.10/minmax-allow-comparisons-of-int-against-unsigned-char-short.patch
queue-5.10/minmax-add-a-few-more-min_t-max_t-users.patch
queue-5.10/minmax-improve-macro-expansion-and-type-checking.patch
queue-5.10/minmax-fix-indentation-of-__cmp_once-and-__clamp_once.patch
queue-5.10/minmax.h-simplify-the-variants-of-clamp.patch
queue-5.10/minmax-add-in_range-macro.patch
queue-5.10/minmax.h-move-all-the-clamp-definitions-after-the-min-max-ones.patch
queue-5.10/minmax-allow-min-max-clamp-if-the-arguments-have-the-same-signedness.patch
queue-5.10/minmax-don-t-use-max-in-situations-that-want-a-c-constant-expression.patch
queue-5.10/minmax.h-remove-some-defines-that-are-only-expanded-once.patch
queue-5.10/minmax.h-use-build_bug_on_msg-for-the-lo-hi-test-in-clamp.patch
queue-5.10/minmax-simplify-min-max-clamp-implementation.patch
queue-5.10/minmax-deduplicate-__unconst_integer_typeof.patch
queue-5.10/minmax-simplify-and-clarify-min_t-max_t-implementation.patch
queue-5.10/minmax.h-add-whitespace-around-operators-and-after-commas.patch
queue-5.10/minmax-sanity-check-constant-bounds-when-clamping.patch
queue-5.10/minmax-avoid-overly-complicated-constant-expressions-in-vm-code.patch
queue-5.10/minmax-make-generic-min-and-max-macros-available-everywhere.patch
queue-5.10/minmax-fix-up-min3-and-max3-too.patch
queue-5.10/minmax.h-reduce-the-define-expansion-of-min-max-and-clamp.patch
queue-5.10/minmax-fix-header-inclusions.patch
queue-5.10/minmax-introduce-min-max-_array.patch
queue-5.10/btrfs-remove-duplicated-in_range-macro.patch
queue-5.10/overflow-tracing-define-the-is_signed_type-macro-once.patch
queue-5.10/minmax-relax-check-to-allow-comparison-between-unsigned-arguments-and-signed-constants.patch
queue-5.10/minmax-clamp-more-efficiently-by-avoiding-extra-comparison.patch
queue-5.10/minmax.h-update-some-comments.patch

Reply via email to