Skip to content

Commit

Permalink
Disallow formatting of multibyte strings into a wide buffer (#606)
Browse files Browse the repository at this point in the history
  • Loading branch information
vitaut committed Nov 19, 2017
1 parent 3851994 commit ba01a5d
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 32 deletions.
50 changes: 22 additions & 28 deletions include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -1189,10 +1189,10 @@ template <> constexpr type get_type<unsigned char *>() { return CSTRING; }
template <> constexpr type get_type<const unsigned char *>() { return CSTRING; }
template <> constexpr type get_type<std::string>() { return STRING; }
template <> constexpr type get_type<string_view>() { return STRING; }
template <> constexpr type get_type<wchar_t *>() { return TSTRING; }
template <> constexpr type get_type<const wchar_t *>() { return TSTRING; }
template <> constexpr type get_type<std::wstring>() { return TSTRING; }
template <> constexpr type get_type<wstring_view>() { return TSTRING; }
template <> constexpr type get_type<wchar_t *>() { return CSTRING; }
template <> constexpr type get_type<const wchar_t *>() { return CSTRING; }
template <> constexpr type get_type<std::wstring>() { return STRING; }
template <> constexpr type get_type<wstring_view>() { return STRING; }
template <> constexpr type get_type<void *>() { return POINTER; }
template <> constexpr type get_type<const void *>() { return POINTER; }
template <> constexpr type get_type<std::nullptr_t>() { return POINTER; }
Expand Down Expand Up @@ -1225,10 +1225,9 @@ class value {
double double_value;
long double long_double_value;
const void *pointer;
string_value<char> string;
string_value<char_type> string;
string_value<signed char> sstring;
string_value<unsigned char> ustring;
string_value<char_type> tstring;
custom_value<char_type> custom;
};

Expand Down Expand Up @@ -1271,18 +1270,16 @@ class value {
}
#endif

value(char *s) { set<CSTRING>(string.value, s); }
value(const char *s) { set<CSTRING>(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(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<CSTRING>(string.value, s); }
value(const char_type *s) { set<CSTRING>(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<char_type> s) { set_string(s); }
value(const std::basic_string<char_type> &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
Expand Down Expand Up @@ -1338,12 +1335,11 @@ class value {
string.size = value.size();
}

template <typename T>
void set_wstring(const T &value) {
require_wchar<char_type>();
static_assert(get_type<T>() == TSTRING, "invalid type");
tstring.value = value.data();
tstring.size = value.size();
template <typename T, typename U>
constexpr void set_cstring(T &field, const U *str) {
static_assert(std::is_same<char, char_type>::value,
"incompatible string types");
set<CSTRING>(field, str);
}

// Formats an argument of a custom type, such as a user-defined class.
Expand Down Expand Up @@ -1439,10 +1435,8 @@ constexpr typename std::result_of<Visitor(int)>::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<Char>(
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:
Expand Down
4 changes: 0 additions & 4 deletions test/util-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit ba01a5d

Please sign in to comment.