Bug 2841 - stdint.h misdefines UINT8_C and UINT16_C to append U
Summary: stdint.h misdefines UINT8_C and UINT16_C to append U
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.4
: P2 normal
Target Milestone: ---
Assignee: Ulrich Drepper
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-06-24 06:35 UTC by Paul Eggert
Modified: 2019-08-08 22:31 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments
UINT8_C and UINT16_C should not append U (352 bytes, patch)
2006-06-24 06:36 UTC, Paul Eggert
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Paul Eggert 2006-06-24 06:35:40 UTC
C99 7.18.4.1 (as revised by ISO/IEC 9899:1999/Cor.1:2001) says that
UINT8_C and UINT16_C return values corresponding to uint_least8_t and
uint_least16_t.  They therefore must promote the same way.  But glibc
appends 'U', which causes UINT8_C and UINT16_C to promote to 'unsigned
int', not 'int'.  Here is a test program illustrating the bug: it
strictly conforms to the C99 but GCC + glibc reject it.  I'll attach
the obvious patch.

#include <stdint.h>
char test1[(-1 < UINT8_C (0)) == (-1 < (uint_least8_t) 0) ? 1 : -1];
char test2[(-1 < UINT16_C (0)) == (-1 < (uint_least16_t) 0) ? 1 : -1];
Comment 1 Paul Eggert 2006-06-24 06:36:20 UTC
Created attachment 1121 [details]
UINT8_C and UINT16_C should not append U
Comment 2 Ulrich Drepper 2006-08-12 21:23:18 UTC
The specificaiton is broken one way or another so I don't really care.  The
patch is in cvs.
Comment 3 Clément 2019-08-08 18:19:57 UTC
Paul, wouldn't it be better to also include a cast to uint_least8_t in that macro (that's what other libcs do, AFAICT)?  Right now UINTC_8(-1) produces an negative int, which is rather surprising.
Comment 4 Andreas Schwab 2019-08-08 18:47:07 UTC
UINTC_8(-1) is undefined.
Comment 5 Florian Weimer 2019-08-08 18:51:09 UTC
(In reply to Clément from comment #3)
> Paul, wouldn't it be better to also include a cast to uint_least8_t in that
> macro (that's what other libcs do, AFAICT)?  Right now UINTC_8(-1) produces
> an negative int, which is rather surprising.

I think the cast would be incorrect according to C11 because the “type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions.”  I think a definition like

  #define UINTC_8(c) ((uint_least_8_t) +(c))

wouldn't satisfy the requirement.  (The + is needed so that the expression can be used in an #if preprocessor context, as required.)

musl and bionic have the same definition as glibc.  The FreeBSD definition adds parentheses, but still has no cast.
Comment 6 Clément 2019-08-08 22:31:14 UTC
(In reply to Florian Weimer from comment #5)
> I think the cast would be incorrect according to C11 because the “type of
> the expression shall have the same type as would an expression of the
> corresponding type converted according to the integer promotions.”  I think
> a definition like
> 
>   #define UINTC_8(c) ((uint_least_8_t) +(c))
> 
> wouldn't satisfy the requirement.  (The + is needed so that the expression
> can be used in an #if preprocessor context, as required.)

Interesting, thanks a lot. I had checked AVR-libc and QP/C++, which use ((uint8_t) __CONCAT(value, U)) and (static_cast<std::uint8_t>(x_)) respectively.