mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Fix streambuf::prepare:
In some edge cases, calling prepare could leave the output sequence with the incorrect size. This happens when out_end_ is non-zero and the call to prepare should leave out_end_ at 0.
This commit is contained in:
@@ -442,6 +442,7 @@ basic_streambuf<Allocator>::prepare (size_type n) ->
|
||||
++pos;
|
||||
break;
|
||||
}
|
||||
out_end_ = pos->size();
|
||||
n -= pos->size();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,129 +26,77 @@ namespace asio {
|
||||
class streambuf_test : public unit_test::suite
|
||||
{
|
||||
public:
|
||||
// Convert a buffer sequence to a string
|
||||
template <class Buffers>
|
||||
template<class ConstBufferSequence>
|
||||
static
|
||||
std::string
|
||||
to_str (Buffers const& b)
|
||||
to_string(ConstBufferSequence const& bs)
|
||||
{
|
||||
using namespace boost::asio;
|
||||
std::string s;
|
||||
auto const n = boost::asio::buffer_size(b);
|
||||
s.resize(n);
|
||||
boost::asio::buffer_copy(
|
||||
boost::asio::buffer(&s[0], n), b);
|
||||
s.reserve(buffer_size(bs));
|
||||
for(auto const& b : bs)
|
||||
s.append(buffer_cast<char const*>(b),
|
||||
buffer_size(b));
|
||||
return s;
|
||||
}
|
||||
|
||||
// Fill a buffer sequence with predictable data
|
||||
template <class Buffers>
|
||||
static
|
||||
void
|
||||
fill (Buffers const& b)
|
||||
void testStreambuf()
|
||||
{
|
||||
char c = 0;
|
||||
auto first = boost::asio::buffers_begin(b);
|
||||
auto last = boost::asio::buffers_end(b);
|
||||
while (first != last)
|
||||
*first++ = c++;
|
||||
}
|
||||
|
||||
// Check that a buffer sequence has predictable data
|
||||
template <class Buffers>
|
||||
void
|
||||
check (Buffers const& b, char c = 0)
|
||||
{
|
||||
auto first = boost::asio::buffers_begin(b);
|
||||
auto last = boost::asio::buffers_end(b);
|
||||
while (first != last)
|
||||
expect (*first++ == c++);
|
||||
}
|
||||
|
||||
void
|
||||
test_prepare()
|
||||
{
|
||||
testcase << "prepare";
|
||||
beast::asio::streambuf b(11);
|
||||
for (std::size_t n = 0; n < 97; ++n)
|
||||
using namespace boost::asio;
|
||||
char buf[12];
|
||||
std::string const s = "Hello, world";
|
||||
expect(s.size() == sizeof(buf));
|
||||
for(std::size_t i = 1; i < 12; ++i) {
|
||||
for(std::size_t x = 1; x < 4; ++x) {
|
||||
for(std::size_t y = 1; y < 4; ++y) {
|
||||
for(std::size_t t = 1; t < 4; ++ t) {
|
||||
for(std::size_t u = 1; u < 4; ++ u) {
|
||||
std::size_t z = sizeof(buf) - (x + y);
|
||||
std::size_t v = sizeof(buf) - (t + u);
|
||||
{
|
||||
fill(b.prepare(n));
|
||||
b.commit(n);
|
||||
check(b.data());
|
||||
b.consume(n);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_commit()
|
||||
{
|
||||
testcase << "commit";
|
||||
beast::asio::streambuf b(11);
|
||||
for (std::size_t n = 0; n < 97; ++n)
|
||||
{
|
||||
fill(b.prepare(n));
|
||||
char c = 0;
|
||||
for (int i = 1;; ++i)
|
||||
{
|
||||
b.commit(i);
|
||||
check(b.data(), c);
|
||||
b.consume(i);
|
||||
if (b.size() < 1)
|
||||
break;
|
||||
c += i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_consume()
|
||||
{
|
||||
testcase << "consume";
|
||||
beast::asio::streambuf b(11);
|
||||
for (std::size_t n = 0; n < 97; ++n)
|
||||
{
|
||||
fill(b.prepare(n));
|
||||
b.commit(n);
|
||||
char c = 0;
|
||||
for (int i = 1; b.size() > 0; ++i)
|
||||
{
|
||||
check(b.data(), c);
|
||||
b.consume(i);
|
||||
c += i;
|
||||
}
|
||||
std::memset(buf, 0, sizeof(buf));
|
||||
streambuf ba(i);
|
||||
decltype(ba)::mutable_buffers_type d;
|
||||
d = ba.prepare(z); expect(buffer_size(d) == z);
|
||||
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||
d = ba.prepare(y); expect(buffer_size(d) == y);
|
||||
d = ba.prepare(x); expect(buffer_size(d) == x);
|
||||
ba.commit(buffer_copy(d, buffer(s.data(), x)));
|
||||
expect(ba.size() == x);
|
||||
expect(buffer_size(ba.data()) == ba.size());
|
||||
d = ba.prepare(x); expect(buffer_size(d) == x);
|
||||
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||
d = ba.prepare(z); expect(buffer_size(d) == z);
|
||||
d = ba.prepare(y); expect(buffer_size(d) == y);
|
||||
ba.commit(buffer_copy(d, buffer(s.data()+x, y)));
|
||||
ba.commit(1);
|
||||
expect(ba.size() == x + y);
|
||||
expect(buffer_size(ba.data()) == ba.size());
|
||||
d = ba.prepare(x); expect(buffer_size(d) == x);
|
||||
d = ba.prepare(y); expect(buffer_size(d) == y);
|
||||
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||
d = ba.prepare(z); expect(buffer_size(d) == z);
|
||||
ba.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
|
||||
ba.commit(2);
|
||||
expect(ba.size() == x + y + z);
|
||||
expect(buffer_size(ba.data()) == ba.size());
|
||||
expect(to_string(ba.data()) == s);
|
||||
ba.consume(t);
|
||||
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||
expect(to_string(ba.data()) == s.substr(t, std::string::npos));
|
||||
ba.consume(u);
|
||||
expect(to_string(ba.data()) == s.substr(t + u, std::string::npos));
|
||||
ba.consume(v);
|
||||
expect(to_string(ba.data()) == "");
|
||||
ba.consume(1);
|
||||
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||
}
|
||||
}}}}}
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
{
|
||||
beast::asio::streambuf b(10);
|
||||
std::string const s = "1234567890";
|
||||
b << s;
|
||||
expect (to_str(b.data()) == s);
|
||||
b.prepare(5);
|
||||
}
|
||||
|
||||
{
|
||||
beast::asio::streambuf b(10);
|
||||
b.prepare(10);
|
||||
b.commit(10);
|
||||
b.consume(10);
|
||||
}
|
||||
|
||||
{
|
||||
beast::asio::streambuf b(5);
|
||||
boost::asio::buffer_copy(b.prepare(14),
|
||||
boost::asio::buffer(std::string("1234567890ABCD")));
|
||||
b.commit(4);
|
||||
expect(to_str(b.data()) == "1234");
|
||||
b.consume(4);
|
||||
b.commit(10);
|
||||
expect(to_str(b.data()) == "567890ABCD");
|
||||
}
|
||||
|
||||
test_prepare();
|
||||
test_commit();
|
||||
test_consume();
|
||||
testStreambuf();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user