From: Julian Seward Date: Tue, 17 May 2011 15:36:01 +0000 (+0000) Subject: Make this test much more independent of glibc, and update outputs X-Git-Tag: svn/VALGRIND_3_7_0~475 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ea6aa5fd25ee41317e3998d50c425d5fcd771687;p=thirdparty%2Fvalgrind.git Make this test much more independent of glibc, and update outputs accordingly. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11762 --- diff --git a/exp-sgcheck/tests/bad_percentify.c b/exp-sgcheck/tests/bad_percentify.c index 2567742c39..94f5559e12 100644 --- a/exp-sgcheck/tests/bad_percentify.c +++ b/exp-sgcheck/tests/bad_percentify.c @@ -4,14 +4,546 @@ is still in Valgrind. */ #include -#include #include -#include +#include typedef unsigned long long int ULong; +typedef signed long long int Long; typedef unsigned int UInt; typedef signed int Int; -typedef char Char; +typedef signed char Char; +typedef char HChar; +typedef unsigned long UWord; +typedef signed long Word; + + + +typedef unsigned char Bool; +#define True ((Bool)1) +#define False ((Bool)0) + +#define VG_(_str) VG_##_str + + +/* --------------------------------------------------------------------- + vg_sprintf, copied from m_libcprint.c + ------------------------------------------------------------------ */ +UInt +VG_(debugLog_vprintf) ( + void(*send)(HChar,void*), + void* send_arg2, + const HChar* format, + va_list vargs + ); + +/* --------------------------------------------------------------------- + printf() and friends + ------------------------------------------------------------------ */ +typedef + struct { Int fd; Bool is_socket; } + OutputSink; + + +OutputSink VG_(log_output_sink) = { 2, False }; /* 2 = stderr */ + +/* Do the low-level send of a message to the logging sink. */ +static +void send_bytes_to_logging_sink ( OutputSink* sink, HChar* msg, Int nbytes ) +{ + fwrite(msg, 1, nbytes, stdout); + fflush(stdout); +} + + +/* --------- printf --------- */ + +typedef + struct { + HChar buf[512]; + Int buf_used; + OutputSink* sink; + } + printf_buf_t; + +// Adds a single char to the buffer. When the buffer gets sufficiently +// full, we write its contents to the logging sink. +static void add_to__printf_buf ( HChar c, void *p ) +{ + printf_buf_t *b = (printf_buf_t *)p; + + if (b->buf_used > sizeof(b->buf) - 2 ) { + send_bytes_to_logging_sink( b->sink, b->buf, b->buf_used ); + b->buf_used = 0; + } + b->buf[b->buf_used++] = c; + b->buf[b->buf_used] = 0; + assert(b->buf_used < sizeof(b->buf)); +} + +__attribute__((noinline)) +static UInt vprintf_to_buf ( printf_buf_t* b, + const HChar *format, va_list vargs ) +{ + UInt ret = 0; + if (b->sink->fd >= 0 || b->sink->fd == -2) { + ret = VG_(debugLog_vprintf) + ( add_to__printf_buf, b, format, vargs ); + } + return ret; +} + +__attribute__((noinline)) +static UInt vprintf_WRK ( OutputSink* sink, + const HChar *format, va_list vargs ) +{ + printf_buf_t myprintf_buf + = { "", 0, sink }; + UInt ret + = vprintf_to_buf(&myprintf_buf, format, vargs); + // Write out any chars left in the buffer. + if (myprintf_buf.buf_used > 0) { + send_bytes_to_logging_sink( myprintf_buf.sink, + myprintf_buf.buf, + myprintf_buf.buf_used ); + } + return ret; +} + +__attribute__((noinline)) +UInt VG_(vprintf) ( const HChar *format, va_list vargs ) +{ + return vprintf_WRK( &VG_(log_output_sink), format, vargs ); +} + +__attribute__((noinline)) +UInt VG_(printf) ( const HChar *format, ... ) +{ + UInt ret; + va_list vargs; + va_start(vargs, format); + ret = VG_(vprintf)(format, vargs); + va_end(vargs); + return ret; +} + +static Bool toBool ( Int x ) { + Int r = (x == 0) ? False : True; + return (Bool)r; +} + +__attribute__((noinline)) +static Int local_strlen ( const HChar* str ) +{ + Int i = 0; + while (str[i] != 0) i++; + return i; +} + +__attribute__((noinline)) +static HChar local_toupper ( HChar c ) +{ + if (c >= 'a' && c <= 'z') + return c + ('A' - 'a'); + else + return c; +} + + +/*------------------------------------------------------------*/ +/*--- A simple, generic, vprintf implementation. ---*/ +/*------------------------------------------------------------*/ + +/* ----------------------------------------------- + Distantly derived from: + + vprintf replacement for Checker. + Copyright 1993, 1994, 1995 Tristan Gingold + Written September 1993 Tristan Gingold + Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE + + (Checker itself was GPL'd.) + ----------------------------------------------- */ + +/* Some flags. */ +#define VG_MSG_SIGNED 1 /* The value is signed. */ +#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */ +#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */ +#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */ +#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */ +#define VG_MSG_ALTFORMAT 32 /* Convert the value to alternate format */ + +/* Copy a string into the buffer. */ +static __attribute__((noinline)) +UInt myvprintf_str ( void(*send)(HChar,void*), + void* send_arg2, + Int flags, + Int width, + HChar* str, + Bool capitalise ) +{ +# define MAYBE_TOUPPER(ch) (capitalise ? local_toupper(ch) : (ch)) + UInt ret = 0; + Int i, extra; + Int len = local_strlen(str); + + if (width == 0) { + ret += len; + for (i = 0; i < len; i++) + send(MAYBE_TOUPPER(str[i]), send_arg2); + return ret; + } + + if (len > width) { + ret += width; + for (i = 0; i < width; i++) + send(MAYBE_TOUPPER(str[i]), send_arg2); + return ret; + } + + extra = width - len; + if (flags & VG_MSG_LJUSTIFY) { + ret += extra; + for (i = 0; i < extra; i++) + send(' ', send_arg2); + } + ret += len; + for (i = 0; i < len; i++) + send(MAYBE_TOUPPER(str[i]), send_arg2); + if (!(flags & VG_MSG_LJUSTIFY)) { + ret += extra; + for (i = 0; i < extra; i++) + send(' ', send_arg2); + } + +# undef MAYBE_TOUPPER + return ret; +} + + +/* Copy a string into the buffer, escaping bad XML chars. */ +static +UInt myvprintf_str_XML_simplistic ( void(*send)(HChar,void*), + void* send_arg2, + HChar* str ) +{ + UInt ret = 0; + Int i; + Int len = local_strlen(str); + HChar* alt; + + for (i = 0; i < len; i++) { + switch (str[i]) { + case '&': alt = "&"; break; + case '<': alt = "<"; break; + case '>': alt = ">"; break; + default: alt = NULL; + } + + if (alt) { + while (*alt) { + send(*alt, send_arg2); + ret++; + alt++; + } + } else { + send(str[i], send_arg2); + ret++; + } + } + + return ret; +} + + +/* Write P into the buffer according to these args: + * If SIGN is true, p is a signed. + * BASE is the base. + * If WITH_ZERO is true, '0' must be added. + * WIDTH is the width of the field. + */ +static +UInt myvprintf_int64 ( void(*send)(HChar,void*), + void* send_arg2, + Int flags, + Int base, + Int width, + Bool capitalised, + ULong p ) +{ + HChar buf[40]; + Int ind = 0; + Int i, nc = 0; + Bool neg = False; + HChar* digits = capitalised ? "0123456789ABCDEF" : "0123456789abcdef"; + UInt ret = 0; + + if (base < 2 || base > 16) + return ret; + + if ((flags & VG_MSG_SIGNED) && (Long)p < 0) { + p = - (Long)p; + neg = True; + } + + if (p == 0) + buf[ind++] = '0'; + else { + while (p > 0) { + if (flags & VG_MSG_COMMA && 10 == base && + 0 == (ind-nc) % 3 && 0 != ind) + { + buf[ind++] = ','; + nc++; + } + buf[ind++] = digits[p % base]; + p /= base; + } + } + + if (neg) + buf[ind++] = '-'; + + if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) { + for(; ind < width; ind++) { + /* assert(ind < 39); */ + if (ind > 39) { + buf[39] = 0; + break; + } + buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' '; + } + } + + /* Reverse copy to buffer. */ + ret += ind; + for (i = ind -1; i >= 0; i--) { + send(buf[i], send_arg2); + } + if (width > 0 && (flags & VG_MSG_LJUSTIFY)) { + for(; ind < width; ind++) { + ret++; + /* Never pad with zeroes on RHS -- changes the value! */ + send(' ', send_arg2); + } + } + return ret; +} + + +/* A simple vprintf(). */ +/* EXPORTED */ +__attribute__((noinline)) +UInt +VG_(debugLog_vprintf) ( + void(*send)(HChar,void*), + void* send_arg2, + const HChar* format, + va_list vargs +) +{ + UInt ret = 0; + Int i; + Int flags; + Int width; + Int n_ls = 0; + Bool is_long, caps; + + /* We assume that vargs has already been initialised by the + caller, using va_start, and that the caller will similarly + clean up with va_end. + */ + + for (i = 0; format[i] != 0; i++) { + if (format[i] != '%') { + send(format[i], send_arg2); + ret++; + continue; + } + i++; + /* A '%' has been found. Ignore a trailing %. */ + if (format[i] == 0) + break; + if (format[i] == '%') { + /* '%%' is replaced by '%'. */ + send('%', send_arg2); + ret++; + continue; + } + flags = 0; + n_ls = 0; + width = 0; /* length of the field. */ + while (1) { + switch (format[i]) { + case '(': + flags |= VG_MSG_PAREN; + break; + case ',': + case '\'': + /* If ',' or '\'' follows '%', commas will be inserted. */ + flags |= VG_MSG_COMMA; + break; + case '-': + /* If '-' follows '%', justify on the left. */ + flags |= VG_MSG_LJUSTIFY; + break; + case '0': + /* If '0' follows '%', pads will be inserted. */ + flags |= VG_MSG_ZJUSTIFY; + break; + case '#': + /* If '#' follows '%', alternative format will be used. */ + flags |= VG_MSG_ALTFORMAT; + break; + default: + goto parse_fieldwidth; + } + i++; + } + parse_fieldwidth: + /* Compute the field length. */ + while (format[i] >= '0' && format[i] <= '9') { + width *= 10; + width += format[i++] - '0'; + } + while (format[i] == 'l') { + i++; + n_ls++; + } + + // %d means print a 32-bit integer. + // %ld means print a word-size integer. + // %lld means print a 64-bit integer. + if (0 == n_ls) { is_long = False; } + else if (1 == n_ls) { is_long = ( sizeof(void*) == sizeof(Long) ); } + else { is_long = True; } + + switch (format[i]) { + case 'o': /* %o */ + if (flags & VG_MSG_ALTFORMAT) { + ret += 2; + send('0',send_arg2); + } + if (is_long) + ret += myvprintf_int64(send, send_arg2, flags, 8, width, False, + (ULong)(va_arg (vargs, ULong))); + else + ret += myvprintf_int64(send, send_arg2, flags, 8, width, False, + (ULong)(va_arg (vargs, UInt))); + break; + case 'd': /* %d */ + flags |= VG_MSG_SIGNED; + if (is_long) + ret += myvprintf_int64(send, send_arg2, flags, 10, width, False, + (ULong)(va_arg (vargs, Long))); + else + ret += myvprintf_int64(send, send_arg2, flags, 10, width, False, + (ULong)(va_arg (vargs, Int))); + break; + case 'u': /* %u */ + if (is_long) + ret += myvprintf_int64(send, send_arg2, flags, 10, width, False, + (ULong)(va_arg (vargs, ULong))); + else + ret += myvprintf_int64(send, send_arg2, flags, 10, width, False, + (ULong)(va_arg (vargs, UInt))); + break; + case 'p': /* %p */ + ret += 2; + send('0',send_arg2); + send('x',send_arg2); + ret += myvprintf_int64(send, send_arg2, flags, 16, width, True, + (ULong)((UWord)va_arg (vargs, void *))); + break; + case 'x': /* %x */ + case 'X': /* %X */ + caps = toBool(format[i] == 'X'); + if (flags & VG_MSG_ALTFORMAT) { + ret += 2; + send('0',send_arg2); + send('x',send_arg2); + } + if (is_long) + ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps, + (ULong)(va_arg (vargs, ULong))); + else + ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps, + (ULong)(va_arg (vargs, UInt))); + break; + case 'c': /* %c */ + ret++; + send(va_arg (vargs, int), send_arg2); + break; + case 's': case 'S': { /* %s */ + char *str = va_arg (vargs, char *); + if (str == (char*) 0) str = "(null)"; + ret += myvprintf_str(send, send_arg2, + flags, width, str, format[i]=='S'); + break; + } + case 't': { /* %t, like %s but escaping chars for XML safety */ + /* Note: simplistic; ignores field width and flags */ + char *str = va_arg (vargs, char *); + if (str == (char*) 0) str = "(null)"; + ret += myvprintf_str_XML_simplistic(send, send_arg2, str); + break; + } + +// case 'y': { /* %y - print symbol */ +// Char buf[100]; +// Char *cp = buf; +// Addr a = va_arg(vargs, Addr); +// +// if (flags & VG_MSG_PAREN) +// *cp++ = '('; +// if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) { +// if (flags & VG_MSG_PAREN) { +// cp += local_strlen(cp); +// *cp++ = ')'; +// *cp = '\0'; +// } +// ret += myvprintf_str(send, send_arg2, flags, width, buf, 0); +// } +// break; +// } + default: + break; + } + } + return ret; +} + + +static void add_to__sprintf_buf ( HChar c, void *p ) +{ + HChar** b = p; + *(*b)++ = c; +} + +UInt VG_(vsprintf) ( HChar* buf, const HChar *format, va_list vargs ) +{ + Int ret; + HChar* sprintf_ptr = buf; + + ret = VG_(debugLog_vprintf) + ( add_to__sprintf_buf, &sprintf_ptr, format, vargs ); + add_to__sprintf_buf('\0', &sprintf_ptr); + + assert(local_strlen(buf) == ret); + + return ret; +} + +UInt VG_(sprintf) ( HChar* buf, const HChar *format, ... ) +{ + UInt ret; + va_list vargs; + va_start(vargs,format); + ret = VG_(vsprintf)(buf, format, vargs); + va_end(vargs); + return ret; +} + + /* --------------------------------------------------------------------- percentify() @@ -21,25 +553,26 @@ typedef char Char; // Percentify n/m with d decimal places. Includes the '%' symbol at the end. // Right justifies in 'buf'. -void VG_percentify(ULong n, ULong m, UInt d, Int n_buf, char buf[]) +__attribute__((noinline)) +void VG_percentify(ULong n, ULong m, UInt d, Int n_buf, HChar buf[]) { Int i, len, space; ULong p1; - Char fmt[32]; + HChar fmt[32]; if (m == 0) { // Have to generate the format string in order to be flexible about // the width of the field. - sprintf(fmt, "%%-%ds", n_buf); + VG_(sprintf)(fmt, "%%-%ds", n_buf); // fmt is now "%s" where is 1,2,3... - sprintf(buf, fmt, "--%"); + VG_(sprintf)(buf, fmt, "--%"); return; } p1 = (100*n) / m; if (d == 0) { - sprintf(buf, "%lld%%", p1); + VG_(sprintf)(buf, "%lld%%", p1); } else { ULong p2; UInt ex; @@ -53,12 +586,12 @@ void VG_percentify(ULong n, ULong m, UInt d, Int n_buf, char buf[]) p2 = ((100*n*ex) / m) % ex; // Have to generate the format string in order to be flexible about // the width of the post-decimal-point part. - sprintf(fmt, "%%lld.%%0%dlld%%%%", d); + VG_(sprintf)(fmt, "%%lld.%%0%dlld%%%%", d); // fmt is now "%lld.%0lld%%" where is 1,2,3... - sprintf(buf, fmt, p1, p2); + VG_(sprintf)(buf, fmt, p1, p2); } - len = strlen(buf); + len = local_strlen(buf); space = n_buf - len; if (space < 0) space = 0; /* Allow for v. small field_width */ i = len; @@ -79,23 +612,24 @@ static UInt n_SP_updates_fast = 0; static UInt n_SP_updates_generic_known = 0; static UInt n_SP_updates_generic_unknown = 0; +__attribute__((noinline)) void VG_print_translation_stats ( void ) { - Char buf[6]; + HChar buf[6]; UInt n_SP_updates = n_SP_updates_fast + n_SP_updates_generic_known + n_SP_updates_generic_unknown; VG_percentify(n_SP_updates_fast, n_SP_updates, 1, 6, buf); - printf( + VG_(printf)( "translate: fast SP updates identified: %'u (%s)\n", n_SP_updates_fast, buf ); VG_percentify(n_SP_updates_generic_known, n_SP_updates, 1, 6, buf); - printf( + VG_(printf)( "translate: generic_known SP updates identified: %'u (%s)\n", n_SP_updates_generic_known, buf ); VG_percentify(n_SP_updates_generic_unknown, n_SP_updates, 1, 6, buf); - printf( + VG_(printf)( "translate: generic_unknown SP updates identified: %'u (%s)\n", n_SP_updates_generic_unknown, buf ); } diff --git a/exp-sgcheck/tests/bad_percentify.stderr.exp-glibc28-amd64 b/exp-sgcheck/tests/bad_percentify.stderr.exp-glibc28-amd64 index b647e4a404..eeb4efadc4 100644 --- a/exp-sgcheck/tests/bad_percentify.stderr.exp-glibc28-amd64 +++ b/exp-sgcheck/tests/bad_percentify.stderr.exp-glibc28-amd64 @@ -1,33 +1,31 @@ +exp-sgcheck, a stack and global array overrun detector Invalid read of size 1 - at 0x........: strlen (h_intercepts.c:...) - by 0x........: ... - by 0x........: ... - by 0x........: VG_print_translation_stats (bad_percentify.c:88) - by 0x........: main (bad_percentify.c:107) + at 0x........: local_strlen (bad_percentify.c:138) + by 0x........: VG_vsprintf (bad_percentify.c:531) + by 0x........: VG_sprintf (bad_percentify.c:541) + by 0x........: VG_percentify (bad_percentify.c:568) + by 0x........: VG_print_translation_stats (bad_percentify.c:621) + by 0x........: main (bad_percentify.c:641) Address 0x........ expected vs actual: - Expected: stack array "buf" in frame 3 back from here + Expected: stack array "buf" of size 6 in frame 4 back from here Actual: unknown + Actual: is 0 after Expected Invalid read of size 1 - at 0x........: strlen (h_intercepts.c:...) - by 0x........: ... - by 0x........: ... - by 0x........: VG_print_translation_stats (bad_percentify.c:93) - by 0x........: main (bad_percentify.c:107) + at 0x........: local_strlen (bad_percentify.c:138) + by 0x........: myvprintf_str (bad_percentify.c:187) + by 0x........: VG_debugLog_vprintf (bad_percentify.c:479) + by 0x........: vprintf_to_buf (bad_percentify.c:89) + by 0x........: vprintf_WRK (bad_percentify.c:102) + by 0x........: VG_vprintf (bad_percentify.c:115) + by 0x........: VG_printf (bad_percentify.c:124) + by 0x........: VG_print_translation_stats (bad_percentify.c:622) + by 0x........: main (bad_percentify.c:641) Address 0x........ expected vs actual: - Expected: stack array "buf" in frame 3 back from here - Actual: unknown - -Invalid read of size 1 - at 0x........: strlen (h_intercepts.c:...) - by 0x........: ... - by 0x........: ... - by 0x........: VG_print_translation_stats (bad_percentify.c:98) - by 0x........: main (bad_percentify.c:107) - Address 0x........ expected vs actual: - Expected: stack array "buf" in frame 3 back from here + Expected: stack array "buf" of size 6 in frame 7 back from here Actual: unknown + Actual: is 0 after Expected -ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0) +ERROR SUMMARY: 6 errors from 2 contexts (suppressed: 0 from 0) diff --git a/exp-sgcheck/tests/bad_percentify.stdout.exp b/exp-sgcheck/tests/bad_percentify.stdout.exp index fd99c2c176..a4ab2ff3e9 100644 --- a/exp-sgcheck/tests/bad_percentify.stdout.exp +++ b/exp-sgcheck/tests/bad_percentify.stdout.exp @@ -1,3 +1,3 @@ -translate: fast SP updates identified: 0 (--% ) -translate: generic_known SP updates identified: 0 (--% ) -translate: generic_unknown SP updates identified: 0 (--% ) +translate: fast SP updates identified: 0 ( --%) +translate: generic_known SP updates identified: 0 ( --%) +translate: generic_unknown SP updates identified: 0 ( --%)