Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 4 Mar 2013 08:10:01 GMT
From:      Bruce Evans <brde@optusnet.com.au>
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: misc/176628: [stdint.h] use safer way of definint __WORDSIZE
Message-ID:  <201303040810.r248A19V095487@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/176628; it has been noted by GNATS.

From: Bruce Evans <brde@optusnet.com.au>
To: Dmitry Marakasov <amdmi3@FreeBSD.org>
Cc: FreeBSD-gnats-submit@FreeBSD.org, freebsd-bugs@FreeBSD.org
Subject: Re: misc/176628: [stdint.h] use safer way of definint __WORDSIZE
Date: Mon, 4 Mar 2013 19:04:12 +1100 (EST)

 On Mon, 4 Mar 2013, Dmitry Marakasov wrote:
 
 >> Description:
 > r228529 introduced __WORDSIZE macro:
 >
 > --- sys/sys/stdint.h
 > +#if defined(UINTPTR_MAX) && defined(UINT64_MAX) && (UINTPTR_MAX == UINT64_MAX)
 > +#define	__WORDSIZE		64
 > +#else
 > +#define	__WORDSIZE		32
 > +#endif
 > ---
 >
 > However the way it's defined is utterly unsafe: when UINTPTR_MAX or UINT64_MAX are not defined (which is the case for C++, as their definitions in e.g. x86/_stint.h are wrapped in
 
 Please use the unix newline character.
 
 UINTPTR_MAX and UINT64_MAX are always defined here.  Except for C++ :-(.
 So the `if defined()' parts of the ifdef are basically...
 
 >
 > #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
 
 ... an obfuscated version of this ifdef.
 
 The ifdef is also utterly unportable. It assumes various things about
 pointers and integer sizes.
 
 It also has many style bugs (excessive parentheses, and I don't like
 supporting non-C compilers (cc -Wundef).  It's interesting that the
 ifdefs to support non-C compilers just break their warning about
 UINTPTR_MAX and UINT64_MAX being 0 in the cpp expression when they are
 not defined.  They are still used when they are not defined, but now
 via tests for them being defined and doing a wrong thing when they are
 not defined).
 
 > __WORDSIZE is always defined as 32, which is wrong on 64bit systems.
 >
 > I have two solutions for the problem.
 > First one uses the same way of testing for 64bit pointers, but doesn't define __WORDSIZE if it can't be detected reliably.
 
 C++ code should be happier with __WORDSIZE being undefined that with it
 being defined to garbage.
 
 > Second one uses different way of testing for 64bit pointers with checking for __LP64__.
 >
 > The second one looks much more useful, but I'm not sure if __LP64__ has the right semantics and will work in all platforms.
 
 Not right, but better than the UINTPTR_MAX test.  Both are broken and default
 to __WORDSIZE == 32 if pointers are not precisely 64 bits.  Actually, the
 __LP64__ test is more fragile, since it fails if __L32_P64__ and many systems
 use that.  Just not any FreeBSD systems, so it is valid to use a hackish
 ifdef that only works on current FreeBSD systems.
 
 > Also, can't it just be unconditionally defined to (sizeof(int*)*8)?
 
 No one knows, since __WORDSIZE is nonstandard.  But other macros for
 integer sizes are specified by standards to work in cpp expressions,
 and sizeof() would break that.  stdint.h would be much simpler if
 sizeof() and casts worked right (cpp should be part of the compiler).
 
 > diff --git sys/sys/stdint.h sys/sys/stdint.h
 > index 762e879..de10869 100644
 > --- sys/sys/stdint.h
 > +++ sys/sys/stdint.h
 > @@ -65,10 +65,12 @@ typedef	__uintmax_t		uintmax_t;
 > #endif
 >
 > /* GNU and Darwin define this and people seem to think it's portable */
 
 The comment has another style bug.
 
 > -#if defined(UINTPTR_MAX) && defined(UINT64_MAX) && (UINTPTR_MAX == UINT64_MAX)
 > -#define	__WORDSIZE		64
 > -#else
 > -#define	__WORDSIZE		32
 > +#if defined(UINTPTR_MAX) && defined(UINT64_MAX)
 > +# if UINTPTR_MAX == UINT64_MAX
 > +#  define	__WORDSIZE		64
 > +# else
 > +#  define	__WORDSIZE		32
 > +# endif
 > #endif
 
 This adds many style bugs in the ifdefs.
 
 >
 > /* Limits of wchar_t. */
 > --- wordsize.patch ends here ---
 >
 > --- wordsize.1.patch begins here ---
 > diff --git sys/sys/stdint.h sys/sys/stdint.h
 > index 762e879..b921b99 100644
 > --- sys/sys/stdint.h
 > +++ sys/sys/stdint.h
 > @@ -65,7 +65,7 @@ typedef	__uintmax_t		uintmax_t;
 > #endif
 >
 > /* GNU and Darwin define this and people seem to think it's portable */
 > -#if defined(UINTPTR_MAX) && defined(UINT64_MAX) && (UINTPTR_MAX == UINT64_MAX)
 > +#if defined(__LP64__)
 > #define	__WORDSIZE		64
 > #else
 > #define	__WORDSIZE		32
 > --- wordsize.1.patch ends here ---
 
 Better.  The only new style bug is `if defined()' instead of ifdef.
 
 clang pre-declares zillions of variable sizes: on amd64
 
 % #define __SIG_ATOMIC_WIDTH__ 32
 % #define __SIZEOF_DOUBLE__ 8
 % #define __SIZEOF_FLOAT__ 4
 % #define __SIZEOF_INT__ 4
 % #define __SIZEOF_LONG_DOUBLE__ 16
 % #define __SIZEOF_LONG_LONG__ 8
 % #define __SIZEOF_LONG__ 8
 % #define __SIZEOF_POINTER__ 8
 % #define __SIZEOF_PTRDIFF_T__ 8
 % #define __SIZEOF_SHORT__ 2
 % #define __SIZEOF_SIZE_T__ 8
 % #define __SIZEOF_WCHAR_T__ 4
 % #define __SIZEOF_WINT_T__ 4
 % #define __SIZE_TYPE__ long unsigned int
 % #define __SIZE_WIDTH__ 64
 % #define __WCHAR_TYPE__ int
 % #define __WCHAR_WIDTH__ 32
 % #define __WINT_WIDTH__ 32
 
 but these are almost useless since they are unportable (most use of __FOO
 give undefined behaviour).  Most or all of these are not pre-defined by
 gcc, so even the implementation cannot use them.
 
 __SIG_ATOMIC_WIDTH__ is also broken.  sig_atomic_t has always been long
 for amd64 in FreeBSD.  SIG_ATOMIC_MAX/MIN used to be inconsistent with
 sig_atomic_t for amd64 (they were INT32_MAX/MIN), but someone fixed that
 without changing clang, so clang is now wrong for the MAX/MIN too.
 
 Anyway, none of the above obviously has the same semantics as __WORDSIZE.
 __SIZEOF_POINTER__ is closest.
 
 The wchar_t and wint_t are more variable than all of the other types
 supported by the above, and the definitions for them could be used to
 replace various ifdefs, but again the above support for them isn't
 pre-defined by gcc.  gcc pre-defines __WCHAR_TYPE__, __WINT_TYPE__
 and __WCHAR_MAX__.  __WCHAR_WIDTH__ can be decoded from the latter,
 but there is nothing similar for __WINT_MAX__.
 
 Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201303040810.r248A19V095487>