public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Alexei Fedorov <Alexei.Fedorov@arm.com>
To: "Cohen, Eugene" <eugene@hp.com>,
	"edk2-devel@lists.01.org" <edk2-devel@lists.01.org>,
	"Kinney, Michael D" <michael.d.kinney@intel.com>
Subject: Re: What is the right way to print a UINTN?
Date: Mon, 26 Sep 2016 14:39:46 +0000	[thread overview]
Message-ID: <AM5PR0801MB1955495ACF3F587353DA7F259ACD0@AM5PR0801MB1955.eurprd08.prod.outlook.com> (raw)
In-Reply-To: <AT5PR84MB0291232000D2209AD7B53D52B4CD0@AT5PR84MB0291.NAMPRD84.PROD.OUTLOOK.COM>

I raised this issue a few years ago & was advised to use %p notation.

Alexei.

-----Original Message-----
From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Cohen, Eugene
Sent: 26 September 2016 14:46
To: edk2-devel@lists.01.org; Kinney, Michael D
Subject: [edk2] What is the right way to print a UINTN?

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



_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.



  reply	other threads:[~2016-09-26 14:39 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-09-26 13:46 What is the right way to print a UINTN? Cohen, Eugene
2016-09-26 14:39 ` Alexei Fedorov [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=AM5PR0801MB1955495ACF3F587353DA7F259ACD0@AM5PR0801MB1955.eurprd08.prod.outlook.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox