rust-for-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Linus Torvalds <torvalds@linux-foundation.org>
To: Steven Rostedt <rostedt@goodmis.org>, Jens Axboe <axboe@kernel.dk>
Cc: Martin Uecker <uecker@tugraz.at>,
	Dan Carpenter <dan.carpenter@linaro.org>,
	 Greg KH <gregkh@linuxfoundation.org>,
	Boqun Feng <boqun.feng@gmail.com>,
	 "H. Peter Anvin" <hpa@zytor.com>,
	Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>,
	 Christoph Hellwig <hch@infradead.org>,
	rust-for-linux <rust-for-linux@vger.kernel.org>,
	 David Airlie <airlied@gmail.com>,
	linux-kernel@vger.kernel.org, ksummit@lists.linux.dev
Subject: Re: Rust kernel policy
Date: Sat, 22 Feb 2025 10:42:23 -0800	[thread overview]
Message-ID: <CAHk-=wjQCbRA1UEag-1-9yn08KNNqerTj++SCbbW80At=rg5RQ@mail.gmail.com> (raw)
In-Reply-To: <20250221172415.5b632ae6@gandalf.local.home>

On Fri, 21 Feb 2025 at 14:23, Steven Rostedt <rostedt@goodmis.org> wrote:
>
> If I could just get a warning for this stupid mistake:
>
>         size_t ret;
>
>         ret = func();
>         if (ret < 0)
>                 error();
>
> I'd be very happy.

I really don't think the issue here should be considered "ret is
unsigned, so checking against zero is wrong".

Because as mentioned, doing range checks is always correct. A compiler
must not complain about that. So I still think that the horrid
"-Wtype-limits" warning is completely misguided.

No, the issue should be seen as "you got a signed value, then you
unwittingly cast it to unsigned, and then you checked if it's
negative".

That pattern is "easy" to check against in SSA form (because SSA is
really a very natural form for "where did this value come from"), and
I wrote a test patch for sparse.

But this test patch is actually interestign because it does show how
hard it is to give meaningful warnings.

Why? Because SSA is basically the "final form" before register
allocation and code generation - and that means that sparse (or any
real compiler) has already done a *lot* of transformations on the
source code. Which in turn means that sparse actually finds places
that have that pattern, not because the code was written as an
unsigned compare of something that used to be a signed value, but
because various simplifications had turned it into that.

Let me give a couple of examples. First, the actual case you want to
find as a test-case for sparse:

   typedef unsigned long size_t;
   extern int fn(void);
   extern int check(void);

   int check(void)
   {
        size_t ret = fn();
        if (ret < 0)
                return -1;
        return 0;
   }

which makes sparse complain about it:

    t.c:8:19: warning: unsigned value that used to be signed checked
for negative?
    t.c:7:24: signed value source

Look, that's nice (ok, I notice that the "offset within line" fields
have regressed at some point, so ignore that).

It tells you that you are doing an unsigned odd compare against zero
of a value that *used* to be signed, and tells you where the value
originated from.

Perfect, right?

Not so fast.

It actually doesn't result in very many warnings in the current kernel
when I run sparse over it all, so on the face of it it all seems like
a nice good safe warning that doesn't cause a lot of noise.

But then when looking at the cases it *does* find, they are very very
subtle indeed. A couple of them look fine:

    drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c:455:26: warning:
unsigned value that used to be signed checked for negative?
    drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c:452:35: signed value source

which turns out to be this:

        unsigned int brightness = bl_dev->props.brightness;
        ...
        if (brightness < S6E3HA2_MIN_BRIGHTNESS ||
                brightness > bl_dev->props.max_brightness) {

and that's actually pretty much exactly your pattern: 'brightness' is
indeed 'unsigned int', and S6E3HA2_MIN_BRIGHTNESS is indeed zero, and
the *source* of it all is indeed a signed value
(bl_dev->props.brightness is 'int' from 'struct
backlight_properties').

So the warning looks fine, and all it really should need is some extra
logic to *not* warn when there is also an upper bounds check (which
makes it all sane again), That warning is wrong because it's not smart
enough, but it's not "fundamentally wrong" like the type-based one
was. Fine so far.

And the sparse check actually finds real issues:

For example, it finds this:

    drivers/block/zram/zram_drv.c:1234:20: warning: unsigned value
that used to be signed checked for negative?
    drivers/block/zram/zram_drv.c:1234:13: signed value source

which looks odd, because it's all obviously correct:

        if (prio < ZRAM_PRIMARY_COMP || prio >= ZRAM_MAX_COMPS)
                return -EINVAL;

and 'prio' is a plain 'int'. So why would sparse have flagged it?

It's because ZRAM_PRIMARY_COMP is thgis:

        #define ZRAM_PRIMARY_COMP 0U

so while 'prio' is indeed signed, and checking it against 0 would be
ok, checking it against 0U is *NOT* ok, because it makes the whole
comparison unsigned.

So yes, sparse found a subtle mistake. A bug that looks real, although
one where it doesn't matter (because ZRAM_MAX_COMPS is *also* an
unsigned constant, so the "prio >= ZRAM_MAX_COMPS" test will make it
all ok, and negative values are indeed checked for).

Again, extending the patch to notice when the code does a unsigned
range check on the upper side too would make it all ok.

Very cool. Short, sweet, simple sparse patch that finds interesting
places, but they seem to be false positives.

In fact, it finds some *really* interesting patterns. Some of them
don't seem to be false positives at all.

For example, it reports this:

    ./include/linux/blk-mq.h:877:31: warning: unsigned value that used
to be signed checked for negative?
    drivers/block/null_blk/main.c:1550:46: signed value source

and that's just

                if (ioerror < 0)
                        return false;

and 'ioerror' is an 'int'. And here we're checking against plain '0',
not some subtle '0U' thing. So it's clearly correct, and isn't an
unsigned compare at all. Why would sparse even mention it?

The 'signed value source' gives a hint. This is an inline, and the
caller is this:

                cmd->error = null_process_cmd(cmd, req_op(req), blk_rq_pos(req),
                                                blk_rq_sectors(req));
                if (!blk_mq_add_to_batch(req, iob, (__force int) cmd->error,
                                        blk_mq_end_request_batch))

iow, the error is that 'cmd->error' thing, and that is starting to
give a hint about what sparse found. Sparse found a bug.

That '(__force int) cmd->error' is wrong. cmd->error is a blk_status_t, which is

        typedef u8 __bitwise blk_status_t;

which means that when cast to 'int', it *CANNOT* be negative. You're
supposed to use 'blk_status_to_errno()' to make it an error code. The
code is simply buggy, and what has happened is that sparse noticed
that the source of the 'int' was a 8-bit unsigned char, and then
sparse saw the subsequent compare, and said "it's stupid to do a 8-bit
to 32-bit type extension and then do the compare as a signed 32-bit
compare: I'll do it as a unsigned 8-bit compare on the original
value".

And then it noticed that as an unsigned 8-bit compare it made no sense any more.

Look, ma - it's the *perfect* check. Instead of doing the
(wrongheaded) type limit check, it's doing the *right* thing. It's
finding places where you actually mis-use unsigned compares.

No. It also finds a lot of really subtle stuff that is very much
correct, exactly because it does that kind of "oh, the source is a
16-bit unsigned field that has been turned into an 'int', and then
compared against zero" and complains about them.

And usually those complaints are bogus, because the "< 0" is important
in inline functions that do range checking on values that *can* be
negative, but just don't happen to be negative in this case because
the source couldn't be negative and earlier simplifications had turned
a signed compare into an unsigned one, so it now talks about that.

Oh well.

I'm adding Jens to the cc, because I do think that the

    drivers/block/null_blk/main.c:1550:46: signed value source

thing is a real bug, and that doing that (__force int) cmd->error is
bogus. I doubt anybody cares (it's the null_blk driver), but still..

I also pushed out the sparse patch in case anybody wants to play with
this, but while I've mentioned a couple of "this looks fine but not
necessarily relevant" warnings, the limitations of that patch really
do cause completely nonsensical warnings:

    git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/sparse.git
unsigned-negative

Not a ton of them, but some. bcachefs actually gets a number of them,
it looks like the games it plays with bkeys really triggers some of
that. I'm almost certain those are false positives, but exactly
because sparse goes *so* deep (there's tons of macros in there, but it
also follows the data flow through inline functions into the source of
the data), it can be really hard to see where it all comes from.

Anyway - good compiler warnings are really hard to generate. But
-Wtype-limits is *not* one of them.

               Linus

  parent reply	other threads:[~2025-02-22 18:42 UTC|newest]

Thread overview: 183+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-09 20:56 Rust kernel policy Miguel Ojeda
2025-02-18 16:08 ` Christoph Hellwig
2025-02-18 16:35   ` Jarkko Sakkinen
2025-02-18 16:39     ` Jarkko Sakkinen
2025-02-18 18:08       ` Jarkko Sakkinen
2025-02-18 21:22         ` Boqun Feng
2025-02-19  6:20           ` Jarkko Sakkinen
2025-02-19  6:35             ` Dave Airlie
2025-02-19 11:37               ` Jarkko Sakkinen
2025-02-19 13:25                 ` Geert Uytterhoeven
2025-02-19 13:40                   ` Jarkko Sakkinen
2025-02-19  7:05             ` Boqun Feng
2025-02-19 11:32               ` Jarkko Sakkinen
2025-02-18 17:36   ` Jiri Kosina
2025-02-20  6:33     ` Christoph Hellwig
2025-02-20 18:40       ` Alexei Starovoitov
2025-02-18 18:46   ` Miguel Ojeda
2025-02-18 21:49     ` H. Peter Anvin
2025-02-18 22:38       ` Dave Airlie
2025-02-18 22:54       ` Miguel Ojeda
2025-02-19  0:58         ` H. Peter Anvin
2025-02-19  3:04           ` Boqun Feng
2025-02-19  5:07             ` NeilBrown
2025-02-19  5:39             ` Greg KH
2025-02-19 15:05               ` Laurent Pinchart
2025-02-20 20:49                 ` Lyude Paul
2025-02-21 19:24                   ` Laurent Pinchart
2025-02-20  7:03               ` Martin Uecker
2025-02-20  7:10                 ` Greg KH
2025-02-20  8:57                   ` Martin Uecker
2025-02-20 13:46                     ` Dan Carpenter
2025-02-20 14:09                       ` Martin Uecker
2025-02-20 14:38                         ` H. Peter Anvin
2025-02-20 15:25                         ` Dan Carpenter
2025-02-20 15:49                         ` Willy Tarreau
2025-02-22 15:30                         ` Kent Overstreet
2025-02-20 14:53                     ` Greg KH
2025-02-20 15:40                       ` Martin Uecker
2025-02-21  0:46                         ` Miguel Ojeda
2025-02-21  9:48                         ` Dan Carpenter
2025-02-21 16:28                           ` Martin Uecker
2025-02-21 17:43                             ` Steven Rostedt
2025-02-21 18:07                               ` Linus Torvalds
2025-02-21 18:19                                 ` Steven Rostedt
2025-02-21 18:31                                 ` Martin Uecker
2025-02-21 19:30                                   ` Linus Torvalds
2025-02-21 19:59                                     ` Martin Uecker
2025-02-21 20:11                                       ` Linus Torvalds
2025-02-22  7:20                                         ` Martin Uecker
2025-02-21 22:24                                     ` Steven Rostedt
2025-02-21 23:04                                       ` Linus Torvalds
2025-02-22 17:53                                         ` Kent Overstreet
2025-02-22 18:44                                           ` Linus Torvalds
2025-02-23 16:42                                         ` David Laight
2025-02-22 18:42                                       ` Linus Torvalds [this message]
2025-02-22  9:45                                   ` Dan Carpenter
2025-02-22 10:25                                     ` Martin Uecker
2025-02-22 11:07                                       ` Greg KH
2025-02-21 18:23                               ` Martin Uecker
2025-02-21 22:14                                 ` Steven Rostedt
2025-03-01 13:22                             ` Askar Safin
2025-03-01 13:55                               ` Martin Uecker
2025-03-02  6:50                               ` Kees Cook
2025-02-21 18:11                           ` Theodore Ts'o
2025-02-24  8:12                             ` Dan Carpenter
2025-02-20 22:08                     ` Paul E. McKenney
2025-02-22 23:42                     ` Piotr Masłowski
2025-02-23  8:10                       ` Martin Uecker
2025-02-23 23:31                       ` comex
2025-02-24  9:08                         ` Ventura Jack
2025-02-24 18:03                           ` Martin Uecker
2025-02-20 12:28               ` Jan Engelhardt
2025-02-20 12:37                 ` Greg KH
2025-02-20 13:23                   ` H. Peter Anvin
2025-02-20 13:51                     ` Willy Tarreau
2025-02-20 15:17                     ` C aggregate passing (Rust kernel policy) Jan Engelhardt
2025-02-20 16:46                       ` Linus Torvalds
2025-02-20 20:34                       ` H. Peter Anvin
2025-02-21  8:31                       ` HUANG Zhaobin
2025-02-21 18:34                       ` David Laight
2025-02-21 19:12                         ` Linus Torvalds
2025-02-21 20:07                           ` comex
2025-02-21 21:45                           ` David Laight
2025-02-22  6:32                             ` Willy Tarreau
2025-02-22  6:37                               ` Willy Tarreau
2025-02-22  8:41                                 ` David Laight
2025-02-22  9:11                                   ` Willy Tarreau
2025-02-21 20:06                         ` Jan Engelhardt
2025-02-21 20:23                           ` Laurent Pinchart
2025-02-21 20:24                             ` Laurent Pinchart
2025-02-21 22:02                             ` David Laight
2025-02-21 22:13                               ` Bart Van Assche
2025-02-22  5:56                                 ` comex
2025-02-21 20:26                           ` Linus Torvalds
2025-02-20 22:13               ` Rust kernel policy Paul E. McKenney
2025-02-21  5:19               ` Felipe Contreras
2025-02-21  5:36                 ` Boqun Feng
2025-02-21  5:59                   ` Felipe Contreras
2025-02-21  7:04                     ` Dave Airlie
2025-02-24 20:27                       ` Felipe Contreras
2025-02-24 20:37                     ` Boqun Feng
2025-02-26  2:42                       ` Felipe Contreras
2025-02-22 16:04               ` Kent Overstreet
2025-02-22 17:10                 ` Ventura Jack
2025-02-22 17:34                   ` Kent Overstreet
2025-02-23  2:08                 ` Bart Van Assche
2025-02-19  5:53             ` Alexey Dobriyan
2025-02-19  5:59           ` Dave Airlie
2025-02-22 18:46             ` Kent Overstreet
2025-02-19 12:37           ` Miguel Ojeda
2025-02-20 11:26       ` Askar Safin
2025-02-20 12:33       ` vpotach
2025-02-19 18:52     ` Kees Cook
2025-02-19 19:08       ` Steven Rostedt
2025-02-19 19:17         ` Kees Cook
2025-02-19 20:27           ` Jason Gunthorpe
2025-02-19 20:46             ` Steven Rostedt
2025-02-19 20:52               ` Bart Van Assche
2025-02-19 21:07                 ` Steven Rostedt
2025-02-20 16:05                   ` Jason Gunthorpe
2025-02-20  8:13                 ` Jarkko Sakkinen
2025-02-20  8:16                   ` Jarkko Sakkinen
2025-02-20 11:57                   ` Fiona Behrens
2025-02-20 14:07                     ` Jarkko Sakkinen
2025-02-21 10:19                       ` Jarkko Sakkinen
2025-02-22 12:10                         ` Miguel Ojeda
2025-03-04 11:17                       ` Fiona Behrens
2025-03-04 17:48                         ` Jarkko Sakkinen
2025-02-20  9:55                 ` Leon Romanovsky
2025-02-19 19:33       ` H. Peter Anvin
2025-02-20  6:32         ` Alexey Dobriyan
2025-02-20  6:53           ` Greg KH
2025-02-20  8:44             ` Alexey Dobriyan
2025-02-20 13:53             ` Willy Tarreau
2025-02-20 16:04             ` Jason Gunthorpe
2025-02-20 12:01           ` H. Peter Anvin
2025-02-20 12:13             ` H. Peter Anvin
2025-02-20 23:42         ` Miguel Ojeda
2025-02-22 15:21           ` Kent Overstreet
2025-02-20  6:42     ` Christoph Hellwig
2025-02-20 23:44       ` Miguel Ojeda
2025-02-21 15:24         ` Simona Vetter
2025-02-22 12:10           ` Miguel Ojeda
2025-02-26 13:17           ` Fiona Behrens
2025-02-21  0:39       ` Linus Torvalds
2025-02-21 12:16         ` Danilo Krummrich
2025-02-21 15:59           ` Steven Rostedt
2025-02-23 18:03           ` Laurent Pinchart
2025-02-23 18:31             ` Linus Torvalds
2025-02-26 16:05               ` Jason Gunthorpe
2025-02-26 19:32                 ` Linus Torvalds
2025-02-19  8:05   ` Dan Carpenter
2025-02-19 14:14     ` James Bottomley
2025-02-19 14:30       ` Geert Uytterhoeven
2025-02-19 14:46       ` Martin K. Petersen
2025-02-19 14:51         ` Bartosz Golaszewski
2025-02-19 15:15         ` James Bottomley
2025-02-19 15:33           ` Willy Tarreau
2025-02-19 15:45             ` Laurent Pinchart
2025-02-19 15:46             ` James Bottomley
2025-02-19 15:56               ` Willy Tarreau
2025-02-19 16:07                 ` Laurent Pinchart
2025-02-19 16:15                   ` Willy Tarreau
2025-02-19 16:32                     ` Laurent Pinchart
2025-02-19 16:34                       ` Willy Tarreau
2025-02-19 16:33                     ` Steven Rostedt
2025-02-19 16:47                       ` Andrew Lunn
2025-02-19 18:22                       ` Jarkko Sakkinen
2025-02-20  6:26                       ` Alexey Dobriyan
2025-02-20 15:37                         ` Steven Rostedt
2025-02-19 17:00           ` Martin K. Petersen
2025-02-19 15:13       ` Steven Rostedt
2025-02-19 14:05   ` James Bottomley
2025-02-19 15:08     ` Miguel Ojeda
2025-02-19 16:03       ` James Bottomley
2025-02-19 16:44         ` Miguel Ojeda
2025-02-19 17:06           ` Theodore Ts'o
2025-02-20 23:40             ` Miguel Ojeda
2025-02-22 15:03             ` Kent Overstreet
2025-02-20 16:03           ` James Bottomley
2025-02-20 23:47             ` Miguel Ojeda
2025-02-20  6:48         ` Christoph Hellwig
2025-02-20 12:56           ` James Bottomley

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAHk-=wjQCbRA1UEag-1-9yn08KNNqerTj++SCbbW80At=rg5RQ@mail.gmail.com' \
    --to=torvalds@linux-foundation.org \
    --cc=airlied@gmail.com \
    --cc=axboe@kernel.dk \
    --cc=boqun.feng@gmail.com \
    --cc=dan.carpenter@linaro.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=hch@infradead.org \
    --cc=hpa@zytor.com \
    --cc=ksummit@lists.linux.dev \
    --cc=linux-kernel@vger.kernel.org \
    --cc=miguel.ojeda.sandonis@gmail.com \
    --cc=rostedt@goodmis.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=uecker@tugraz.at \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).