make stack_allocator::format_string() grow the buffer for large strings

This commit is contained in:
arvidn 2018-11-29 00:55:31 +01:00 committed by Arvid Norberg
parent 507fffe872
commit eb5f29a79c
2 changed files with 59 additions and 10 deletions

View File

@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/stack_allocator.hpp"
#include <cstdarg> // 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<std::size_t>(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<char const> buf)

View File

@ -33,6 +33,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "test.hpp"
#include "libtorrent/stack_allocator.hpp"
#include "libtorrent/string_view.hpp"
#include <cstdarg> // 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);
}