2008-09-12 02:13:21

by Larry Finger

[permalink] [raw]
Subject: I need help with a sparse warning

In file drivers/net/wireless/p54/p54common.c, the statement

priv->rx_mtu = (size_t) le16_to_cpu((__le16)bootrec->data[10]);

generates the sparse warning

.../p54common.c:185:29: warning: cast to restricted __le16

where bootrec->data is u32, and priv->rx_mtu is u16.

What should be done to eliminate this warning?

Thanks,

Larry



2008-09-12 02:58:24

by Larry Finger

[permalink] [raw]
Subject: Re: I need help with a sparse warning

Steven Noonan wrote:
> On Thu, Sep 11, 2008 at 7:13 PM, Larry Finger <[email protected]> wrote:
>> In file drivers/net/wireless/p54/p54common.c, the statement
>>
>> priv->rx_mtu = (size_t) le16_to_cpu((__le16)bootrec->data[10]);
>>
>> generates the sparse warning
>>
>> .../p54common.c:185:29: warning: cast to restricted __le16
>>
>> where bootrec->data is u32, and priv->rx_mtu is u16.
>>
>
> (Whoops, didn't CC the mailing lists. Sorry about the double-message, Larry.)
>
> If priv->rx_mtu is u16, I'm surprised it doesn't get noisy about the
> size_t cast. Unless the machine it's being compiled on is 16-bit, that
> should throw a truncation warning, because size_t should be a 32-bit
> integer on 32-bit machines (typically).
>
> I think if you change the (__le16) cast to (__le16 __force) it will
> stop warning you about that particular issue.

This one gets rid of the sparse warning.

priv->rx_mtu = le16_to_cpu((__le16 __force)
bootrec->data[10]);

Thanks,

Larry

2008-09-12 02:32:39

by Steven Noonan

[permalink] [raw]
Subject: Re: I need help with a sparse warning

On Thu, Sep 11, 2008 at 7:13 PM, Larry Finger <[email protected]> wrote:
> In file drivers/net/wireless/p54/p54common.c, the statement
>
> priv->rx_mtu = (size_t) le16_to_cpu((__le16)bootrec->data[10]);
>
> generates the sparse warning
>
> .../p54common.c:185:29: warning: cast to restricted __le16
>
> where bootrec->data is u32, and priv->rx_mtu is u16.
>

(Whoops, didn't CC the mailing lists. Sorry about the double-message, Larry.)

If priv->rx_mtu is u16, I'm surprised it doesn't get noisy about the
size_t cast. Unless the machine it's being compiled on is 16-bit, that
should throw a truncation warning, because size_t should be a 32-bit
integer on 32-bit machines (typically).

I think if you change the (__le16) cast to (__le16 __force) it will
stop warning you about that particular issue.

- Steven

2008-09-12 17:12:16

by Pavel Roskin

[permalink] [raw]
Subject: Re: I need help with a sparse warning

On Thu, 2008-09-11 at 22:05 -0500, Larry Finger wrote:
> > I would guess you want something like:
> >
> > priv->rx_mtu = le16_to_cpu(((__force __le16 *) bootrec->data)[20]);
> >
> > (__force is what shuts up sparse, and as far as I can see, the size_t
> > cast is useless, since the result will be promoted anyway)
>
> Yes, that one works. As you suspected, this section is parsing data
> from the firmware.

I believe __force should be the last resort. If you want to read a
16-bit little endian value at the given offset, I suggest that you use
le16_to_cpup(), which operates on pointers and does the cast for you.

A better but more elaborate solution would be to define a structure that
would have __le16 rx_mtu at the offset 40. Then you can cast bootrec to
that structure and apply le16_to_cpu() to that field.

--
Regards,
Pavel Roskin

2008-09-12 03:05:02

by Larry Finger

[permalink] [raw]
Subject: Re: I need help with a sparse warning

Roland Dreier wrote:
> > In file drivers/net/wireless/p54/p54common.c, the statement
> >
> > priv->rx_mtu = (size_t) le16_to_cpu((__le16)bootrec->data[10]);
>
> [I don't see this code in Linus's tree]

It is in wireless-testing.

>
> the code in question looks buggy to me. Since bootrec->data[10] is u32,
> casting it to a 16-bit type is going to take a different 2 bytes out of
> the 4 bytes depending on the endianness of the system the driver is
> built for. And I assume you are parsing some fixed-layout thing that
> the firmware is giving you or something like that.
>
> I would guess you want something like:
>
> priv->rx_mtu = le16_to_cpu(((__force __le16 *) bootrec->data)[20]);
>
> (__force is what shuts up sparse, and as far as I can see, the size_t
> cast is useless, since the result will be promoted anyway)

Yes, that one works. As you suspected, this section is parsing data
from the firmware.

When I started, there were 18 sparse warnings, and a number of them
were accesses of little-endian variables without an appropriate
leXX_to_cpu() conversion. Obviously, this code has never been tested
on a big-endian machine.

Thanks,

Larry


2008-09-12 02:40:51

by Roland Dreier

[permalink] [raw]
Subject: Re: I need help with a sparse warning

> In file drivers/net/wireless/p54/p54common.c, the statement
>
> priv->rx_mtu = (size_t) le16_to_cpu((__le16)bootrec->data[10]);

[I don't see this code in Linus's tree]

>
> generates the sparse warning
>
> .../p54common.c:185:29: warning: cast to restricted __le16
>
> where bootrec->data is u32, and priv->rx_mtu is u16.
>
> What should be done to eliminate this warning?

the code in question looks buggy to me. Since bootrec->data[10] is u32,
casting it to a 16-bit type is going to take a different 2 bytes out of
the 4 bytes depending on the endianness of the system the driver is
built for. And I assume you are parsing some fixed-layout thing that
the firmware is giving you or something like that.

I would guess you want something like:

priv->rx_mtu = le16_to_cpu(((__force __le16 *) bootrec->data)[20]);

(__force is what shuts up sparse, and as far as I can see, the size_t
cast is useless, since the result will be promoted anyway)

- R.

2008-09-12 03:07:34

by Larry Finger

[permalink] [raw]
Subject: Re: I need help with a sparse warning

Roland Dreier wrote:
> > This one gets rid of the sparse warning.
> >
> > priv->rx_mtu = le16_to_cpu((__le16 __force)
> > bootrec->data[10]);
>
> Yes but does it actually work on both big and little endian systems?
> (See my previous email)

I don't know, but as my previous email stated, the code could not
possibly have worked on a big-endian system before I started the
sparse cleanup. I don't have access to anything but little-endian
hardware.

Larry

2008-09-12 15:25:45

by Michael Büsch

[permalink] [raw]
Subject: Re: I need help with a sparse warning

On Friday 12 September 2008, Larry Finger wrote:
> Steven Noonan wrote:
> > On Thu, Sep 11, 2008 at 7:13 PM, Larry Finger <[email protected]> wrote:
> >> In file drivers/net/wireless/p54/p54common.c, the statement
> >>
> >> priv->rx_mtu = (size_t) le16_to_cpu((__le16)bootrec->data[10]);
> >>
> >> generates the sparse warning
> >>
> >> .../p54common.c:185:29: warning: cast to restricted __le16
> >>
> >> where bootrec->data is u32, and priv->rx_mtu is u16.
> >>
> >
> > (Whoops, didn't CC the mailing lists. Sorry about the double-message, Larry.)
> >
> > If priv->rx_mtu is u16, I'm surprised it doesn't get noisy about the
> > size_t cast. Unless the machine it's being compiled on is 16-bit, that
> > should throw a truncation warning, because size_t should be a 32-bit
> > integer on 32-bit machines (typically).
> >
> > I think if you change the (__le16) cast to (__le16 __force) it will
> > stop warning you about that particular issue.
>
> This one gets rid of the sparse warning.
>
> priv->rx_mtu = le16_to_cpu((__le16 __force)
> bootrec->data[10]);

I think you should rather fix the type of bootrec->data.
If it is u32, but the data in fact is __le16, please fix the struct instead
of adding dangerous casts.
Note that this is especially dangerous, because you cast between different
typesizes and endianesses at the same time.

2008-09-12 03:04:40

by Roland Dreier

[permalink] [raw]
Subject: Re: I need help with a sparse warning

> This one gets rid of the sparse warning.
>
> priv->rx_mtu = le16_to_cpu((__le16 __force)
> bootrec->data[10]);

Yes but does it actually work on both big and little endian systems?
(See my previous email)

- R.

2008-09-12 02:42:17

by Alexey Dobriyan

[permalink] [raw]
Subject: Re: I need help with a sparse warning

On Thu, Sep 11, 2008 at 09:13:20PM -0500, Larry Finger wrote:
> In file drivers/net/wireless/p54/p54common.c, the statement
>
> priv->rx_mtu = (size_t) le16_to_cpu((__le16)bootrec->data[10]);
>
> generates the sparse warning
>
> .../p54common.c:185:29: warning: cast to restricted __le16
>
> where bootrec->data is u32, and priv->rx_mtu is u16.
>
> What should be done to eliminate this warning?

What is the intent?

MTU is 2-byte little-endian starting at 40-th byte?

Oh, and size_t cast is pointless.