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;
|
++pos;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
out_end_ = pos->size();
|
||||||
n -= pos->size();
|
n -= pos->size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,129 +26,77 @@ namespace asio {
|
|||||||
class streambuf_test : public unit_test::suite
|
class streambuf_test : public unit_test::suite
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Convert a buffer sequence to a string
|
template<class ConstBufferSequence>
|
||||||
template <class Buffers>
|
|
||||||
static
|
static
|
||||||
std::string
|
std::string
|
||||||
to_str (Buffers const& b)
|
to_string(ConstBufferSequence const& bs)
|
||||||
{
|
{
|
||||||
|
using namespace boost::asio;
|
||||||
std::string s;
|
std::string s;
|
||||||
auto const n = boost::asio::buffer_size(b);
|
s.reserve(buffer_size(bs));
|
||||||
s.resize(n);
|
for(auto const& b : bs)
|
||||||
boost::asio::buffer_copy(
|
s.append(buffer_cast<char const*>(b),
|
||||||
boost::asio::buffer(&s[0], n), b);
|
buffer_size(b));
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill a buffer sequence with predictable data
|
void testStreambuf()
|
||||||
template <class Buffers>
|
|
||||||
static
|
|
||||||
void
|
|
||||||
fill (Buffers const& b)
|
|
||||||
{
|
{
|
||||||
char c = 0;
|
using namespace boost::asio;
|
||||||
auto first = boost::asio::buffers_begin(b);
|
char buf[12];
|
||||||
auto last = boost::asio::buffers_end(b);
|
std::string const s = "Hello, world";
|
||||||
while (first != last)
|
expect(s.size() == sizeof(buf));
|
||||||
*first++ = c++;
|
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) {
|
||||||
// Check that a buffer sequence has predictable data
|
for(std::size_t t = 1; t < 4; ++ t) {
|
||||||
template <class Buffers>
|
for(std::size_t u = 1; u < 4; ++ u) {
|
||||||
void
|
std::size_t z = sizeof(buf) - (x + y);
|
||||||
check (Buffers const& b, char c = 0)
|
std::size_t v = sizeof(buf) - (t + u);
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
fill(b.prepare(n));
|
std::memset(buf, 0, sizeof(buf));
|
||||||
b.commit(n);
|
streambuf ba(i);
|
||||||
check(b.data());
|
decltype(ba)::mutable_buffers_type d;
|
||||||
b.consume(n);
|
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);
|
||||||
void
|
ba.commit(buffer_copy(d, buffer(s.data(), x)));
|
||||||
test_commit()
|
expect(ba.size() == x);
|
||||||
{
|
expect(buffer_size(ba.data()) == ba.size());
|
||||||
testcase << "commit";
|
d = ba.prepare(x); expect(buffer_size(d) == x);
|
||||||
beast::asio::streambuf b(11);
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
for (std::size_t n = 0; n < 97; ++n)
|
d = ba.prepare(z); expect(buffer_size(d) == z);
|
||||||
{
|
d = ba.prepare(y); expect(buffer_size(d) == y);
|
||||||
fill(b.prepare(n));
|
ba.commit(buffer_copy(d, buffer(s.data()+x, y)));
|
||||||
char c = 0;
|
ba.commit(1);
|
||||||
for (int i = 1;; ++i)
|
expect(ba.size() == x + y);
|
||||||
{
|
expect(buffer_size(ba.data()) == ba.size());
|
||||||
b.commit(i);
|
d = ba.prepare(x); expect(buffer_size(d) == x);
|
||||||
check(b.data(), c);
|
d = ba.prepare(y); expect(buffer_size(d) == y);
|
||||||
b.consume(i);
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
if (b.size() < 1)
|
d = ba.prepare(z); expect(buffer_size(d) == z);
|
||||||
break;
|
ba.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
|
||||||
c += i;
|
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);
|
||||||
void
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
test_consume()
|
expect(to_string(ba.data()) == s.substr(t, std::string::npos));
|
||||||
{
|
ba.consume(u);
|
||||||
testcase << "consume";
|
expect(to_string(ba.data()) == s.substr(t + u, std::string::npos));
|
||||||
beast::asio::streambuf b(11);
|
ba.consume(v);
|
||||||
for (std::size_t n = 0; n < 97; ++n)
|
expect(to_string(ba.data()) == "");
|
||||||
{
|
ba.consume(1);
|
||||||
fill(b.prepare(n));
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
b.commit(n);
|
|
||||||
char c = 0;
|
|
||||||
for (int i = 1; b.size() > 0; ++i)
|
|
||||||
{
|
|
||||||
check(b.data(), c);
|
|
||||||
b.consume(i);
|
|
||||||
c += i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}}}}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
{
|
testStreambuf();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user