diff --git a/src/stack_allocator.cpp b/src/stack_allocator.cpp index 81d113443..05522110b 100644 --- a/src/stack_allocator.cpp +++ b/src/stack_allocator.cpp @@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "libtorrent/stack_allocator.hpp" +#include // for va_list, va_copy, va_end namespace libtorrent { namespace aux { @@ -56,28 +57,44 @@ namespace aux { allocation_slot stack_allocator::format_string(char const* fmt, va_list v) { - int const ret = int(m_storage.size()); - int const max_size = 1024; - m_storage.resize(ret + max_size); + int const pos = int(m_storage.size()); + int len = 512; + + for(;;) + { + m_storage.resize(pos + len + 1); + + va_list args; + va_copy(args, v); #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wformat-nonliteral" #endif - int const len = std::vsnprintf(m_storage.data() + ret, max_size, fmt, v); + int const ret = std::vsnprintf(m_storage.data() + pos, static_cast(len + 1), fmt, args); #ifdef __clang__ #pragma clang diagnostic pop #endif - if (len < 0) - { - m_storage.resize(ret); - return copy_string("(format error)"); + va_end(args); + + if (ret < 0) + { + m_storage.resize(pos); + return copy_string("(format error)"); + } + if (ret > len) + { + // try again + len = ret; + continue; + } + break; } // +1 is to include the 0-terminator - m_storage.resize(ret + std::min(len, max_size) + 1); - return allocation_slot(ret); + m_storage.resize(pos + len + 1); + return allocation_slot(pos); } allocation_slot stack_allocator::copy_buffer(span buf) diff --git a/test/test_stack_allocator.cpp b/test/test_stack_allocator.cpp index 8d7ccbd77..f0a474f72 100644 --- a/test/test_stack_allocator.cpp +++ b/test/test_stack_allocator.cpp @@ -33,6 +33,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "test.hpp" #include "libtorrent/stack_allocator.hpp" #include "libtorrent/string_view.hpp" +#include // for va_list, va_start, va_end using lt::aux::stack_allocator; using lt::aux::allocation_slot; @@ -107,3 +108,34 @@ TORRENT_TEST(swap) TEST_CHECK(a2.ptr(idx1) == "testing"_sv); } +namespace { + +TORRENT_FORMAT(2,3) +allocation_slot format_string_helper(stack_allocator& stack, char const* fmt, ...) +{ + va_list v; + va_start(v, fmt); + auto const ret = stack.format_string(fmt, v); + va_end(v); + return ret; +} + +} + +TORRENT_TEST(format_string_long) +{ + stack_allocator a; + std::string long_string; + for (int i = 0; i < 1024; ++i) long_string += "foobar-"; + auto const idx = format_string_helper(a, "%s", long_string.c_str()); + + TEST_EQUAL(a.ptr(idx), long_string); +} + +TORRENT_TEST(format_string) +{ + stack_allocator a; + auto const idx = format_string_helper(a, "%d", 10); + + TEST_EQUAL(a.ptr(idx), "10"_sv); +}