From 6570dc3122e6aa182f84be26350f0b08c96ff998 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 19 Nov 2017 10:28:01 -0800 Subject: [PATCH] Disallow formatting of multibyte strings into a wide buffer (#606) --- include/fmt/format.h | 80 +++++++++++++++----------------------------- test/util-test.cc | 8 ++--- 2 files changed, 29 insertions(+), 59 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 2ea0a86bc1c9..9b4249da6fde 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1112,7 +1112,7 @@ enum type { INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR, // followed by floating-point types. DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, - CSTRING, STRING, TSTRING, POINTER, CUSTOM + CSTRING, STRING, POINTER, CUSTOM }; constexpr bool is_integral(type t) { @@ -1189,10 +1189,10 @@ template <> constexpr type get_type() { return CSTRING; } template <> constexpr type get_type() { return CSTRING; } template <> constexpr type get_type() { return STRING; } template <> constexpr type get_type() { return STRING; } -template <> constexpr type get_type() { return TSTRING; } -template <> constexpr type get_type() { return TSTRING; } -template <> constexpr type get_type() { return TSTRING; } -template <> constexpr type get_type() { return TSTRING; } +template <> constexpr type get_type() { return CSTRING; } +template <> constexpr type get_type() { return CSTRING; } +template <> constexpr type get_type() { return STRING; } +template <> constexpr type get_type() { return STRING; } template <> constexpr type get_type() { return POINTER; } template <> constexpr type get_type() { return POINTER; } template <> constexpr type get_type() { return POINTER; } @@ -1225,10 +1225,9 @@ class value { double double_value; long double long_double_value; const void *pointer; - string_value string; + string_value string; string_value sstring; string_value ustring; - string_value tstring; custom_value custom; }; @@ -1271,18 +1270,16 @@ class value { } #endif - value(char *s) { set(string.value, s); } - value(const char *s) { set(string.value, s); } - value(signed char *s) { set(sstring.value, s); } - value(const signed char *s) { set(sstring.value, s); } - value(unsigned char *s) { set(ustring.value, s); } - value(const unsigned char *s) { set(ustring.value, s); } - value(string_view s) { set_string(s); } - value(const std::string &s) { set_string(s); } - value(wstring_view s) { set_wstring(s); } - value(const std::wstring &s) { set_wstring(s); } - value(wchar_t *s) { set_wstring(wstring_view(s)); } - value(const wchar_t *s) { set_wstring(wstring_view(s)); } + // Formatting of wide strings into a narrow buffer and multibyte strings + // into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606). + value(char_type *s) { set(string.value, s); } + value(const char_type *s) { set(string.value, s); } + value(signed char *s) { set_cstring(sstring.value, s); } + value(const signed char *s) { set_cstring(sstring.value, s); } + value(unsigned char *s) { set_cstring(ustring.value, s); } + value(const unsigned char *s) { set_cstring(ustring.value, s); } + value(basic_string_view s) { set_string(s); } + value(const std::basic_string &s) { set_string(s); } // Formatting of arbitrary pointers is disallowed. If you want to output a // pointer cast it to "void *" or "const void *". In particular, this forbids @@ -1338,12 +1335,11 @@ class value { string.size = value.size(); } - template - void set_wstring(const T &value) { - require_wchar(); - static_assert(get_type() == TSTRING, "invalid type"); - tstring.value = value.data(); - tstring.size = value.size(); + template + constexpr void set_cstring(T &field, const U *str) { + static_assert(std::is_same::value, + "incompatible string types"); + set(field, str); } // Formats an argument of a custom type, such as a user-defined class. @@ -1439,10 +1435,8 @@ constexpr typename std::result_of::type case internal::CSTRING: return vis(arg.value_.string.value); case internal::STRING: - return vis(string_view(arg.value_.string.value, arg.value_.string.size)); - case internal::TSTRING: return vis(basic_string_view( - arg.value_.tstring.value, arg.value_.tstring.size)); + arg.value_.string.value, arg.value_.string.size)); case internal::POINTER: return vis(arg.value_.pointer); case internal::CUSTOM: @@ -1902,22 +1896,6 @@ class arg_formatter_base { writer_.write_int(reinterpret_cast(p), spec_); } - template - typename std::enable_if< - std::is_same::value && - std::is_same::value>::type - write_str(basic_string_view value) { - writer_.write_str(value, spec_); - } - - template - typename std::enable_if< - !std::is_same::value || - !std::is_same::value>::type - write_str(basic_string_view ) { - // Do nothing. - } - protected: basic_writer &writer() { return writer_; } format_specs &spec() { return spec_; } @@ -1926,9 +1904,9 @@ class arg_formatter_base { writer_.write_str(string_view(value ? "true" : "false"), spec_); } - void write(const char *value) { - writer_.write_str( - string_view(value, value != 0 ? std::strlen(value) : 0), spec_); + void write(const Char *value) { + writer_.write_str(basic_string_view( + value, value != 0 ? std::char_traits::length(value) : 0), spec_); } public: @@ -1985,20 +1963,16 @@ class arg_formatter_base { *out = internal::char_traits::cast(value); } - void operator()(const char *value) { + void operator()(const Char *value) { if (spec_.type_ == 'p') return write_pointer(value); write(value); } - void operator()(string_view value) { + void operator()(basic_string_view value) { writer_.write_str(value, spec_); } - void operator()(basic_string_view value) { - write_str(value); - } - void operator()(const void *value) { if (spec_.type_ && spec_.type_ != 'p') report_unknown_type(spec_.type_, "pointer"); diff --git a/test/util-test.cc b/test/util-test.cc index ce9205bf3bb7..459e5914fc09 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -563,13 +563,9 @@ TEST(UtilTest, StringArg) { char *str = str_data; const char *cstr = str; CHECK_ARG_(char, cstr, str); - CHECK_ARG_(wchar_t, cstr, str); - CHECK_ARG(cstr); string_view sref(str); CHECK_ARG_(char, sref, std::string(str)); - CHECK_ARG_(wchar_t, sref, std::string(str)); - CHECK_ARG(sref); } TEST(UtilTest, WStringArg) { @@ -578,8 +574,8 @@ TEST(UtilTest, WStringArg) { const wchar_t *cstr = str; fmt::wstring_view sref(str); - CHECK_ARG_(wchar_t, sref, str); - CHECK_ARG_(wchar_t, sref, cstr); + CHECK_ARG_(wchar_t, cstr, str); + CHECK_ARG_(wchar_t, cstr, cstr); CHECK_ARG_(wchar_t, sref, std::wstring(str)); CHECK_ARG_(wchar_t, sref, fmt::wstring_view(str)); }