diff mbox

[3/8] 9pfs: fix P9_NOTAG and P9_NOFID macros

Message ID 148127568042.2633.5084932697061472826.stgit@bahia
State New
Headers show

Commit Message

Greg Kurz Dec. 9, 2016, 9:28 a.m. UTC
The u16 and u32 types don't exist in QEMU common headers. It never broke
build because these two macros aren't use by the current code, but this
is about to change with the future addition of functional tests for 9P.

This patch convert the types to uintXX_t.

Signed-off-by: Greg Kurz <groug@kaod.org>
---
 hw/9pfs/9p.h |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Comments

Eric Blake Dec. 9, 2016, 9:25 p.m. UTC | #1
On 12/09/2016 03:28 AM, Greg Kurz wrote:
> The u16 and u32 types don't exist in QEMU common headers. It never broke
> build because these two macros aren't use by the current code, but this
> is about to change with the future addition of functional tests for 9P.
> 
> This patch convert the types to uintXX_t.
> 
> Signed-off-by: Greg Kurz <groug@kaod.org>
> ---
>  hw/9pfs/9p.h |    4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h
> index 3976b7fe3dcd..89c904bdb7e7 100644
> --- a/hw/9pfs/9p.h
> +++ b/hw/9pfs/9p.h
> @@ -99,8 +99,8 @@ enum p9_proto_version {
>      V9FS_PROTO_2000L = 0x02,
>  };
>  
> -#define P9_NOTAG    (u16)(~0)
> -#define P9_NOFID    (u32)(~0)
> +#define P9_NOTAG    (uint16_t)(~0)
> +#define P9_NOFID    (uint32_t)(~0)

Don't you want to write ((uint16_t)(~0)), to ensure that this expression
can be used as a drop-in in any other syntactical situation?

Or even write it as UINT16_C(~0) (using <stdint.h>), or as UINT16_MAX.
(Be aware: the type of (uint16_t)(~0) is uint16_t, while the type of
UINT16_MAX is int, due to the rules of integer promotion, if that matters)
Greg Kurz Dec. 10, 2016, 1:57 p.m. UTC | #2
On Fri, 9 Dec 2016 15:25:55 -0600
Eric Blake <eblake@redhat.com> wrote:

> On 12/09/2016 03:28 AM, Greg Kurz wrote:
> > The u16 and u32 types don't exist in QEMU common headers. It never broke
> > build because these two macros aren't use by the current code, but this
> > is about to change with the future addition of functional tests for 9P.
> > 
> > This patch convert the types to uintXX_t.
> > 
> > Signed-off-by: Greg Kurz <groug@kaod.org>
> > ---
> >  hw/9pfs/9p.h |    4 ++--
> >  1 file changed, 2 insertions(+), 2 deletions(-)
> > 
> > diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h
> > index 3976b7fe3dcd..89c904bdb7e7 100644
> > --- a/hw/9pfs/9p.h
> > +++ b/hw/9pfs/9p.h
> > @@ -99,8 +99,8 @@ enum p9_proto_version {
> >      V9FS_PROTO_2000L = 0x02,
> >  };
> >  
> > -#define P9_NOTAG    (u16)(~0)
> > -#define P9_NOFID    (u32)(~0)
> > +#define P9_NOTAG    (uint16_t)(~0)
> > +#define P9_NOFID    (uint32_t)(~0)  
> 
> Don't you want to write ((uint16_t)(~0)), to ensure that this expression
> can be used as a drop-in in any other syntactical situation?
> 

These defines come from the linux kernel sources and I must admit it
didn't cross my mind... can you share a case where this would cause
troubles ?

> Or even write it as UINT16_C(~0) (using <stdint.h>), or as UINT16_MAX.
> (Be aware: the type of (uint16_t)(~0) is uint16_t, while the type of
> UINT16_MAX is int, due to the rules of integer promotion, if that matters)
> 

UINT16_C(~0) expands to ~0 and UINT16_MAX expands to (65535), at least on
my laptop (glibc-headers-2.23.1-11.fc24.x86_64)... doesn't that mean the
type of UINT16_C(~0) is also int ? Please enlighten me.

The 9P spec at http://man.cat-v.org/plan_9/5/version says "(ushort)~0". My
understanding is 16 bits all ones. I guess I'd rather then go for
((uint16_t)(~0)).

Thanks!

--
Greg
Eric Blake Dec. 10, 2016, 4:24 p.m. UTC | #3
On 12/10/2016 07:57 AM, Greg Kurz wrote:

>>> -#define P9_NOTAG    (u16)(~0)
>>> -#define P9_NOFID    (u32)(~0)
>>> +#define P9_NOTAG    (uint16_t)(~0)
>>> +#define P9_NOFID    (uint32_t)(~0)  
>>
>> Don't you want to write ((uint16_t)(~0)), to ensure that this expression
>> can be used as a drop-in in any other syntactical situation?
>>
> 
> These defines come from the linux kernel sources and I must admit it
> didn't cross my mind... can you share a case where this would cause
> troubles ?

Unlikely to occur in real code, but:

  int a[] = { -2, -3 };
  int *b = a + 1;
  printf("%d\n", (uint16_t)(~0)[b]); // prints 65534 - let's see why?

  // prints 65534, or the result of b[-1] cast to uint16_t
  printf("%d\n", (uint16_t)((~0)[b]));

  // probably dumps core, as b[65535] is out of bounds
  printf("%d\n", ((uint16_t)(~0))[b]);

that is, since [] has higher precedence than casts, failure to
parenthesize a cast will change the interpretation of P9_NOTAG[pointer].

And yes, if you copied from the kernel, that means the kernel has a bug
(even if it is unlikely to trip up normal code).


> 
>> Or even write it as UINT16_C(~0) (using <stdint.h>), or as UINT16_MAX.
>> (Be aware: the type of (uint16_t)(~0) is uint16_t, while the type of
>> UINT16_MAX is int, due to the rules of integer promotion, if that matters)
>>
> 
> UINT16_C(~0) expands to ~0 and UINT16_MAX expands to (65535), at least on
> my laptop (glibc-headers-2.23.1-11.fc24.x86_64)... doesn't that mean the
> type of UINT16_C(~0) is also int ? Please enlighten me.

Indeed, UINT16_C produces an int constant, not uint16_t (since there is
no such thing as a uint16_t constant).  So the cast is the only way to
force ~0 to be truncated to a 16-bit pattern.  But using UINT16_MAX is
probably just fine, as it is the all-ones value with the correct integer
promotion for use in any other arithmetic.

> 
> The 9P spec at http://man.cat-v.org/plan_9/5/version says "(ushort)~0". My
> understanding is 16 bits all ones. I guess I'd rather then go for
> ((uint16_t)(~0)).

Verbose, but works, as does UINT16_MAX.  But I stand corrected that
UINT16_C(~0) does not work.
Greg Kurz Dec. 10, 2016, 11:03 p.m. UTC | #4
On Sat, 10 Dec 2016 10:24:35 -0600
Eric Blake <eblake@redhat.com> wrote:

> On 12/10/2016 07:57 AM, Greg Kurz wrote:
> 
> >>> -#define P9_NOTAG    (u16)(~0)
> >>> -#define P9_NOFID    (u32)(~0)
> >>> +#define P9_NOTAG    (uint16_t)(~0)
> >>> +#define P9_NOFID    (uint32_t)(~0)    
> >>
> >> Don't you want to write ((uint16_t)(~0)), to ensure that this expression
> >> can be used as a drop-in in any other syntactical situation?
> >>  
> > 
> > These defines come from the linux kernel sources and I must admit it
> > didn't cross my mind... can you share a case where this would cause
> > troubles ?  
> 
> Unlikely to occur in real code, but:
> 
>   int a[] = { -2, -3 };
>   int *b = a + 1;
>   printf("%d\n", (uint16_t)(~0)[b]); // prints 65534 - let's see why?
> 
>   // prints 65534, or the result of b[-1] cast to uint16_t
>   printf("%d\n", (uint16_t)((~0)[b]));
> 
>   // probably dumps core, as b[65535] is out of bounds
>   printf("%d\n", ((uint16_t)(~0))[b]);
> 
> that is, since [] has higher precedence than casts, failure to
> parenthesize a cast will change the interpretation of P9_NOTAG[pointer].
> 

... which is indeed very unlikely to happen even if it is legit. :)

> And yes, if you copied from the kernel, that means the kernel has a bug
> (even if it is unlikely to trip up normal code).
> 

I'll send a patch there too.

> 
> >   
> >> Or even write it as UINT16_C(~0) (using <stdint.h>), or as UINT16_MAX.
> >> (Be aware: the type of (uint16_t)(~0) is uint16_t, while the type of
> >> UINT16_MAX is int, due to the rules of integer promotion, if that matters)
> >>  
> > 
> > UINT16_C(~0) expands to ~0 and UINT16_MAX expands to (65535), at least on
> > my laptop (glibc-headers-2.23.1-11.fc24.x86_64)... doesn't that mean the
> > type of UINT16_C(~0) is also int ? Please enlighten me.  
> 
> Indeed, UINT16_C produces an int constant, not uint16_t (since there is
> no such thing as a uint16_t constant).  So the cast is the only way to
> force ~0 to be truncated to a 16-bit pattern.  But using UINT16_MAX is
> probably just fine, as it is the all-ones value with the correct integer
> promotion for use in any other arithmetic.
> 
> > 
> > The 9P spec at http://man.cat-v.org/plan_9/5/version says "(ushort)~0". My
> > understanding is 16 bits all ones. I guess I'd rather then go for
> > ((uint16_t)(~0)).  
> 
> Verbose, but works, as does UINT16_MAX.  But I stand corrected that
> UINT16_C(~0) does not work.
> 

Ok, I'll go the UINT16_MAX way then.

Thanks for the detailed explanation.

Cheers.

--
Greg
diff mbox

Patch

diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h
index 3976b7fe3dcd..89c904bdb7e7 100644
--- a/hw/9pfs/9p.h
+++ b/hw/9pfs/9p.h
@@ -99,8 +99,8 @@  enum p9_proto_version {
     V9FS_PROTO_2000L = 0x02,
 };
 
-#define P9_NOTAG    (u16)(~0)
-#define P9_NOFID    (u32)(~0)
+#define P9_NOTAG    (uint16_t)(~0)
+#define P9_NOFID    (uint32_t)(~0)
 #define P9_MAXWELEM 16
 
 #define FID_REFERENCED          0x1