diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 65a07306..014e027b 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -48,6 +48,8 @@ jobs: - cxx: clang++-14 build_type: Debug std: 20 + cxxflags: -fsanitize=address + cxxflags_extra: -fno-sanitize-recover=all -fno-omit-frame-pointer - cxx: clang++-14 build_type: Debug std: 20 @@ -154,7 +156,7 @@ jobs: working-directory: ${{runner.workspace}}/build env: CXX: ${{matrix.cxx}} - CXXFLAGS: ${{matrix.cxxflags}} + CXXFLAGS: ${{matrix.cxxflags}} ${{matrix.cxxflags_extra}} run: | cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \ -DCMAKE_CXX_STANDARD=${{matrix.std}} \ diff --git a/include/fmt/printf.h b/include/fmt/printf.h index 7f6f6f3a..c2e92291 100644 --- a/include/fmt/printf.h +++ b/include/fmt/printf.h @@ -330,6 +330,7 @@ template auto parse_header(const Char*& it, const Char* end, format_specs& specs, GetArg get_arg) -> int { int arg_index = -1; + if (it == end) return arg_index; Char c = *it; if (c >= '0' && c <= '9') { // Parse an argument index (if followed by '$') or a width possibly diff --git a/test/format-test.cc b/test/format-test.cc index c649aa4d..f18f3172 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -268,22 +268,6 @@ TEST(util_test, format_system_error) { fmt::format_system_error(message, EDOM, "test"); auto ec = std::error_code(EDOM, std::generic_category()); EXPECT_EQ(to_string(message), std::system_error(ec, "test").what()); - message = fmt::memory_buffer(); - - // Check if std::allocator throws on allocating max size_t / 2 chars. - size_t max_size = max_value() / 2; - bool throws_on_alloc = false; - try { - auto alloc = std::allocator(); - alloc.deallocate(alloc.allocate(max_size), max_size); - } catch (const std::bad_alloc&) { - throws_on_alloc = true; - } - if (!throws_on_alloc) { - fmt::print(stderr, "warning: std::allocator allocates {} chars\n", - max_size); - return; - } } TEST(util_test, system_error) { diff --git a/test/printf-test.cc b/test/printf-test.cc index f232263c..1b1f4f57 100644 --- a/test/printf-test.cc +++ b/test/printf-test.cc @@ -313,7 +313,8 @@ TEST(printf_test, positional_precision) { EXPECT_EQ("Hell", test_sprintf("%2$.*1$s", 4, "Hello")); EXPECT_THROW_MSG(test_sprintf("%2$.*1$d", 5.0, 42), format_error, "precision is not integer"); - EXPECT_THROW_MSG(test_sprintf("%2$.*1$d"), format_error, "argument not found"); + EXPECT_THROW_MSG(test_sprintf("%2$.*1$d"), format_error, + "argument not found"); EXPECT_THROW_MSG(test_sprintf("%2$.*1$d", big_num, 42), format_error, "number is too big"); } @@ -322,7 +323,8 @@ TEST(printf_test, positional_width_and_precision) { EXPECT_EQ(" 00042", test_sprintf("%3$*1$.*2$d", 7, 5, 42)); EXPECT_EQ(" ab", test_sprintf("%3$*1$.*2$s", 7, 2, "abcdef")); EXPECT_EQ(" 00042", test_sprintf("%3$*1$.*2$x", 7, 5, 0x42)); - EXPECT_EQ("100.4400000", test_sprintf("%6$-*5$.*4$f%3$s%2$s%1$s", "", "", "", 7, 4, 100.44)); + EXPECT_EQ("100.4400000", + test_sprintf("%6$-*5$.*4$f%3$s%2$s%1$s", "", "", "", 7, 4, 100.44)); } template struct make_signed { @@ -555,3 +557,8 @@ TEST(printf_test, make_printf_args) { fmt::vsprintf(fmt::basic_string_view(L"[%d] %s happened"), {fmt::make_printf_args(n, L"something")})); } + +TEST(printf_test, trailing_percent_non_nul_terminated) { + auto p = std::unique_ptr(new char('%')); + EXPECT_THROW(fmt::sprintf(fmt::string_view(p.get(), 1)), format_error); +}