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
10typedef  unsigned long long int  ULong;
11typedef    signed long long int  Long;
12typedef  unsigned int            UInt;
13typedef  signed int              Int;
14typedef  signed char             Char;
15typedef  char                    HChar;
16typedef unsigned long            UWord;
17typedef   signed long            Word;
18
19
20
21typedef  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   ------------------------------------------------------------------ */
31UInt
32VG_(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   ------------------------------------------------------------------ */
42typedef
43   struct { Int fd; Bool is_socket; }
44   OutputSink;
45
46
47OutputSink VG_(log_output_sink) = {  2, False }; /* 2 = stderr */
48
49/* Do the low-level send of a message to the logging sink. */
50static
51void 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
60typedef
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.
70static 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))
84static 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))
96static 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))
113UInt VG_(vprintf) ( const HChar *format, va_list vargs )
114{
115   return vprintf_WRK( &VG_(log_output_sink), format, vargs );
116}
117
118__attribute__((noinline))
119UInt 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
129static Bool toBool ( Int x ) {
130   Int r = (x == 0) ? False : True;
131   return (Bool)r;
132}
133
134__attribute__((noinline))
135static 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))
143static 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. */
176static __attribute__((noinline))
177UInt 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. */
224static
225UInt 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 */
264static
265UInt 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))
336UInt
337VG_(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
520static void add_to__sprintf_buf ( HChar c, void *p )
521{
522   HChar** b = p;
523   *(*b)++ = c;
524}
525
526UInt 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
540UInt 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))
561void 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
615static UInt n_SP_updates_fast            = 0;
616static UInt n_SP_updates_generic_known   = 0;
617static UInt n_SP_updates_generic_unknown = 0;
618
619__attribute__((noinline))
620void 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
643int main ( void )
644{
645  VG_print_translation_stats();
646  return 0;
647}
648