boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

018-printf-int-promo.c (1375B)


      1 /* printf %d / %c / %u with plain `int` args. amd64 SysV stores int
      2  * varargs as a 32-bit write into an 8-byte reg-save slot — upper bits
      3  * are unspecified (tcc does not sign-extend ints into the slot).
      4  * mes-libc's vfprintf used to read every integer spec via
      5  * `va_arg(ap, long)`, so the upper bits leaked: -42 printed as
      6  * 4294967254 (= 0x00000000_FFFFFFD6). The fix tracks the `l` length
      7  * modifier and reads with the right width. Other arches passed by
      8  * accident (their ABIs / va_list lowerings extend int slots), but
      9  * the fix is correct everywhere. */
     10 extern int   atoi   (char const *s);
     11 extern int   printf (char const *fmt, ...);
     12 
     13 int
     14 main (void)
     15 {
     16   printf ("%d\n", atoi ("-42"));         /* -42                        */
     17   printf ("%d\n", -2147483647 - 1);      /* INT_MIN: -2147483648       */
     18   printf ("%d\n", 2147483647);           /* INT_MAX:  2147483647       */
     19   printf ("%u\n", (unsigned int)-1);     /*           4294967295       */
     20   printf ("%x\n", (unsigned int)-1);     /*           ffffffff         */
     21   printf ("%c\n", 'Z');                  /*           Z                */
     22 
     23   /* %ld must still read a full long. Pass an intentionally wide
     24      value so a buggy "always int" fix would fail this case. */
     25   long big = 4294967296L + 7L;           /* 0x100000007 */
     26   printf ("%ld\n", big);                 /* 4294967303 */
     27   return 0;
     28 }