Home | History | Annotate | Download | only in tests
      1 
      2 /* This demonstrates a stack overrun bug that exp-ptrcheck found while
      3    running Valgrind itself (self hosting).  As at 12 Sept 08 this bug
      4    is still in Valgrind. */
      5 
      6 #include <stdio.h>
      7 #include <assert.h>
      8 #include <stdarg.h>
      9 
     10 typedef  unsigned long long int  ULong;
     11 typedef    signed long long int  Long;
     12 typedef  unsigned int            UInt;
     13 typedef  signed int              Int;
     14 typedef  signed char             Char;
     15 typedef  char                    HChar;
     16 typedef unsigned long            UWord;
     17 typedef   signed long            Word;
     18 
     19 
     20 
     21 typedef  unsigned char  Bool;
     22 #define  True   ((Bool)1)
     23 #define  False  ((Bool)0)
     24 
     25 #define VG_(_str) VG_##_str
     26 
     27 
     28 /* ---------------------------------------------------------------------
     29    vg_sprintf, copied from m_libcprint.c
     30    ------------------------------------------------------------------ */
     31 UInt
     32 VG_(debugLog_vprintf) (
     33    void(*send)(HChar,void*),
     34    void* send_arg2,
     35    const HChar* format,
     36    va_list vargs
     37                         );
     38 
     39 /* ---------------------------------------------------------------------
     40    printf() and friends
     41    ------------------------------------------------------------------ */
     42 typedef
     43    struct { Int fd; Bool is_socket; }
     44    OutputSink;
     45 
     46 
     47 OutputSink VG_(log_output_sink) = {  2, False }; /* 2 = stderr */
     48 
     49 /* Do the low-level send of a message to the logging sink. */
     50 static
     51 void send_bytes_to_logging_sink ( OutputSink* sink, HChar* msg, Int nbytes )
     52 {
     53    fwrite(msg, 1, nbytes, stdout);
     54    fflush(stdout);
     55 }
     56 
     57 
     58 /* --------- printf --------- */
     59 
     60 typedef
     61    struct {
     62       HChar       buf[512];
     63       Int         buf_used;
     64       OutputSink* sink;
     65    }
     66    printf_buf_t;
     67 
     68 // Adds a single char to the buffer.  When the buffer gets sufficiently
     69 // full, we write its contents to the logging sink.
     70 static void add_to__printf_buf ( HChar c, void *p )
     71 {
     72    printf_buf_t *b = (printf_buf_t *)p;
     73 
     74    if (b->buf_used > sizeof(b->buf) - 2 ) {
     75       send_bytes_to_logging_sink( b->sink, b->buf, b->buf_used );
     76       b->buf_used = 0;
     77    }
     78    b->buf[b->buf_used++] = c;
     79    b->buf[b->buf_used]   = 0;
     80    assert(b->buf_used < sizeof(b->buf));
     81 }
     82 
     83 __attribute__((noinline))
     84 static UInt vprintf_to_buf ( printf_buf_t* b,
     85                              const HChar *format, va_list vargs )
     86 {
     87    UInt ret = 0;
     88    if (b->sink->fd >= 0 || b->sink->fd == -2) {
     89       ret = VG_(debugLog_vprintf)
     90                ( add_to__printf_buf, b, format, vargs );
     91    }
     92    return ret;
     93 }
     94 
     95 __attribute__((noinline))
     96 static UInt vprintf_WRK ( OutputSink* sink,
     97                           const HChar *format, va_list vargs )
     98 {
     99    printf_buf_t myprintf_buf
    100       = { "", 0, sink };
    101    UInt ret;
    102    ret = vprintf_to_buf(&myprintf_buf, format, vargs);
    103    // Write out any chars left in the buffer.
    104    if (myprintf_buf.buf_used > 0) {
    105       send_bytes_to_logging_sink( myprintf_buf.sink,
    106                                   myprintf_buf.buf,
    107                                   myprintf_buf.buf_used );
    108    }
    109    return ret;
    110 }
    111 
    112 __attribute__((noinline))
    113 UInt VG_(vprintf) ( const HChar *format, va_list vargs )
    114 {
    115    return vprintf_WRK( &VG_(log_output_sink), format, vargs );
    116 }
    117 
    118 __attribute__((noinline))
    119 UInt VG_(printf) ( const HChar *format, ... )
    120 {
    121    UInt ret;
    122    va_list vargs;
    123    va_start(vargs, format);
    124    ret = VG_(vprintf)(format, vargs);
    125    va_end(vargs);
    126    return ret;
    127 }
    128 
    129 static Bool toBool ( Int x ) {
    130    Int r = (x == 0) ? False : True;
    131    return (Bool)r;
    132 }
    133 
    134 __attribute__((noinline))
    135 static Int local_strlen ( const HChar* str )
    136 {
    137    Int i = 0;
    138    while (str[i] != 0) i++;
    139    return i;
    140 }
    141 
    142 __attribute__((noinline))
    143 static HChar local_toupper ( HChar c )
    144 {
    145    if (c >= 'a' && c <= 'z')
    146       return c + ('A' - 'a');
    147    else
    148       return c;
    149 }
    150 
    151 
    152 /*------------------------------------------------------------*/
    153 /*--- A simple, generic, vprintf implementation.           ---*/
    154 /*------------------------------------------------------------*/
    155 
    156 /* -----------------------------------------------
    157    Distantly derived from:
    158 
    159       vprintf replacement for Checker.
    160       Copyright 1993, 1994, 1995 Tristan Gingold
    161       Written September 1993 Tristan Gingold
    162       Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
    163 
    164    (Checker itself was GPL'd.)
    165    ----------------------------------------------- */
    166 
    167 /* Some flags.  */
    168 #define VG_MSG_SIGNED    1 /* The value is signed. */
    169 #define VG_MSG_ZJUSTIFY  2 /* Must justify with '0'. */
    170 #define VG_MSG_LJUSTIFY  4 /* Must justify on the left. */
    171 #define VG_MSG_PAREN     8 /* Parenthesize if present (for %y) */
    172 #define VG_MSG_COMMA    16 /* Add commas to numbers (for %d, %u) */
    173 #define VG_MSG_ALTFORMAT 32 /* Convert the value to alternate format */
    174 
    175 /* Copy a string into the buffer. */
    176 static __attribute__((noinline))
    177 UInt myvprintf_str ( void(*send)(HChar,void*),
    178                      void* send_arg2,
    179                      Int flags,
    180                      Int width,
    181                      HChar* str,
    182                      Bool capitalise )
    183 {
    184 #  define MAYBE_TOUPPER(ch) (capitalise ? local_toupper(ch) : (ch))
    185    UInt ret = 0;
    186    Int i, extra;
    187    Int len = local_strlen(str);
    188 
    189    if (width == 0) {
    190       ret += len;
    191       for (i = 0; i < len; i++)
    192           send(MAYBE_TOUPPER(str[i]), send_arg2);
    193       return ret;
    194    }
    195 
    196    if (len > width) {
    197       ret += width;
    198       for (i = 0; i < width; i++)
    199          send(MAYBE_TOUPPER(str[i]), send_arg2);
    200       return ret;
    201    }
    202 
    203    extra = width - len;
    204    if (flags & VG_MSG_LJUSTIFY) {
    205       ret += extra;
    206       for (i = 0; i < extra; i++)
    207          send(' ', send_arg2);
    208    }
    209    ret += len;
    210    for (i = 0; i < len; i++)
    211       send(MAYBE_TOUPPER(str[i]), send_arg2);
    212    if (!(flags & VG_MSG_LJUSTIFY)) {
    213       ret += extra;
    214       for (i = 0; i < extra; i++)
    215          send(' ', send_arg2);
    216    }
    217 
    218 #  undef MAYBE_TOUPPER
    219    return ret;
    220 }
    221 
    222 
    223 /* Copy a string into the buffer, escaping bad XML chars. */
    224 static
    225 UInt myvprintf_str_XML_simplistic ( void(*send)(HChar,void*),
    226                                     void* send_arg2,
    227                                     HChar* str )
    228 {
    229    UInt   ret = 0;
    230    Int    i;
    231    Int    len = local_strlen(str);
    232    HChar* alt;
    233 
    234    for (i = 0; i < len; i++) {
    235       switch (str[i]) {
    236          case '&': alt = "&amp;"; break;
    237          case '<': alt = "&lt;"; break;
    238          case '>': alt = "&gt;"; break;
    239          default:  alt = NULL;
    240       }
    241 
    242       if (alt) {
    243          while (*alt) {
    244             send(*alt, send_arg2);
    245             ret++;
    246             alt++;
    247          }
    248       } else {
    249          send(str[i], send_arg2);
    250          ret++;
    251       }
    252    }
    253 
    254    return ret;
    255 }
    256 
    257 
    258 /* Write P into the buffer according to these args:
    259  *  If SIGN is true, p is a signed.
    260  *  BASE is the base.
    261  *  If WITH_ZERO is true, '0' must be added.
    262  *  WIDTH is the width of the field.
    263  */
    264 static
    265 UInt myvprintf_int64 ( void(*send)(HChar,void*),
    266                        void* send_arg2,
    267                        Int flags,
    268                        Int base,
    269                        Int width,
    270                        Bool capitalised,
    271                        ULong p )
    272 {
    273    HChar  buf[40];
    274    Int    ind = 0;
    275    Int    i, nc = 0;
    276    Bool   neg = False;
    277    HChar* digits = capitalised ? "0123456789ABCDEF" : "0123456789abcdef";
    278    UInt   ret = 0;
    279 
    280    if (base < 2 || base > 16)
    281       return ret;
    282 
    283    if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
    284       p   = - (Long)p;
    285       neg = True;
    286    }
    287 
    288    if (p == 0)
    289       buf[ind++] = '0';
    290    else {
    291       while (p > 0) {
    292          if (flags & VG_MSG_COMMA && 10 == base &&
    293              0 == (ind-nc) % 3 && 0 != ind)
    294          {
    295             buf[ind++] = ',';
    296             nc++;
    297          }
    298          buf[ind++] = digits[p % base];
    299          p /= base;
    300       }
    301    }
    302 
    303    if (neg)
    304       buf[ind++] = '-';
    305 
    306    if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
    307       for(; ind < width; ind++) {
    308          /* assert(ind < 39); */
    309          if (ind > 39) {
    310             buf[39] = 0;
    311             break;
    312          }
    313          buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
    314       }
    315    }
    316 
    317    /* Reverse copy to buffer.  */
    318    ret += ind;
    319    for (i = ind -1; i >= 0; i--) {
    320       send(buf[i], send_arg2);
    321    }
    322    if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
    323       for(; ind < width; ind++) {
    324          ret++;
    325          /* Never pad with zeroes on RHS -- changes the value! */
    326          send(' ', send_arg2);
    327       }
    328    }
    329    return ret;
    330 }
    331 
    332 
    333 /* A simple vprintf().  */
    334 /* EXPORTED */
    335 __attribute__((noinline))
    336 UInt
    337 VG_(debugLog_vprintf) (
    338    void(*send)(HChar,void*),
    339    void* send_arg2,
    340    const HChar* format,
    341    va_list vargs
    342 )
    343 {
    344    UInt ret = 0;
    345    Int  i;
    346    Int  flags;
    347    Int  width;
    348    Int  n_ls = 0;
    349    Bool is_long, caps;
    350 
    351    /* We assume that vargs has already been initialised by the
    352       caller, using va_start, and that the caller will similarly
    353       clean up with va_end.
    354    */
    355 
    356    for (i = 0; format[i] != 0; i++) {
    357       if (format[i] != '%') {
    358          send(format[i], send_arg2);
    359          ret++;
    360          continue;
    361       }
    362       i++;
    363       /* A '%' has been found.  Ignore a trailing %. */
    364       if (format[i] == 0)
    365          break;
    366       if (format[i] == '%') {
    367          /* '%%' is replaced by '%'. */
    368          send('%', send_arg2);
    369          ret++;
    370          continue;
    371       }
    372       flags = 0;
    373       n_ls  = 0;
    374       width = 0; /* length of the field. */
    375       while (1) {
    376          switch (format[i]) {
    377          case '(':
    378             flags |= VG_MSG_PAREN;
    379             break;
    380          case ',':
    381          case '\'':
    382             /* If ',' or '\'' follows '%', commas will be inserted. */
    383             flags |= VG_MSG_COMMA;
    384             break;
    385          case '-':
    386             /* If '-' follows '%', justify on the left. */
    387             flags |= VG_MSG_LJUSTIFY;
    388             break;
    389          case '0':
    390             /* If '0' follows '%', pads will be inserted. */
    391             flags |= VG_MSG_ZJUSTIFY;
    392             break;
    393          case '#':
    394             /* If '#' follows '%', alternative format will be used. */
    395             flags |= VG_MSG_ALTFORMAT;
    396             break;
    397          default:
    398             goto parse_fieldwidth;
    399          }
    400          i++;
    401       }
    402      parse_fieldwidth:
    403       /* Compute the field length. */
    404       while (format[i] >= '0' && format[i] <= '9') {
    405          width *= 10;
    406          width += format[i++] - '0';
    407       }
    408       while (format[i] == 'l') {
    409          i++;
    410          n_ls++;
    411       }
    412 
    413       //   %d means print a 32-bit integer.
    414       //  %ld means print a word-size integer.
    415       // %lld means print a 64-bit integer.
    416       if      (0 == n_ls) { is_long = False; }
    417       else if (1 == n_ls) { is_long = ( sizeof(void*) == sizeof(Long) ); }
    418       else                { is_long = True; }
    419 
    420       switch (format[i]) {
    421          case 'o': /* %o */
    422             if (flags & VG_MSG_ALTFORMAT) {
    423                ret += 2;
    424                send('0',send_arg2);
    425             }
    426             if (is_long)
    427                ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
    428                                       (ULong)(va_arg (vargs, ULong)));
    429             else
    430                ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
    431                                       (ULong)(va_arg (vargs, UInt)));
    432             break;
    433          case 'd': /* %d */
    434             flags |= VG_MSG_SIGNED;
    435             if (is_long)
    436                ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
    437                                       (ULong)(va_arg (vargs, Long)));
    438             else
    439                ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
    440                                       (ULong)(va_arg (vargs, Int)));
    441             break;
    442          case 'u': /* %u */
    443             if (is_long)
    444                ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
    445                                       (ULong)(va_arg (vargs, ULong)));
    446             else
    447                ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
    448                                       (ULong)(va_arg (vargs, UInt)));
    449             break;
    450          case 'p':
    451             if (format[i+1] == 'S') {
    452                i++;
    453                /* %pS, like %s but escaping chars for XML safety */
    454                /* Note: simplistic; ignores field width and flags */
    455                char *str = va_arg (vargs, char *);
    456                if (str == (char*) 0)
    457                   str = "(null)";
    458                ret += myvprintf_str_XML_simplistic(send, send_arg2, str);
    459             } else {
    460                /* %p */
    461                ret += 2;
    462                send('0',send_arg2);
    463                send('x',send_arg2);
    464                ret += myvprintf_int64(send, send_arg2, flags, 16, width, True,
    465                                       (ULong)((UWord)va_arg (vargs, void *)));
    466             }
    467             break;
    468          case 'x': /* %x */
    469          case 'X': /* %X */
    470             caps = toBool(format[i] == 'X');
    471             if (flags & VG_MSG_ALTFORMAT) {
    472                ret += 2;
    473                send('0',send_arg2);
    474                send('x',send_arg2);
    475             }
    476             if (is_long)
    477                ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
    478                                       (ULong)(va_arg (vargs, ULong)));
    479             else
    480                ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
    481                                       (ULong)(va_arg (vargs, UInt)));
    482             break;
    483          case 'c': /* %c */
    484             ret++;
    485             send(va_arg (vargs, int), send_arg2);
    486             break;
    487          case 's': case 'S': { /* %s */
    488             char *str = va_arg (vargs, char *);
    489             if (str == (char*) 0) str = "(null)";
    490             ret += myvprintf_str(send, send_arg2,
    491                                  flags, width, str, format[i]=='S');
    492             break;
    493          }
    494 
    495 //         case 'y': { /* %y - print symbol */
    496 //            Char buf[100];
    497 //            Char *cp = buf;
    498 //            Addr a = va_arg(vargs, Addr);
    499 //
    500 //            if (flags & VG_MSG_PAREN)
    501 //               *cp++ = '(';
    502 //            if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
    503 //               if (flags & VG_MSG_PAREN) {
    504 //                  cp += local_strlen(cp);
    505 //                  *cp++ = ')';
    506 //                  *cp = '\0';
    507 //               }
    508 //               ret += myvprintf_str(send, send_arg2, flags, width, buf, 0);
    509 //            }
    510 //            break;
    511 //         }
    512          default:
    513             break;
    514       }
    515    }
    516    return ret;
    517 }
    518 
    519 
    520 static void add_to__sprintf_buf ( HChar c, void *p )
    521 {
    522    HChar** b = p;
    523    *(*b)++ = c;
    524 }
    525 
    526 UInt VG_(vsprintf) ( HChar* buf, const HChar *format, va_list vargs )
    527 {
    528    Int ret;
    529    HChar* sprintf_ptr = buf;
    530 
    531    ret = VG_(debugLog_vprintf)
    532             ( add_to__sprintf_buf, &sprintf_ptr, format, vargs );
    533    add_to__sprintf_buf('\0', &sprintf_ptr);
    534 
    535    assert(local_strlen(buf) == ret);
    536 
    537    return ret;
    538 }
    539 
    540 UInt VG_(sprintf) ( HChar* buf, const HChar *format, ... )
    541 {
    542    UInt ret;
    543    va_list vargs;
    544    va_start(vargs,format);
    545    ret = VG_(vsprintf)(buf, format, vargs);
    546    va_end(vargs);
    547    return ret;
    548 }
    549 
    550 
    551 
    552 /* ---------------------------------------------------------------------
    553    percentify()
    554    ------------------------------------------------------------------ */
    555 
    556 /* This part excerpted from coregrind/m_libcbase.c */
    557 
    558 // Percentify n/m with d decimal places.  Includes the '%' symbol at the end.
    559 // Right justifies in 'buf'.
    560 __attribute__((noinline))
    561 void VG_percentify(ULong n, ULong m, UInt d, Int n_buf, HChar buf[])
    562 {
    563    Int i, len, space;
    564    ULong p1;
    565    HChar fmt[32];
    566 
    567    if (m == 0) {
    568       // Have to generate the format string in order to be flexible about
    569       // the width of the field.
    570       VG_(sprintf)(fmt, "%%-%ds", n_buf);
    571       // fmt is now "%<n_buf>s" where <d> is 1,2,3...
    572       VG_(sprintf)(buf, fmt, "--%");
    573       return;
    574    }
    575 
    576    p1 = (100*n) / m;
    577 
    578    if (d == 0) {
    579       VG_(sprintf)(buf, "%lld%%", p1);
    580    } else {
    581       ULong p2;
    582       UInt  ex;
    583       switch (d) {
    584       case 1: ex = 10;    break;
    585       case 2: ex = 100;   break;
    586       case 3: ex = 1000;  break;
    587       default: assert(0);
    588       /* was: VG_(tool_panic)("Currently can only handle 3 decimal places"); */
    589       }
    590       p2 = ((100*n*ex) / m) % ex;
    591       // Have to generate the format string in order to be flexible about
    592       // the width of the post-decimal-point part.
    593       VG_(sprintf)(fmt, "%%lld.%%0%dlld%%%%", d);
    594       // fmt is now "%lld.%0<d>lld%%" where <d> is 1,2,3...
    595       VG_(sprintf)(buf, fmt, p1, p2);
    596    }
    597 
    598    len = local_strlen(buf);
    599    space = n_buf - len;
    600    if (space < 0) space = 0;     /* Allow for v. small field_width */
    601    i = len;
    602 
    603    /* Right justify in field */
    604    for (     ; i >= 0;    i--)  buf[i + space] = buf[i];
    605    for (i = 0; i < space; i++)  buf[i] = ' ';
    606 }
    607 
    608 
    609 /*------------------------------------------------------------*/
    610 /*--- Stats                                                ---*/
    611 /*------------------------------------------------------------*/
    612 
    613 /* This part excerpted from coregrind/m_translate.c */
    614 
    615 static UInt n_SP_updates_fast            = 0;
    616 static UInt n_SP_updates_generic_known   = 0;
    617 static UInt n_SP_updates_generic_unknown = 0;
    618 
    619 __attribute__((noinline))
    620 void VG_print_translation_stats ( void )
    621 {
    622    HChar buf[6];
    623    UInt n_SP_updates = n_SP_updates_fast + n_SP_updates_generic_known
    624                                          + n_SP_updates_generic_unknown;
    625    VG_percentify(n_SP_updates_fast, n_SP_updates, 1, 6, buf);
    626    VG_(printf)(
    627       "translate:            fast SP updates identified: %'u (%s)\n",
    628       n_SP_updates_fast, buf );
    629 
    630    VG_percentify(n_SP_updates_generic_known, n_SP_updates, 1, 6, buf);
    631    VG_(printf)(
    632       "translate:   generic_known SP updates identified: %'u (%s)\n",
    633       n_SP_updates_generic_known, buf );
    634 
    635    VG_percentify(n_SP_updates_generic_unknown, n_SP_updates, 1, 6, buf);
    636    VG_(printf)(
    637       "translate: generic_unknown SP updates identified: %'u (%s)\n",
    638       n_SP_updates_generic_unknown, buf );
    639 }
    640 
    641 
    642 
    643 int main ( void )
    644 {
    645   VG_print_translation_stats();
    646   return 0;
    647 }
    648