public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* What is the right way to print a UINTN?
@ 2016-09-26 13:46 Cohen, Eugene
  2016-09-26 14:39 ` Alexei Fedorov
  2016-09-26 15:31 ` Laszlo Ersek
  0 siblings, 2 replies; 16+ messages in thread
From: Cohen, Eugene @ 2016-09-26 13:46 UTC (permalink / raw)
  To: edk2-devel@lists.01.org, Kinney, Michael D

Get ready for a potentially stupid question (or at least a question I probably should know the answer to by now)...

The implementation of BasePrintLib treats types like %d and %x as the size of the compiler's "int" type.  On many 64-bit architectures the size of int is 32-bits.  On these same architectures we declare a "UINTN" type as 64-bits.

The handling for integral types (%d, %x, %u, etc) in BasePrintLib is as follows, note the use of 'int':

          if (BaseListMarker == NULL) {
            Value = VA_ARG (VaListMarker, int);
          } else {
            Value = BASE_ARG (BaseListMarker, int);
          }

So it would seem to be improper to try to Print/DEBUG a UINTN value with %d/%u/%x since the size will be mismatched on some architecture (INTN 64 bits, int 32 bits).  But it also would be improper to try to print this as %ld/%lx because the size will be mismatched on 32-bit architectures (INTN 32 bits and print will use a INT64 with the 'l' prefix).  It's not obvious then how to create a portable format specifier that works for UINTN.

I did some research in how this is handled in edk2 for modules we know to be portable and I see multiple conflicting techniques being used.  The predominant pattern for this is to try to print a UINTN parameter with the %d/%x format specifier anyways like this:

  DEBUG ((EFI_D_ERROR, "FATAL ERROR - RaiseTpl with OldTpl(0x%x) > NewTpl(0x%x)\n", OldTpl, NewTpl));

in this case the parameter if EFI_TPL which was typedef'ed as a UINTN.  In this case the compiler does the variadic thing and on a 64-bit architecture puts a 64-bit UINTN on the variadic stack (using the term stack in the abstract sense here).

When the print code tries to pop it off the stack using VA_ARG (VaListMarker, int) the 'int' gets upgraded in size to UINTN due to this construct in Base.h (I'm using GCC):

  #define VA_ARG(Marker, TYPE)         ((sizeof (TYPE) < sizeof (UINTN)) ? (TYPE)(__builtin_va_arg (Marker, UINTN)) : (TYPE)(__builtin_va_arg (Marker, TYPE)))

since sizeof(int) is 4 and this is less than sizeof(UINTN) at 8 the result will be  (TYPE)(__builtin_va_arg (Marker, UINTN)) where TYPE is 'int'.  So we end up popping 64-bits off the varidic stack but immediately typecast it to an int (4 byte) resulting in loss of the upper-64 bits.  If I'm reading this right it means we can only print UINTNs whose value is below 2^32 (confirmed with a debugger on AArch64 using GCC).  Maybe this seems benign for the simple EFI_TPL enumeration but if for some reason you add a new value that exceeds 2^32-1 then the print code is broken.  Is every user of Print/DEBUG expected understand this range limitation?


What is the preferred pattern for printing a INTN/UINTN then?  Two yucky hacks I can think of: upcasting to UINT64/%ld when you "know" the value may exceed 2^32-1 or using %p for non-pointer types since this happens to get the right size treatment although we lose formatting options.

Eugene





^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2016-09-27 20:27 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-09-26 13:46 What is the right way to print a UINTN? Cohen, Eugene
2016-09-26 14:39 ` Alexei Fedorov
2016-09-26 15:31 ` Laszlo Ersek
2016-09-27 12:29   ` Cohen, Eugene
2016-09-27 14:30     ` Laszlo Ersek
2016-09-27 16:03       ` Cohen, Eugene
2016-09-27 16:31         ` Laszlo Ersek
2016-09-27 16:47         ` Andrew Fish
2016-09-27 17:14           ` Brian J. Johnson
2016-09-27 18:31             ` Laszlo Ersek
2016-09-27 20:27             ` Kinney, Michael D
2016-09-27 17:27           ` Kinney, Michael D
2016-09-27 17:46             ` Andrew Fish
2016-09-27 18:20               ` Kinney, Michael D
2016-09-27 19:28             ` Cohen, Eugene
2016-09-27 20:10               ` Kinney, Michael D

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox