mirror of
https://github.com/fmtlib/fmt.git
synced 2024-12-24 12:14:26 +00:00
Check pointer type specs are compile time
This commit is contained in:
parent
c8a9d902dd
commit
b25a029284
@ -287,17 +287,6 @@ const uint64_t internal::basic_data<T>::POWERS_OF_10_64[] = {
|
||||
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
|
||||
|
||||
FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
|
||||
|
@ -895,8 +895,6 @@ struct int_traits {
|
||||
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
|
||||
// configuration.
|
||||
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>
|
||||
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<Char>::write_str(
|
||||
// Check if StrChar is convertible to Char.
|
||||
internal::char_traits<Char>::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<Char>::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<Char>::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
|
||||
|
@ -971,18 +971,13 @@ TEST(FormatterTest, RuntimePrecision) {
|
||||
template <typename T>
|
||||
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<char>(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<unsigned char>(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");
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user