Check pointer type specs are compile time

This commit is contained in:
Victor Zverovich 2017-11-23 10:12:23 -08:00
parent c8a9d902dd
commit b25a029284
4 changed files with 16 additions and 29 deletions

View File

@ -287,17 +287,6 @@ const uint64_t internal::basic_data<T>::POWERS_OF_10_64[] = {
10000000000000000000ull 10000000000000000000ull
}; };
FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
(void)type;
if (std::isprint(static_cast<unsigned char>(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<unsigned>(code), type)));
}
#if FMT_USE_WINDOWS_H #if FMT_USE_WINDOWS_H
FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) { FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {

View File

@ -895,8 +895,6 @@ struct int_traits {
std::numeric_limits<T>::digits <= 32, uint32_t, uint64_t>::type main_type; std::numeric_limits<T>::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 // Static data is placed in this class template to allow header-only
// configuration. // configuration.
template <typename T = void> template <typename T = void>
@ -1814,6 +1812,12 @@ constexpr void handle_float_type_spec(char spec, Handler &&handler) {
} }
} }
template <typename ErrorHandler>
constexpr void check_pointer_type_spec(char spec, ErrorHandler &&eh) {
if (spec != 0 && spec != 'p')
eh.on_error("invalid type specifier");
}
template <typename ErrorHandler> template <typename ErrorHandler>
class int_type_checker : private ErrorHandler { class int_type_checker : private ErrorHandler {
public: public:
@ -2010,8 +2014,7 @@ class arg_formatter_base {
} }
void operator()(const void *value) { void operator()(const void *value) {
if (spec_.type_ && spec_.type_ != 'p') check_pointer_type_spec(spec_.type_, internal::error_handler());
report_unknown_type(spec_.type_, "pointer");
write_pointer(value); write_pointer(value);
} }
}; };
@ -3099,7 +3102,7 @@ void basic_writer<Char>::write_str(
// Check if StrChar is convertible to Char. // Check if StrChar is convertible to Char.
internal::char_traits<Char>::convert(StrChar()); internal::char_traits<Char>::convert(StrChar());
if (spec.type_ && spec.type_ != 's') 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(); const StrChar *str_value = s.data();
std::size_t str_size = s.size(); std::size_t str_size = s.size();
if (str_size == 0 && !str_value) if (str_size == 0 && !str_value)
@ -3288,8 +3291,7 @@ void basic_writer<Char>::write_int(T value, const Spec& spec) {
} }
void on_error() { void on_error() {
internal::report_unknown_type( FMT_THROW(format_error("invalid type specifier"));
spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer");
} }
}; };
internal::handle_int_type_spec(spec.type(), spec_handler(*this, value, spec)); internal::handle_int_type_spec(spec.type(), spec_handler(*this, value, spec));
@ -3333,7 +3335,7 @@ void basic_writer<Char>::write_double(T value, const format_specs &spec) {
} }
void on_error() { void on_error() {
internal::report_unknown_type(type, "double"); FMT_THROW(format_error("invalid type specifier"));
} }
}; };
spec_handler handler(spec.type()); spec_handler handler(spec.type());
@ -3813,7 +3815,7 @@ struct formatter<
// TODO // TODO
break; break;
case internal::POINTER: case internal::POINTER:
// TODO internal::check_pointer_type_spec(type, eh);
break; break;
case internal::CUSTOM: case internal::CUSTOM:
// Custom format specifiers should be checked in parse functions of // Custom format specifiers should be checked in parse functions of

View File

@ -971,18 +971,13 @@ TEST(FormatterTest, RuntimePrecision) {
template <typename T> template <typename T>
void check_unknown_types( void check_unknown_types(
const T &value, const char *types, const char *type_name) { 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}"; const char *special = ".0123456789}";
for (int i = CHAR_MIN; i <= CHAR_MAX; ++i) { for (int i = CHAR_MIN; i <= CHAR_MAX; ++i) {
char c = static_cast<char>(i); char c = static_cast<char>(i);
if (std::strchr(types, c) || std::strchr(special, c) || !c) continue; if (std::strchr(types, c) || std::strchr(special, c) || !c) continue;
safe_sprintf(format_str, "{0:10%c}", c); safe_sprintf(format_str, "{0:10%c}", c);
if (std::isprint(static_cast<unsigned char>(c))) { const char *message = "invalid type specifier";
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);
}
EXPECT_THROW_MSG(format(format_str, value), format_error, message) EXPECT_THROW_MSG(format(format_str, value), format_error, message)
<< format_str << " " << message; << format_str << " " << message;
} }
@ -1346,7 +1341,7 @@ TEST(FormatterTest, Examples) {
EXPECT_EQ("The answer is 42", format("The answer is {}", 42)); EXPECT_EQ("The answer is 42", format("The answer is {}", 42));
EXPECT_THROW_MSG( EXPECT_THROW_MSG(
format("The answer is {:d}", "forty-two"), format_error, format("The answer is {:d}", "forty-two"), format_error,
"unknown format code 'd' for string"); "invalid type specifier");
EXPECT_EQ(L"Cyrillic letter \x42e", EXPECT_EQ(L"Cyrillic letter \x42e",
format(L"Cyrillic letter {}", L'\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", int);
EXPECT_ERROR("{:s}", "invalid type specifier", bool); EXPECT_ERROR("{:s}", "invalid type specifier", bool);
EXPECT_ERROR("{:s}", "invalid type specifier", double); EXPECT_ERROR("{:s}", "invalid type specifier", double);
EXPECT_ERROR("{:s}", "invalid type specifier", void*);
#endif #endif
EXPECT_ERROR("{foo", "missing '}' in format string", int); EXPECT_ERROR("{foo", "missing '}' in format string", int);
EXPECT_ERROR("{10000000000}", "number is too big"); EXPECT_ERROR("{10000000000}", "number is too big");

View File

@ -205,7 +205,7 @@ TEST(PrintfTest, Width) {
// Width cannot be specified twice. // Width cannot be specified twice.
EXPECT_THROW_MSG(fmt::sprintf("%5-5d", 42), format_error, 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), EXPECT_THROW_MSG(fmt::sprintf(format("%{}d", BIG_NUM), 42),
format_error, "number is too big"); format_error, "number is too big");