Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into fuzz
Browse files Browse the repository at this point in the history
  • Loading branch information
pauldreik committed Jun 17, 2019
2 parents 28add37 + 4912cff commit 4102d82
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 93 deletions.
26 changes: 11 additions & 15 deletions include/fmt/format-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ inline fmt::internal::null<> strerror_s(char*, std::size_t, ...) {
}

FMT_BEGIN_NAMESPACE

namespace {
namespace internal {

#ifndef _MSC_VER
# define FMT_SNPRINTF snprintf
Expand All @@ -79,12 +78,6 @@ inline int fmt_snprintf(char* buffer, size_t size, const char* format, ...) {
# define FMT_SNPRINTF fmt_snprintf
#endif // _MSC_VER

#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
# define FMT_SWPRINTF snwprintf
#else
# define FMT_SWPRINTF swprintf
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)

typedef void (*FormatFunc)(internal::buffer<char>&, int, string_view);

// Portable thread-safe version of strerror.
Expand Down Expand Up @@ -198,7 +191,7 @@ void report_error(FormatFunc func, int error_code,
fwrite_fully(full_message.data(), 1, full_message.size(), stderr);
std::fputc('\n', stderr);
}
} // namespace
} // namespace internal

#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
namespace internal {
Expand Down Expand Up @@ -236,7 +229,7 @@ FMT_FUNC void system_error::init(int err_code, string_view format_str,

namespace internal {

template <> FMT_FUNC int count_digits<4>(internal::uintptr n) {
template <> FMT_FUNC int count_digits<4>(internal::fallback_uintptr n) {
// Assume little endian; pointer formatting is implementation-defined anyway.
int i = static_cast<int>(sizeof(void*)) - 1;
while (i > 0 && n.value[i] == 0) --i;
Expand All @@ -247,8 +240,10 @@ template <> FMT_FUNC int count_digits<4>(internal::uintptr n) {
template <typename T>
int format_float(char* buf, std::size_t size, const char* format, int precision,
T value) {
return precision < 0 ? FMT_SNPRINTF(buf, size, format, value)
: FMT_SNPRINTF(buf, size, format, precision, value);
// Suppress the warning about nonliteral format string.
auto snprintf_ptr = FMT_SNPRINTF;
return precision < 0 ? snprintf_ptr(buf, size, format, value)
: snprintf_ptr(buf, size, format, precision, value);
}

template <typename T>
Expand Down Expand Up @@ -925,7 +920,8 @@ FMT_FUNC void format_system_error(internal::buffer<char>& out, int error_code,
buf.resize(inline_buffer_size);
for (;;) {
char* system_message = &buf[0];
int result = safe_strerror(error_code, system_message, buf.size());
int result =
internal::safe_strerror(error_code, system_message, buf.size());
if (result == 0) {
writer w(out);
w.write(message);
Expand Down Expand Up @@ -962,13 +958,13 @@ FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) {
memory_buffer buffer;
internal::vformat_to(buffer, format_str,
basic_format_args<buffer_context<char>>(args));
fwrite_fully(buffer.data(), 1, buffer.size(), f);
internal::fwrite_fully(buffer.data(), 1, buffer.size(), f);
}

FMT_FUNC void vprint(std::FILE* f, wstring_view format_str, wformat_args args) {
wmemory_buffer buffer;
internal::vformat_to(buffer, format_str, args);
fwrite_fully(buffer.data(), sizeof(wchar_t), buffer.size(), f);
internal::fwrite_fully(buffer.data(), sizeof(wchar_t), buffer.size(), f);
}

FMT_FUNC void vprint(string_view format_str, format_args args) {
Expand Down
102 changes: 37 additions & 65 deletions include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,20 +60,17 @@
# define FMT_CUDA_VERSION 0
#endif

#if FMT_GCC_VERSION >= 406 || FMT_CLANG_VERSION
# pragma GCC diagnostic push
#ifdef __GNUC_LIBSTD__
# define FMT_GNUC_LIBSTD_VERSION \
(__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__)
#endif

// Disable warning about not handling all enums in switch statement even with
// a default case
# pragma GCC diagnostic ignored "-Wswitch-enum"
#if FMT_GCC_VERSION || FMT_CLANG_VERSION
# pragma GCC diagnostic push

// Disable the warning about declaration shadowing because it affects too
// many valid cases.
# pragma GCC diagnostic ignored "-Wshadow"

// Disable the warning about nonliteral format strings because we construct
// them dynamically when falling back to snprintf for FP formatting.
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif

#if FMT_CLANG_VERSION
Expand Down Expand Up @@ -101,11 +98,6 @@
# define FMT_HAS_BUILTIN(x) 0
#endif

#ifdef __GNUC_LIBSTD__
# define FMT_GNUC_LIBSTD_VERSION \
(__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__)
#endif

#ifndef FMT_THROW
# if FMT_EXCEPTIONS
# if FMT_MSC_VER
Expand All @@ -128,13 +120,12 @@ FMT_END_NAMESPACE
do { \
static_cast<void>(sizeof(x)); \
assert(false); \
} while (false);
} while (false)
# endif
#endif

#ifndef FMT_USE_USER_DEFINED_LITERALS
// For Intel's compiler and NVIDIA's compiler both it and the system gcc/msc
// must support UDLs.
// For Intel and NVIDIA compilers both they and the system gcc/msc support UDLs.
# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \
FMT_MSC_VER >= 1900) && \
(!(FMT_ICC_VERSION || FMT_CUDA_VERSION) || FMT_ICC_VERSION >= 1500 || \
Expand Down Expand Up @@ -170,11 +161,11 @@ FMT_END_NAMESPACE
// __builtin_clz is broken in clang with Microsoft CodeGen:
// https://github.com/fmtlib/fmt/issues/519
#ifndef _MSC_VER
# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz)
# if FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clz)
# define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
# endif

# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll)
# if FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clzll)
# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
# endif
#endif
Expand Down Expand Up @@ -240,13 +231,13 @@ namespace internal {
#endif

// A fallback implementation of uintptr_t for systems that lack it.
struct uintptr {
struct fallback_uintptr {
unsigned char value[sizeof(void*)];
};
#ifdef UINTPTR_MAX
using uintptr_t = ::uintptr_t;
#else
using uintptr_t = uintptr;
using uintptr_t = fallback_uintptr;
#endif

template <typename T> inline bool use_grisu() {
Expand All @@ -268,19 +259,8 @@ inline Dest bit_cast(const Source& source) {
// An implementation of iterator_t for pre-C++20 systems.
template <typename T>
using iterator_t = decltype(std::begin(std::declval<T&>()));

template <typename Allocator>
typename Allocator::value_type* allocate(Allocator& alloc, std::size_t n) {
#if __cplusplus >= 201103L || FMT_MSC_VER >= 1700
return std::allocator_traits<Allocator>::allocate(alloc, n);
#else
return alloc.allocate(n);
#endif
}
} // namespace internal

template <typename Range> class basic_writer;

template <typename OutputIt, typename T = typename OutputIt::value_type>
class output_range {
private:
Expand All @@ -302,17 +282,18 @@ class output_range {
template <typename Container>
class back_insert_range
: public output_range<std::back_insert_iterator<Container>> {
typedef output_range<std::back_insert_iterator<Container>> base;
using base = output_range<std::back_insert_iterator<Container>>;

public:
typedef typename Container::value_type value_type;
using value_type = typename Container::value_type;

back_insert_range(Container& c) : base(std::back_inserter(c)) {}
back_insert_range(typename base::iterator it) : base(it) {}
};

typedef basic_writer<back_insert_range<internal::buffer<char>>> writer;
typedef basic_writer<back_insert_range<internal::buffer<wchar_t>>> wwriter;
template <typename Range> class basic_writer;
using writer = basic_writer<back_insert_range<internal::buffer<char>>>;
using wwriter = basic_writer<back_insert_range<internal::buffer<wchar_t>>>;

/** A formatting error such as invalid format string. */
class format_error : public std::runtime_error {
Expand Down Expand Up @@ -485,7 +466,7 @@ void basic_memory_buffer<T, SIZE, Allocator>::grow(std::size_t size) {
std::size_t new_capacity = old_capacity + old_capacity / 2;
if (size > new_capacity) new_capacity = size;
T* old_data = this->data();
T* new_data = internal::allocate<Allocator>(*this, new_capacity);
T* new_data = std::allocator_traits<Allocator>::allocate(*this, new_capacity);
// The following code doesn't throw, so the raw pointer above doesn't leak.
std::uninitialized_copy(old_data, old_data + this->size(),
internal::make_checked(new_data, new_capacity));
Expand Down Expand Up @@ -713,7 +694,7 @@ template <unsigned BITS, typename UInt> inline int count_digits(UInt n) {
return num_digits;
}

template <> int count_digits<4>(internal::uintptr n);
template <> int count_digits<4>(internal::fallback_uintptr n);

template <typename Char>
inline size_t count_code_points(basic_string_view<Char> s) {
Expand Down Expand Up @@ -942,7 +923,7 @@ inline Char* format_uint(Char* buffer, UInt value, int num_digits,
}

template <unsigned BASE_BITS, typename Char>
Char* format_uint(Char* buffer, internal::uintptr n, int num_digits,
Char* format_uint(Char* buffer, internal::fallback_uintptr n, int num_digits,
bool = false) {
auto char_digits = std::numeric_limits<unsigned char>::digits / 4;
int start = (num_digits + char_digits - 1) / char_digits - 1;
Expand Down Expand Up @@ -1326,27 +1307,14 @@ void arg_map<Context>::init(const basic_format_args<Context>& args) {
if (args.is_packed()) {
for (unsigned i = 0; /*nothing*/; ++i) {
internal::type arg_type = args.type(i);
switch (arg_type) {
case internal::none_type:
return;
case internal::named_arg_type:
push_back(args.values_[i]);
break;
default:
break; // Do nothing.
}
if (arg_type == internal::none_type) return;
if (arg_type == internal::named_arg_type) push_back(args.values_[i]);
}
}
for (unsigned i = 0;; ++i) {
switch (args.args_[i].type_) {
case internal::none_type:
return;
case internal::named_arg_type:
push_back(args.args_[i].value_);
break;
default:
break; // Do nothing.
}
auto type = args.args_[i].type_;
if (type == internal::none_type) return;
if (type == internal::named_arg_type) push_back(args.args_[i].value_);
}
}

Expand Down Expand Up @@ -2139,10 +2107,14 @@ FMT_CONSTEXPR void parse_format_string(basic_string_view<Char> format_str,
template <typename T, typename ParseContext>
FMT_CONSTEXPR const typename ParseContext::char_type* parse_format_specs(
ParseContext& ctx) {
// GCC 7.2 requires initializer.
typedef typename ParseContext::char_type char_type;
conditional_t<has_formatter<T, buffer_context<char_type>>::value,
formatter<T, char_type>,
using char_type = typename ParseContext::char_type;
using context = buffer_context<char_type>;
using mapped_type =
conditional_t<internal::mapped_type_constant<T, context>::value !=
internal::custom_type,
decltype(arg_mapper<context>().map(std::declval<T>())), T>;
conditional_t<has_formatter<mapped_type, context>::value,
formatter<mapped_type, char_type>,
internal::fallback_formatter<T, char_type>>
f;
return f.parse(ctx);
Expand Down Expand Up @@ -3323,14 +3295,14 @@ arg_join<It, wchar_t> join(It begin, It end, wstring_view sep) {
\endrst
*/
template <typename Range>
arg_join<internal::iterator_t<const Range>, char> join(
const Range& range, string_view sep) {
arg_join<internal::iterator_t<const Range>, char> join(const Range& range,
string_view sep) {
return join(std::begin(range), std::end(range), sep);
}

template <typename Range>
arg_join<internal::iterator_t<const Range>, wchar_t> join(
const Range& range, wstring_view sep) {
arg_join<internal::iterator_t<const Range>, wchar_t> join(const Range& range,
wstring_view sep) {
return join(std::begin(range), std::end(range), sep);
}
#endif
Expand Down
22 changes: 12 additions & 10 deletions test/format-impl-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,9 @@ TEST(FormatTest, FormatNegativeNaN) {
TEST(FormatTest, StrError) {
char* message = nullptr;
char buffer[BUFFER_SIZE];
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = nullptr, 0),
EXPECT_ASSERT(fmt::internal::safe_strerror(EDOM, message = nullptr, 0),
"invalid buffer");
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = buffer, 0),
EXPECT_ASSERT(fmt::internal::safe_strerror(EDOM, message = buffer, 0),
"invalid buffer");
buffer[0] = 'x';
#if defined(_GNU_SOURCE) && !defined(__COVERITY__)
Expand All @@ -184,17 +184,19 @@ TEST(FormatTest, StrError) {
int error_code = EDOM;
#endif

int result = fmt::safe_strerror(error_code, message = buffer, BUFFER_SIZE);
int result =
fmt::internal::safe_strerror(error_code, message = buffer, BUFFER_SIZE);
EXPECT_EQ(result, 0);
std::size_t message_size = std::strlen(message);
EXPECT_GE(BUFFER_SIZE - 1u, message_size);
EXPECT_EQ(get_system_error(error_code), message);

// safe_strerror never uses buffer on MinGW.
#ifndef __MINGW32__
result = fmt::safe_strerror(error_code, message = buffer, message_size);
result =
fmt::internal::safe_strerror(error_code, message = buffer, message_size);
EXPECT_EQ(ERANGE, result);
result = fmt::safe_strerror(error_code, message = buffer, 1);
result = fmt::internal::safe_strerror(error_code, message = buffer, 1);
EXPECT_EQ(buffer, message); // Message should point to buffer.
EXPECT_EQ(ERANGE, result);
EXPECT_STREQ("", message);
Expand All @@ -206,14 +208,14 @@ TEST(FormatTest, FormatErrorCode) {
{
fmt::memory_buffer buffer;
format_to(buffer, "garbage");
fmt::format_error_code(buffer, 42, "test");
fmt::internal::format_error_code(buffer, 42, "test");
EXPECT_EQ("test: " + msg, to_string(buffer));
}
{
fmt::memory_buffer buffer;
std::string prefix(fmt::inline_buffer_size - msg.size() - sep.size() + 1,
'x');
fmt::format_error_code(buffer, 42, prefix);
fmt::internal::format_error_code(buffer, 42, prefix);
EXPECT_EQ(msg, to_string(buffer));
}
int codes[] = {42, -1};
Expand All @@ -222,14 +224,14 @@ TEST(FormatTest, FormatErrorCode) {
msg = fmt::format("error {}", codes[i]);
fmt::memory_buffer buffer;
std::string prefix(fmt::inline_buffer_size - msg.size() - sep.size(), 'x');
fmt::format_error_code(buffer, codes[i], prefix);
fmt::internal::format_error_code(buffer, codes[i], prefix);
EXPECT_EQ(prefix + sep + msg, to_string(buffer));
std::size_t size = fmt::inline_buffer_size;
EXPECT_EQ(size, buffer.size());
buffer.resize(0);
// Test with a message that doesn't fit into the buffer.
prefix += 'x';
fmt::format_error_code(buffer, codes[i], prefix);
fmt::internal::format_error_code(buffer, codes[i], prefix);
EXPECT_EQ(msg, to_string(buffer));
}
}
Expand Down Expand Up @@ -257,7 +259,7 @@ TEST(UtilTest, CountDigits) {
TEST(UtilTest, WriteUIntPtr) {
fmt::memory_buffer buf;
fmt::writer writer(buf);
writer.write_pointer(fmt::internal::bit_cast<fmt::internal::uintptr>(
writer.write_pointer(fmt::internal::bit_cast<fmt::internal::fallback_uintptr>(
reinterpret_cast<void*>(0xface)),
nullptr);
EXPECT_EQ("0xface", to_string(buf));
Expand Down
Loading

0 comments on commit 4102d82

Please sign in to comment.