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 = "&"; 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 */ 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// 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 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