From dd8cc8b0ba7a90e64b7b6507ec80b87ff585946f Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Tue, 9 Jul 2019 11:50:16 -0700 Subject: [PATCH] Disallow passing views as lvalues --- include/fmt/core.h | 41 ++++++++++++++++++++++++++--------------- include/fmt/format.h | 10 +++++----- include/fmt/locale.h | 10 +++++----- include/fmt/ostream.h | 5 ++--- include/fmt/prepare.h | 18 ++++++++++-------- include/fmt/printf.h | 27 ++++++++++++--------------- 6 files changed, 60 insertions(+), 51 deletions(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index 76b684fd..08312f7c 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -1260,10 +1260,20 @@ inline void check_format_string(const S&) {} template ::value)> void check_format_string(S); -template > -inline format_arg_store, Args...> make_args_checked( - const S& format_str, const Args&... args) { - check_format_string(format_str); +struct view {}; +template struct bool_pack; +template +using all_true = + std::is_same, bool_pack>; + +template > +inline format_arg_store, remove_reference_t...> +make_args_checked(const S& format_str, + const remove_reference_t&... args) { + static_assert(all_true<(!std::is_base_of>() || + !std::is_reference())...>::value, + "passing views as lvalues is disallowed"); + check_format_string...>(format_str); return {args...}; } @@ -1321,9 +1331,10 @@ template ::value&& internal::is_string::value)> inline std::back_insert_iterator format_to( std::back_insert_iterator out, const S& format_str, - const Args&... args) { - return vformat_to(out, to_string_view(format_str), - {internal::make_args_checked(format_str, args...)}); + Args&&... args) { + return vformat_to( + out, to_string_view(format_str), + {internal::make_args_checked(format_str, args...)}); } template > @@ -1345,10 +1356,10 @@ inline std::basic_string vformat( // Pass char_t as a default template parameter instead of using // std::basic_string> to reduce the symbol size. template > -inline std::basic_string format(const S& format_str, - const Args&... args) { - return internal::vformat(to_string_view(format_str), - {internal::make_args_checked(format_str, args...)}); +inline std::basic_string format(const S& format_str, Args&&... args) { + return internal::vformat( + to_string_view(format_str), + {internal::make_args_checked(format_str, args...)}); } FMT_API void vprint(std::FILE* f, string_view format_str, format_args args); @@ -1367,9 +1378,9 @@ FMT_API void vprint(std::FILE* f, wstring_view format_str, wformat_args args); */ template ::value)> -inline void print(std::FILE* f, const S& format_str, const Args&... args) { +inline void print(std::FILE* f, const S& format_str, Args&&... args) { vprint(f, to_string_view(format_str), - internal::make_args_checked(format_str, args...)); + internal::make_args_checked(format_str, args...)); } FMT_API void vprint(string_view format_str, format_args args); @@ -1386,9 +1397,9 @@ FMT_API void vprint(wstring_view format_str, wformat_args args); */ template ::value)> -inline void print(const S& format_str, const Args&... args) { +inline void print(const S& format_str, Args&&... args) { vprint(to_string_view(format_str), - internal::make_args_checked(format_str, args...)); + internal::make_args_checked(format_str, args...)); } FMT_END_NAMESPACE diff --git a/include/fmt/format.h b/include/fmt/format.h index 753696c6..ff780416 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3218,10 +3218,12 @@ template inline const void* ptr(const std::shared_ptr& p) { return p.get(); } -template struct arg_join { +template struct arg_join : internal::view { It begin; It end; basic_string_view sep; + + arg_join(It b, It e, basic_string_view s) : begin(b), end(e), sep(s) {} }; template @@ -3330,8 +3332,7 @@ inline typename buffer_context::iterator vformat_to( template ::value, char_t>> inline typename buffer_context::iterator format_to( - basic_memory_buffer& buf, const S& format_str, - const Args&... args) { + basic_memory_buffer& buf, const S& format_str, Args&&... args) { internal::check_format_string(format_str); using context = buffer_context; return internal::vformat_to(buf, to_string_view(format_str), @@ -3367,8 +3368,7 @@ inline OutputIt vformat_to(OutputIt out, const S& format_str, \endrst */ template -inline OutputIt format_to(OutputIt out, const S& format_str, - const Args&... args) { +inline OutputIt format_to(OutputIt out, const S& format_str, Args&&... args) { static_assert(internal::is_output_iterator::value && internal::is_string::value, ""); diff --git a/include/fmt/locale.h b/include/fmt/locale.h index df8fff76..7c13656e 100644 --- a/include/fmt/locale.h +++ b/include/fmt/locale.h @@ -43,10 +43,10 @@ inline std::basic_string vformat( template > inline std::basic_string format(const std::locale& loc, - const S& format_str, - const Args&... args) { - return internal::vformat(loc, to_string_view(format_str), - {internal::make_args_checked(format_str, args...)}); + const S& format_str, Args&&... args) { + return internal::vformat( + loc, to_string_view(format_str), + {internal::make_args_checked(format_str, args...)}); } template ::value&& internal::is_string::value)> inline OutputIt format_to(OutputIt out, const std::locale& loc, - const S& format_str, const Args&... args) { + const S& format_str, Args&&... args) { internal::check_format_string(format_str); using context = format_context_t>; format_arg_store as{args...}; diff --git a/include/fmt/ostream.h b/include/fmt/ostream.h index a2248bef..69bac0e2 100644 --- a/include/fmt/ostream.h +++ b/include/fmt/ostream.h @@ -127,10 +127,9 @@ void vprint(std::basic_ostream& os, basic_string_view format_str, */ template ::value, char_t>> -void print(std::basic_ostream& os, const S& format_str, - const Args&... args) { +void print(std::basic_ostream& os, const S& format_str, Args&&... args) { vprint(os, to_string_view(format_str), - {internal::make_args_checked(format_str, args...)}); + {internal::make_args_checked(format_str, args...)}); } FMT_END_NAMESPACE diff --git a/include/fmt/prepare.h b/include/fmt/prepare.h index 67d3f1a6..7e144116 100644 --- a/include/fmt/prepare.h +++ b/include/fmt/prepare.h @@ -215,18 +215,20 @@ class prepared_format { std::basic_string format(const Args&... args) const { basic_memory_buffer buffer; using range = buffer_range; - this->vformat_to(range(buffer), basic_format_args{ - make_args_checked(format_, args...)}); + this->vformat_to(range(buffer), + basic_format_args{ + make_args_checked(format_, args...)}); return to_string(buffer); } template ::value)> inline std::back_insert_iterator format_to( - std::back_insert_iterator out, const Args&... args) const { + std::back_insert_iterator out, Args&&... args) const { internal::container_buffer buffer(internal::get_container(out)); using range = buffer_range; - this->vformat_to(range(buffer), basic_format_args{ - make_args_checked(format_, args...)}); + this->vformat_to(range(buffer), + basic_format_args{ + make_args_checked(format_, args...)}); return out; } @@ -242,9 +244,9 @@ class prepared_format { inline typename buffer_context::iterator format_to( basic_memory_buffer& buf, const Args&... args) const { using range = buffer_range; - return this->vformat_to( - range(buf), - basic_format_args{make_args_checked(format_, args...)}); + return this->vformat_to(range(buf), + basic_format_args{ + make_args_checked(format_, args...)}); } private: diff --git a/include/fmt/printf.h b/include/fmt/printf.h index 267724a7..c803aa95 100644 --- a/include/fmt/printf.h +++ b/include/fmt/printf.h @@ -138,7 +138,7 @@ template class char_converter { template ::value)> void operator()(T value) { arg_ = internal::make_arg( - static_cast(value)); + static_cast(value)); } template ::value)> @@ -563,9 +563,10 @@ OutputIt basic_printf_context::format() { return std::copy(start, it, out); } -template using basic_printf_context_t = - basic_printf_context>, - Char>; +template +using basic_printf_context_t = + basic_printf_context>, + Char>; using printf_context = basic_printf_context_t; using wprintf_context = basic_printf_context_t; @@ -599,8 +600,7 @@ inline format_arg_store make_wprintf_args( template > inline std::basic_string vsprintf( - const S& format, - basic_format_args> args) { + const S& format, basic_format_args> args) { basic_memory_buffer buffer; printf(buffer, to_string_view(format), args); return to_string(buffer); @@ -623,9 +623,8 @@ inline std::basic_string sprintf(const S& format, const Args&... args) { } template > -inline int vfprintf( - std::FILE* f, const S& format, - basic_format_args> args) { +inline int vfprintf(std::FILE* f, const S& format, + basic_format_args> args) { basic_memory_buffer buffer; printf(buffer, to_string_view(format), args); std::size_t size = buffer.size(); @@ -652,9 +651,8 @@ inline int fprintf(std::FILE* f, const S& format, const Args&... args) { } template > -inline int vprintf( - const S& format, - basic_format_args> args) { +inline int vprintf(const S& format, + basic_format_args> args) { return vfprintf(stdout, to_string_view(format), args); } @@ -676,9 +674,8 @@ inline int printf(const S& format_str, const Args&... args) { } template > -inline int vfprintf( - std::basic_ostream& os, const S& format, - basic_format_args> args) { +inline int vfprintf(std::basic_ostream& os, const S& format, + basic_format_args> args) { basic_memory_buffer buffer; printf(buffer, to_string_view(format), args); internal::write(os, buffer);