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 = "&"; break;
237 case '<': alt = "<"; break;
238 case '>': alt = ">"; 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 // 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
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