Index: lib/sanitizer_common/sanitizer_printf.cc =================================================================== --- lib/sanitizer_common/sanitizer_printf.cc +++ lib/sanitizer_common/sanitizer_printf.cc @@ -38,45 +38,62 @@ } // Appends number in a given base to buffer. If its length is less than -// "minimal_num_length", it is padded with leading zeroes. -static int AppendUnsigned(char **buff, const char *buff_end, u64 num, - u8 base, u8 minimal_num_length) { +// |minimal_num_length|, it is padded with leading zeroes or spaces, depending +// on the value of |pad_with_zero|. +static int AppendNumber(char **buff, const char *buff_end, u64 absolute_value, + u8 base, u8 minimal_num_length, bool pad_with_zero, + bool negative) { uptr const kMaxLen = 30; RAW_CHECK(base == 10 || base == 16); + RAW_CHECK(base == 10 || !negative); + RAW_CHECK(absolute_value || !negative); RAW_CHECK(minimal_num_length < kMaxLen); + int result = 0; + if (negative && minimal_num_length) + --minimal_num_length; + if (negative && pad_with_zero) + result += AppendChar(buff, buff_end, '-'); uptr num_buffer[kMaxLen]; - uptr pos = 0; + int pos = 0; do { - RAW_CHECK_MSG(pos < kMaxLen, "appendNumber buffer overflow"); - num_buffer[pos++] = num % base; - num /= base; - } while (num > 0); + RAW_CHECK_MSG((uptr)pos < kMaxLen, "AppendNumber buffer overflow"); + num_buffer[pos++] = absolute_value % base; + absolute_value /= base; + } while (absolute_value > 0); if (pos < minimal_num_length) { // Make sure compiler doesn't insert call to memset here. internal_memset(&num_buffer[pos], 0, sizeof(num_buffer[0]) * (minimal_num_length - pos)); pos = minimal_num_length; } - int result = 0; - while (pos-- > 0) { + RAW_CHECK(pos > 0); + pos--; + while (pos >= 0 && num_buffer[pos] == 0) { + char c = (pad_with_zero || pos == 0) ? '0' : ' '; + result += AppendChar(buff, buff_end, c); + pos--; + } + if (negative && !pad_with_zero) result += AppendChar(buff, buff_end, '-'); + while (pos >= 0) { char digit = static_cast(num_buffer[pos]); result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit : 'a' + digit - 10); + pos--; } return result; } +static int AppendUnsigned(char **buff, const char *buff_end, u64 num, u8 base, + u8 minimal_num_length, bool pad_with_zero) { + return AppendNumber(buff, buff_end, num, base, minimal_num_length, + pad_with_zero, false /* negative */); +} + static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num, - u8 minimal_num_length) { - int result = 0; - if (num < 0) { - result += AppendChar(buff, buff_end, '-'); - num = -num; - if (minimal_num_length) - --minimal_num_length; - } - result += AppendUnsigned(buff, buff_end, (u64)num, 10, minimal_num_length); - return result; + u8 minimal_num_length, bool pad_with_zero) { + bool negative = (num < 0); + return AppendNumber(buff, buff_end, (u64)(negative ? -num : num), 10, + minimal_num_length, pad_with_zero, negative); } static int AppendString(char **buff, const char *buff_end, const char *s) { @@ -93,14 +110,14 @@ int result = 0; result += AppendString(buff, buff_end, "0x"); result += AppendUnsigned(buff, buff_end, ptr_value, 16, - (SANITIZER_WORDSIZE == 64) ? 12 : 8); + (SANITIZER_WORDSIZE == 64) ? 12 : 8, true); return result; } int VSNPrintf(char *buff, int buff_length, const char *format, va_list args) { static const char *kPrintfFormatsHelp = - "Supported Printf formats: %(0[0-9]*)?(z|ll)?{d,u,x}; %p; %s; %c\n"; + "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x}; %p; %s; %c\n"; RAW_CHECK(format); RAW_CHECK(buff_length > 0); const char *buff_end = &buff[buff_length - 1]; @@ -112,11 +129,11 @@ continue; } cur++; - bool have_width = (*cur == '0'); + bool have_width = (*cur >= '0' && *cur <= '9'); + bool pad_with_zero = (*cur == '0'); int width = 0; if (have_width) { while (*cur >= '0' && *cur <= '9') { - have_width = true; width = width * 10 + *cur++ - '0'; } } @@ -132,7 +149,8 @@ dval = have_ll ? va_arg(args, s64) : have_z ? va_arg(args, sptr) : va_arg(args, int); - result += AppendSignedDecimal(&buff, buff_end, dval, width); + result += AppendSignedDecimal(&buff, buff_end, dval, width, + pad_with_zero); break; } case 'u': @@ -141,7 +159,7 @@ : have_z ? va_arg(args, uptr) : va_arg(args, unsigned); result += AppendUnsigned(&buff, buff_end, uval, - (*cur == 'u') ? 10 : 16, width); + (*cur == 'u') ? 10 : 16, width, pad_with_zero); break; } case 'p': { Index: lib/sanitizer_common/tests/sanitizer_printf_test.cc =================================================================== --- lib/sanitizer_common/tests/sanitizer_printf_test.cc +++ lib/sanitizer_common/tests/sanitizer_printf_test.cc @@ -104,22 +104,36 @@ } template -static void TestMinMax(const char *fmt, T min, T max) { +static void TestAgainstLibc(const char *fmt, T arg1, T arg2) { char buf[1024]; - uptr len = internal_snprintf(buf, sizeof(buf), fmt, min, max); + uptr len = internal_snprintf(buf, sizeof(buf), fmt, arg1, arg2); char buf2[1024]; - snprintf(buf2, sizeof(buf2), fmt, min, max); + snprintf(buf2, sizeof(buf2), fmt, arg1, arg2); EXPECT_EQ(len, strlen(buf)); EXPECT_STREQ(buf2, buf); } TEST(Printf, MinMax) { - TestMinMax("%d-%d", INT_MIN, INT_MAX); // NOLINT - TestMinMax("%zd-%zd", LONG_MIN, LONG_MAX); // NOLINT - TestMinMax("%u-%u", 0, UINT_MAX); // NOLINT - TestMinMax("%zu-%zu", 0, ULONG_MAX); // NOLINT - TestMinMax("%x-%x", 0, UINT_MAX); // NOLINT - TestMinMax("%zx-%zx", 0, ULONG_MAX); // NOLINT + TestAgainstLibc("%d-%d", INT_MIN, INT_MAX); // NOLINT + TestAgainstLibc("%zd-%zd", LONG_MIN, LONG_MAX); // NOLINT + TestAgainstLibc("%u-%u", 0, UINT_MAX); // NOLINT + TestAgainstLibc("%zu-%zu", 0, ULONG_MAX); // NOLINT + TestAgainstLibc("%x-%x", 0, UINT_MAX); // NOLINT + TestAgainstLibc("%zx-%zx", 0, ULONG_MAX); // NOLINT + Report("%zd\n", LONG_MIN); +} + +TEST(Printf, Padding) { + TestAgainstLibc("%3d - %3d", 1, 0); + TestAgainstLibc("%3d - %3d", -1, 123); + TestAgainstLibc("%3d - %3d", -1, -123); + TestAgainstLibc("%3d - %3d", 12, 1234); + TestAgainstLibc("%3d - %3d", -12, -1234); + TestAgainstLibc("%03d - %03d", 1, 0); + TestAgainstLibc("%03d - %03d", -1, 123); + TestAgainstLibc("%03d - %03d", -1, -123); + TestAgainstLibc("%03d - %03d", 12, 1234); + TestAgainstLibc("%03d - %03d", -12, -1234); } } // namespace __sanitizer