Handle null terminator at the end of the buffer

This commit is contained in:
Victor Zverovich 2019-11-24 06:38:01 -08:00
parent 63a9f3fcd4
commit 43271ba8e8
2 changed files with 24 additions and 18 deletions

View File

@ -1159,7 +1159,8 @@ int snprintf_float(T value, int precision, float_spec spec, buffer<char>& buf) {
continue; continue;
} }
unsigned size = to_unsigned(result); unsigned size = to_unsigned(result);
if (size > capacity) { // Size equal to capacity means that the last character was truncated.
if (size >= capacity) {
buf.reserve(size + 1); // Add 1 for the terminating '\0'. buf.reserve(size + 1); // Add 1 for the terminating '\0'.
continue; continue;
} }

View File

@ -40,13 +40,13 @@
using std::size_t; using std::size_t;
using fmt::basic_memory_buffer; using fmt::basic_memory_buffer;
using fmt::internal::basic_writer;
using fmt::internal::max_value;
using fmt::format; using fmt::format;
using fmt::format_error; using fmt::format_error;
using fmt::memory_buffer; using fmt::memory_buffer;
using fmt::string_view; using fmt::string_view;
using fmt::wmemory_buffer; using fmt::wmemory_buffer;
using fmt::internal::basic_writer;
using fmt::internal::max_value;
using testing::Return; using testing::Return;
using testing::StrictMock; using testing::StrictMock;
@ -169,8 +169,7 @@ TEST(UtilTest, Increment) {
} }
TEST(UtilTest, ParseNonnegativeInt) { TEST(UtilTest, ParseNonnegativeInt) {
if (max_value<int>() != if (max_value<int>() != static_cast<int>(static_cast<unsigned>(1) << 31)) {
static_cast<int>(static_cast<unsigned>(1) << 31)) {
fmt::print("Skipping parse_nonnegative_int test\n"); fmt::print("Skipping parse_nonnegative_int test\n");
return; return;
} }
@ -539,9 +538,8 @@ TEST(UtilTest, FormatWindowsError) {
EXPECT_EQ(fmt::format("test: {}", utf8_message.str()), EXPECT_EQ(fmt::format("test: {}", utf8_message.str()),
fmt::to_string(actual_message)); fmt::to_string(actual_message));
actual_message.resize(0); actual_message.resize(0);
fmt::internal::format_windows_error( fmt::internal::format_windows_error(actual_message, ERROR_FILE_EXISTS,
actual_message, ERROR_FILE_EXISTS, fmt::string_view(0, max_value<size_t>()));
fmt::string_view(0, max_value<size_t>()));
EXPECT_EQ(fmt::format("error {}", ERROR_FILE_EXISTS), EXPECT_EQ(fmt::format("error {}", ERROR_FILE_EXISTS),
fmt::to_string(actual_message)); fmt::to_string(actual_message));
} }
@ -687,9 +685,7 @@ TEST(WriterTest, WriteString) {
CHECK_WRITE_WCHAR("abc"); CHECK_WRITE_WCHAR("abc");
} }
TEST(WriterTest, WriteWideString) { TEST(WriterTest, WriteWideString) { CHECK_WRITE_WCHAR(L"abc"); }
CHECK_WRITE_WCHAR(L"abc");
}
TEST(FormatToTest, FormatWithoutArgs) { TEST(FormatToTest, FormatWithoutArgs) {
std::string s; std::string s;
@ -1207,6 +1203,15 @@ TEST(FormatterTest, Precision) {
EXPECT_EQ("1.2", format("{0:.2}", 1.2345)); EXPECT_EQ("1.2", format("{0:.2}", 1.2345));
EXPECT_EQ("1.2", format("{0:.2}", 1.2345l)); EXPECT_EQ("1.2", format("{0:.2}", 1.2345l));
EXPECT_EQ("1.2e+56", format("{:.2}", 1.234e56)); EXPECT_EQ("1.2e+56", format("{:.2}", 1.234e56));
EXPECT_EQ(
"4.9406564584124654417656879286822137236505980261432476442558568250067550"
"727020875186529983636163599237979656469544571773092665671035593979639877"
"479601078187812630071319031140452784581716784898210368871863605699873072"
"305000638740915356498438731247339727316961514003171538539807412623856559"
"117102665855668676818703956031062493194527159149245532930545654440112748"
"012970999954193198940908041656332452475714786901472678015935523861155013"
"480352649347201937902681071074917033322268447533357208324319361e-324",
format("{:.494}", 4.9406564584124654E-324));
EXPECT_THROW_MSG(format("{0:.2}", reinterpret_cast<void*>(0xcafe)), EXPECT_THROW_MSG(format("{0:.2}", reinterpret_cast<void*>(0xcafe)),
format_error, format_error,
@ -1806,8 +1811,7 @@ TEST(FormatIntTest, FormatInt) {
EXPECT_EQ("-42", fmt::format_int(-42ll).str()); EXPECT_EQ("-42", fmt::format_int(-42ll).str());
std::ostringstream os; std::ostringstream os;
os << max_value<int64_t>(); os << max_value<int64_t>();
EXPECT_EQ(os.str(), EXPECT_EQ(os.str(), fmt::format_int(max_value<int64_t>()).str());
fmt::format_int(max_value<int64_t>()).str());
} }
TEST(FormatTest, Print) { TEST(FormatTest, Print) {
@ -1966,8 +1970,9 @@ enum TestEnum { A };
TEST(FormatTest, Enum) { EXPECT_EQ("0", fmt::format("{}", A)); } TEST(FormatTest, Enum) { EXPECT_EQ("0", fmt::format("{}", A)); }
TEST(FormatTest, FormatterNotSpecialized) { TEST(FormatTest, FormatterNotSpecialized) {
static_assert(!fmt::has_formatter<fmt::formatter<TestEnum>, static_assert(
fmt::format_context>::value, ""); !fmt::has_formatter<fmt::formatter<TestEnum>, fmt::format_context>::value,
"");
} }
#if FMT_HAS_FEATURE(cxx_strong_enums) #if FMT_HAS_FEATURE(cxx_strong_enums)
@ -2449,11 +2454,11 @@ TEST(FormatTest, FormatStringErrors) {
EXPECT_ERROR("{:10000000000}", "number is too big", int); EXPECT_ERROR("{:10000000000}", "number is too big", int);
EXPECT_ERROR("{:.10000000000}", "number is too big", int); EXPECT_ERROR("{:.10000000000}", "number is too big", int);
EXPECT_ERROR_NOARGS("{:x}", "argument index out of range"); EXPECT_ERROR_NOARGS("{:x}", "argument index out of range");
#if FMT_NUMERIC_ALIGN # if FMT_NUMERIC_ALIGN
EXPECT_ERROR("{0:=5", "unknown format specifier", int); EXPECT_ERROR("{0:=5", "unknown format specifier", int);
EXPECT_ERROR("{:=}", "format specifier requires numeric argument", EXPECT_ERROR("{:=}", "format specifier requires numeric argument",
const char*); const char*);
#endif # endif
EXPECT_ERROR("{:+}", "format specifier requires numeric argument", EXPECT_ERROR("{:+}", "format specifier requires numeric argument",
const char*); const char*);
EXPECT_ERROR("{:-}", "format specifier requires numeric argument", EXPECT_ERROR("{:-}", "format specifier requires numeric argument",
@ -2613,7 +2618,7 @@ TEST(FormatTest, FormatCustomChar) {
TEST(FormatTest, FormatUTF8Precision) { TEST(FormatTest, FormatUTF8Precision) {
using str_type = std::basic_string<char8_t>; using str_type = std::basic_string<char8_t>;
str_type format(reinterpret_cast<const char8_t*>(u8"{:.4}")); str_type format(reinterpret_cast<const char8_t*>(u8"{:.4}"));
str_type str(reinterpret_cast<const char8_t*>(u8"caf\u00e9s")); // cafés str_type str(reinterpret_cast<const char8_t*>(u8"caf\u00e9s")); // cafés
auto result = fmt::format(format, str); auto result = fmt::format(format, str);
EXPECT_EQ(fmt::internal::count_code_points(result), 4); EXPECT_EQ(fmt::internal::count_code_points(result), 4);
EXPECT_EQ(result.size(), 5); EXPECT_EQ(result.size(), 5);