All of lore.kernel.org
 help / color / mirror / Atom feed
* + minmax-add-umina-b-and-umaxa-b.patch added to mm-nonmm-unstable branch
@ 2023-09-27 17:30 Andrew Morton
  2023-09-27 19:21 ` Alexey Dobriyan
  0 siblings, 1 reply; 5+ messages in thread
From: Andrew Morton @ 2023-09-27 17:30 UTC (permalink / raw)
  To: mm-commits, willy, torvalds, Jason, hch, david.laight,
	andriy.shevchenko, David.Laight, akpm


The patch titled
     Subject: minmax: add umin(a, b) and umax(a, b)
has been added to the -mm mm-nonmm-unstable branch.  Its filename is
     minmax-add-umina-b-and-umaxa-b.patch

This patch will shortly appear at
     https://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new.git/tree/patches/minmax-add-umina-b-and-umaxa-b.patch

This patch will later appear in the mm-nonmm-unstable branch at
    git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Before you just go and hit "reply", please:
   a) Consider who else should be cc'ed
   b) Prefer to cc a suitable mailing list as well
   c) Ideally: find the original patch on the mailing list and do a
      reply-to-all to that, adding suitable additional cc's

*** Remember to use Documentation/process/submit-checklist.rst when testing your code ***

The -mm tree is included into linux-next via the mm-everything
branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
and is updated there every 2-3 working days

------------------------------------------------------
From: David Laight <David.Laight@ACULAB.COM>
Subject: minmax: add umin(a, b) and umax(a, b)
Date: Mon, 18 Sep 2023 08:16:30 +0000

Patch series "minmax: Relax type checks in min() and max()", v4.

The min() (etc) functions in minmax.h require that the arguments have
exactly the same types.

However when the type check fails, rather than look at the types and fix
the type of a variable/constant, everyone seems to jump on min_t().  In
reality min_t() ought to be rare - when something unusual is being done,
not normality.

The orginal min() (added in 2.4.9) replaced several inline functions and
included the type - so matched the implicit casting of the function call. 
This was renamed min_t() in 2.4.10 and the current min() added.  There is
no actual indication that the conversion of negatve values to large
unsigned values has ever been an actual problem.

A quick grep shows 5734 min() and 4597 min_t().  Having the casts on
almost half of the calls shows that something is clearly wrong.

If the wrong type is picked (and it is far too easy to pick the type of
the result instead of the larger input) then significant bits can get
discarded.

Pretty much the worst example is in the derived clamp_val(), consider:
        unsigned char x = 200u;
        y = clamp_val(x, 10u, 300u);

I also suspect that many of the min_t(u16, ...) are actually wrong.  For
example copy_data() in printk_ringbuffer.c contains:

        data_size = min_t(u16, buf_size, len);

Here buf_size is 'unsigned int' and len 'u16', pass a 64k buffer (can you
prove that doesn't happen?) and no data is returned.  Apparantly it did -
and has since been fixed.

The only reason that most of the min_t() are 'fine' is that pretty much
all the values in the kernel are between 0 and INT_MAX.

Patch 1 adds umin(), this uses integer promotions to convert both
arguments to 'unsigned long long'.  It can be used to compare a signed
type that is known to contain a non-negative value with an unsigned type. 
The compiler typically optimises it all away.  Added first so that it can
be referred to in patch 2.

Patch 2 replaces the 'same type' check with a 'same signedness' one.  This
makes min(unsigned_int_var, sizeof()) be ok.  The error message is also
improved and will contain the expanded form of both arguments (useful for
seeing how constants are defined).

Patch 3 just fixes some whitespace.

Patch 4 allows comparisons of 'unsigned char' and 'unsigned short' to
signed types.  The integer promotion rules convert them both to 'signed
int' prior to the comparison so they can never cause a negative value be
converted to a large positive one.

Patch 5 (rewritted for v4) allows comparisons of unsigned values against
non-negative constant integer expressions.  This makes
min(unsigned_int_var, 4) be ok.

The only common case that is still errored is the comparison of signed
values against unsigned constant integer expressions below __INT_MAX__. 
Typcally min(int_val, sizeof (foo)), the real fix for this is casting the
constant: min(int_var, (int)sizeof (foo)).

With all the patches applied pretty much all the min_t() could be replaced
by min(), and most of the rest by umin().  However they all need careful
inspection due to code like:

        sz = min_t(unsigned char, sz - 1, LIM - 1) + 1;

which converts 0 to LIM.


This patch (of 6):

umin() and umax() can be used when min()/max() errors a signed v unsigned
compare when the signed value is known to be non-negative.

Unlike min_t(some_unsigned_type, a, b) umin() will never mask off high
bits if an inappropriate type is selected.

The '+ 0u + 0ul + 0ull' may look strange.
The '+ 0u' is needed for 'signed int' on 64bit systems.
The '+ 0ul' is needed for 'signed long' on 32bit systems.
The '+ 0ull' is needed for 'signed long long'.

Link: https://lkml.kernel.org/r/b97faef60ad24922b530241c5d7c933c@AcuMS.aculab.com
Link: https://lkml.kernel.org/r/41d93ca827a248698ec64bf57e0c05a5@AcuMS.aculab.com
Signed-off-by: David Laight <david.laight@aculab.com>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Jason A. Donenfeld <Jason@zx2c4.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---

 include/linux/minmax.h |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)

--- a/include/linux/minmax.h~minmax-add-umina-b-and-umaxa-b
+++ a/include/linux/minmax.h
@@ -77,6 +77,23 @@
 #define max(x, y)	__careful_cmp(x, y, >)
 
 /**
+ * umin - return minimum of two non-negative values
+ *   Signed types are zero extended to match a larger unsigned type.
+ * @x: first value
+ * @y: second value
+ */
+#define umin(x, y)	\
+	__careful_cmp((x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull, <)
+
+/**
+ * umax - return maximum of two non-negative values
+ * @x: first value
+ * @y: second value
+ */
+#define umax(x, y)	\
+	__careful_cmp((x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull, >)
+
+/**
  * min3 - return minimum of three values
  * @x: first value
  * @y: second value
_

Patches currently in -mm which might be from David.Laight@ACULAB.COM are

minmax-add-umina-b-and-umaxa-b.patch
minmax-allow-min-max-clamp-if-the-arguments-have-the-same-signedness.patch
minmax-fix-indentation-of-__cmp_once-and-__clamp_once.patch
minmax-allow-comparisons-of-int-against-unsigned-char-short.patch
minmax-relax-check-to-allow-comparison-between-unsigned-arguments-and-signed-constants.patch


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

* Re: + minmax-add-umina-b-and-umaxa-b.patch added to mm-nonmm-unstable branch
  2023-09-27 17:30 + minmax-add-umina-b-and-umaxa-b.patch added to mm-nonmm-unstable branch Andrew Morton
@ 2023-09-27 19:21 ` Alexey Dobriyan
  2023-09-27 20:00   ` Matthew Wilcox
  0 siblings, 1 reply; 5+ messages in thread
From: Alexey Dobriyan @ 2023-09-27 19:21 UTC (permalink / raw)
  To: David Laight
  Cc: linux-kernel, willy, torvalds, Jason, hch, david.laight,
	andriy.shevchenko, akpm

On Wed, Sep 27, 2023 at 10:30:33AM -0700, Andrew Morton wrote:
> +#define umin(x, y)	\
> +	__careful_cmp((x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull, <)

kmin() and kmax() are (of course!) much better names.

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

* Re: + minmax-add-umina-b-and-umaxa-b.patch added to mm-nonmm-unstable branch
  2023-09-27 19:21 ` Alexey Dobriyan
@ 2023-09-27 20:00   ` Matthew Wilcox
  2023-09-28  8:38     ` Alexey Dobriyan
  0 siblings, 1 reply; 5+ messages in thread
From: Matthew Wilcox @ 2023-09-27 20:00 UTC (permalink / raw)
  To: Alexey Dobriyan
  Cc: David Laight, linux-kernel, torvalds, Jason, hch,
	andriy.shevchenko, akpm

On Wed, Sep 27, 2023 at 10:21:41PM +0300, Alexey Dobriyan wrote:
> On Wed, Sep 27, 2023 at 10:30:33AM -0700, Andrew Morton wrote:
> > +#define umin(x, y)	\
> > +	__careful_cmp((x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull, <)
> 
> kmin() and kmax() are (of course!) much better names.

it's unsigned, not user.

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

* Re: + minmax-add-umina-b-and-umaxa-b.patch added to mm-nonmm-unstable branch
  2023-09-27 20:00   ` Matthew Wilcox
@ 2023-09-28  8:38     ` Alexey Dobriyan
  2023-09-28  8:55       ` David Laight
  0 siblings, 1 reply; 5+ messages in thread
From: Alexey Dobriyan @ 2023-09-28  8:38 UTC (permalink / raw)
  To: Matthew Wilcox
  Cc: David Laight, linux-kernel, torvalds, Jason, hch,
	andriy.shevchenko, akpm

On Wed, Sep 27, 2023 at 09:00:37PM +0100, Matthew Wilcox wrote:
> On Wed, Sep 27, 2023 at 10:21:41PM +0300, Alexey Dobriyan wrote:
> > On Wed, Sep 27, 2023 at 10:30:33AM -0700, Andrew Morton wrote:
> > > +#define umin(x, y)	\
> > > +	__careful_cmp((x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull, <)
> > 
> > kmin() and kmax() are (of course!) much better names.
> 
> it's unsigned, not user.

Yes, but the same idea applies to signed types:

min, max require identical types
min_t force type
kmin, kmax are relaxed min/max versions if signednesses match.

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

* RE: + minmax-add-umina-b-and-umaxa-b.patch added to mm-nonmm-unstable branch
  2023-09-28  8:38     ` Alexey Dobriyan
@ 2023-09-28  8:55       ` David Laight
  0 siblings, 0 replies; 5+ messages in thread
From: David Laight @ 2023-09-28  8:55 UTC (permalink / raw)
  To: 'Alexey Dobriyan', Matthew Wilcox
  Cc: linux-kernel, torvalds, Jason, hch, andriy.shevchenko, akpm

From: Alexey Dobriyan
> Sent: 28 September 2023 09:39
> 
> On Wed, Sep 27, 2023 at 09:00:37PM +0100, Matthew Wilcox wrote:
> > On Wed, Sep 27, 2023 at 10:21:41PM +0300, Alexey Dobriyan wrote:
> > > On Wed, Sep 27, 2023 at 10:30:33AM -0700, Andrew Morton wrote:
> > > > +#define umin(x, y)	\
> > > > +	__careful_cmp((x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull, <)
> > >
> > > kmin() and kmax() are (of course!) much better names.
> >
> > it's unsigned, not user.

Linus suggested umin() as being much shorter than the min_unsigned()
I'd originally used.

> Yes, but the same idea applies to signed types:

The kernel pretty much never wants a cast to convert a large
unsigned value to a negative signed one.
If the types mismatch both values are normally non-negative
so doing an unsigned compare is right.
If you do need to treat 0u - 1 as a signed value then adding
an explicit cast is probably a good idea!

> min, max require identical types
> min_t force type
> kmin, kmax are relaxed min/max versions if signednesses match.

The 'identical types' case is pointless, and the 'force type'
often buggy.

The only reason for any type-check is to stop 'integer promotion'
converting a negative value to a very large unsigned one.
And even that isn't why the typecheck was added to min().
(That is, there is no indication that it ever caused a bug.)

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

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

end of thread, other threads:[~2023-09-28  8:55 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-27 17:30 + minmax-add-umina-b-and-umaxa-b.patch added to mm-nonmm-unstable branch Andrew Morton
2023-09-27 19:21 ` Alexey Dobriyan
2023-09-27 20:00   ` Matthew Wilcox
2023-09-28  8:38     ` Alexey Dobriyan
2023-09-28  8:55       ` David Laight

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.