Skip to content

Commit

Permalink
Don't access a C string past precision in printf (#1595)
Browse files Browse the repository at this point in the history
  • Loading branch information
vitaut committed Apr 22, 2020
1 parent 7d748a6 commit 0ca0d03
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 0 deletions.
15 changes: 15 additions & 0 deletions include/fmt/printf.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,13 @@ template <typename Context> class char_converter {
void operator()(T) {} // No conversion needed for non-integral types.
};

// An argument visitor that return a pointer to a C string if argument is a
// string or null otherwise.
template <typename Char> struct get_cstring {
template <typename T> const Char* operator()(T value) { return nullptr; }
const Char* operator()(const Char* s) { return s; }
};

// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
template <typename Char> class printf_width_handler {
Expand Down Expand Up @@ -561,6 +568,14 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
break;
}
}
if (specs.precision >= 0 &&
arg.type() == fmt::internal::type::cstring_type) {
auto str = visit_format_arg(internal::get_cstring<Char>(), arg);
auto end = str + specs.precision;
auto nul = std::find(str, end, Char());
arg = internal::make_arg<basic_printf_context>(basic_string_view<Char>(
str, nul != end ? nul - str : specs.precision));
}

start = it;

Expand Down
5 changes: 5 additions & 0 deletions test/printf-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,11 @@ TEST(PrintfTest, FloatPrecision) {
EXPECT_PRINTF(buffer, "%.3a", 1234.5678);
}

TEST(PrintfTest, StringPrecision) {
char test[] = {'H', 'e', 'l', 'l', 'o'};
EXPECT_EQ(fmt::sprintf("%.4s", test), "Hell");
}

TEST(PrintfTest, IgnorePrecisionForNonNumericArg) {
EXPECT_PRINTF("abc", "%.5s", "abc");
}
Expand Down

0 comments on commit 0ca0d03

Please sign in to comment.