• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
send_bytes_to_logging_sink(OutputSink * sink,HChar * msg,Int nbytes)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.
add_to__printf_buf(HChar c,void * p)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))
vprintf_to_buf(printf_buf_t * b,const HChar * format,va_list vargs)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))
vprintf_WRK(OutputSink * sink,const HChar * format,va_list vargs)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))
VG_(vprintf)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))
VG_(printf)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 
toBool(Int x)129 static Bool toBool ( Int x ) {
130    Int r = (x == 0) ? False : True;
131    return (Bool)r;
132 }
133 
134 __attribute__((noinline))
local_strlen(const HChar * str)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))
local_toupper(HChar c)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))
myvprintf_str(void (* send)(HChar,void *),void * send_arg2,Int flags,Int width,HChar * str,Bool capitalise)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
myvprintf_str_XML_simplistic(void (* send)(HChar,void *),void * send_arg2,HChar * str)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
myvprintf_int64(void (* send)(HChar,void *),void * send_arg2,Int flags,Int base,Int width,Bool capitalised,ULong p)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
VG_(debugLog_vprintf)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 //            Addr a = va_arg(vargs, Addr);
497 //
498 //
499 //
500 //            HChar *name;
501 // 	      if (VG_(get_fnname_w_offset)(a, &name)) {
502 //               HChar buf[1 + VG_strlen(name) + 1 + 1];
503 // 	         if (flags & VG_MSG_PAREN) {
504 //                  VG_(sprintf)(str, "(%s)", name):
505 // 	         } else {
506 //                  VG_(sprintf)(str, "%s", name):
507 //               }
508 // 	         ret += myvprintf_str(send, flags, width, buf, 0);
509 // 	      }
510 //            break;
511 //         }
512          default:
513             break;
514       }
515    }
516    return ret;
517 }
518 
519 
add_to__sprintf_buf(HChar c,void * p)520 static void add_to__sprintf_buf ( HChar c, void *p )
521 {
522    HChar** b = p;
523    *(*b)++ = c;
524 }
525 
VG_(vsprintf)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 
VG_(sprintf)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))
VG_percentify(ULong n,ULong m,UInt d,Int n_buf,HChar buf[])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))
VG_print_translation_stats(void)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 
main(void)643 int main ( void )
644 {
645   VG_print_translation_stats();
646   return 0;
647 }
648