From b25a029284b3761aa15a14b9a040d5b4880b6b83 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 23 Nov 2017 10:12:23 -0800 Subject: [PATCH] Check pointer type specs are compile time --- include/fmt/format.cc | 11 ----------- include/fmt/format.h | 20 +++++++++++--------- test/format-test.cc | 12 ++++-------- test/printf-test.cc | 2 +- 4 files changed, 16 insertions(+), 29 deletions(-) diff --git a/include/fmt/format.cc b/include/fmt/format.cc index bd12cb9b..03dad13e 100644 --- a/include/fmt/format.cc +++ b/include/fmt/format.cc @@ -287,17 +287,6 @@ const uint64_t internal::basic_data::POWERS_OF_10_64[] = { 10000000000000000000ull }; -FMT_FUNC void internal::report_unknown_type(char code, const char *type) { - (void)type; - if (std::isprint(static_cast(code))) { - FMT_THROW(format_error( - format("unknown format code '{}' for {}", code, type))); - } - FMT_THROW(format_error( - format("unknown format code '\\x{:02x}' for {}", - static_cast(code), type))); -} - #if FMT_USE_WINDOWS_H FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) { diff --git a/include/fmt/format.h b/include/fmt/format.h index af002718..5dcccda0 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -895,8 +895,6 @@ struct int_traits { std::numeric_limits::digits <= 32, uint32_t, uint64_t>::type main_type; }; -FMT_API FMT_NORETURN void report_unknown_type(char code, const char *type); - // Static data is placed in this class template to allow header-only // configuration. template @@ -1814,6 +1812,12 @@ constexpr void handle_float_type_spec(char spec, Handler &&handler) { } } +template +constexpr void check_pointer_type_spec(char spec, ErrorHandler &&eh) { + if (spec != 0 && spec != 'p') + eh.on_error("invalid type specifier"); +} + template class int_type_checker : private ErrorHandler { public: @@ -2010,8 +2014,7 @@ class arg_formatter_base { } void operator()(const void *value) { - if (spec_.type_ && spec_.type_ != 'p') - report_unknown_type(spec_.type_, "pointer"); + check_pointer_type_spec(spec_.type_, internal::error_handler()); write_pointer(value); } }; @@ -3099,7 +3102,7 @@ void basic_writer::write_str( // Check if StrChar is convertible to Char. internal::char_traits::convert(StrChar()); if (spec.type_ && spec.type_ != 's') - internal::report_unknown_type(spec.type_, "string"); + FMT_THROW(format_error("invalid type specifier")); const StrChar *str_value = s.data(); std::size_t str_size = s.size(); if (str_size == 0 && !str_value) @@ -3288,8 +3291,7 @@ void basic_writer::write_int(T value, const Spec& spec) { } void on_error() { - internal::report_unknown_type( - spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer"); + FMT_THROW(format_error("invalid type specifier")); } }; internal::handle_int_type_spec(spec.type(), spec_handler(*this, value, spec)); @@ -3333,7 +3335,7 @@ void basic_writer::write_double(T value, const format_specs &spec) { } void on_error() { - internal::report_unknown_type(type, "double"); + FMT_THROW(format_error("invalid type specifier")); } }; spec_handler handler(spec.type()); @@ -3813,7 +3815,7 @@ struct formatter< // TODO break; case internal::POINTER: - // TODO + internal::check_pointer_type_spec(type, eh); break; case internal::CUSTOM: // Custom format specifiers should be checked in parse functions of diff --git a/test/format-test.cc b/test/format-test.cc index d812ff56..42f7f443 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -971,18 +971,13 @@ TEST(FormatterTest, RuntimePrecision) { template void check_unknown_types( const T &value, const char *types, const char *type_name) { - char format_str[BUFFER_SIZE], message[BUFFER_SIZE]; + char format_str[BUFFER_SIZE]; const char *special = ".0123456789}"; for (int i = CHAR_MIN; i <= CHAR_MAX; ++i) { char c = static_cast(i); if (std::strchr(types, c) || std::strchr(special, c) || !c) continue; safe_sprintf(format_str, "{0:10%c}", c); - if (std::isprint(static_cast(c))) { - safe_sprintf(message, "unknown format code '%c' for %s", c, type_name); - } else { - safe_sprintf(message, "unknown format code '\\x%02x' for %s", c, - type_name); - } + const char *message = "invalid type specifier"; EXPECT_THROW_MSG(format(format_str, value), format_error, message) << format_str << " " << message; } @@ -1346,7 +1341,7 @@ TEST(FormatterTest, Examples) { EXPECT_EQ("The answer is 42", format("The answer is {}", 42)); EXPECT_THROW_MSG( format("The answer is {:d}", "forty-two"), format_error, - "unknown format code 'd' for string"); + "invalid type specifier"); EXPECT_EQ(L"Cyrillic letter \x42e", format(L"Cyrillic letter {}", L'\x42e')); @@ -1894,6 +1889,7 @@ TEST(FormatTest, FormatStringErrors) { EXPECT_ERROR("{:s}", "invalid type specifier", int); EXPECT_ERROR("{:s}", "invalid type specifier", bool); EXPECT_ERROR("{:s}", "invalid type specifier", double); + EXPECT_ERROR("{:s}", "invalid type specifier", void*); #endif EXPECT_ERROR("{foo", "missing '}' in format string", int); EXPECT_ERROR("{10000000000}", "number is too big"); diff --git a/test/printf-test.cc b/test/printf-test.cc index c95fc7b9..65020c03 100644 --- a/test/printf-test.cc +++ b/test/printf-test.cc @@ -205,7 +205,7 @@ TEST(PrintfTest, Width) { // Width cannot be specified twice. EXPECT_THROW_MSG(fmt::sprintf("%5-5d", 42), format_error, - "unknown format code '-' for integer"); + "invalid type specifier"); EXPECT_THROW_MSG(fmt::sprintf(format("%{}d", BIG_NUM), 42), format_error, "number is too big");