1 | /*
|
---|
2 |
|
---|
3 | This is a test program to reproduce a bug which appears in the
|
---|
4 | implementation of boost::asio::async_read_some() somewhere between
|
---|
5 | boost 1.42.0 and 1.46.1. From the async_read_some() documentation:
|
---|
6 | (http://www.boost.org/doc/libs/1_46_1/doc/html/boost_asio/reference/async_read_until/overload2.html)
|
---|
7 |
|
---|
8 | "If the streambuf's get area already contains the delimiter, this
|
---|
9 | asynchronous operation completes immediately."
|
---|
10 |
|
---|
11 | This condition appears to be met under boost 1.42.0, and not under
|
---|
12 | boost 1.46.1, boost 1.49.0, or boost trunk from subversion.
|
---|
13 |
|
---|
14 | Output on ubuntu 11.10, using boost 1.42.0:
|
---|
15 |
|
---|
16 | % ./boost_async_read_test
|
---|
17 | Calling readline, streambuf:
|
---|
18 | async_read_some, invocations: 1
|
---|
19 | HandleLine: test line
|
---|
20 | Calling readline, streambuf: more
|
---|
21 | async_read_some, invocations: 2
|
---|
22 | HandleLine: more lines
|
---|
23 | Calling readline, streambuf: another line
|
---|
24 |
|
---|
25 | HandleLine: another line
|
---|
26 |
|
---|
27 | Output on ubuntu 11.10, using boost 1.46.1 (1.49.0 and trunk produce
|
---|
28 | identical output):
|
---|
29 |
|
---|
30 | % ./boost_async_read_test
|
---|
31 | Calling readline, streambuf:
|
---|
32 | async_read_some, invocations: 1
|
---|
33 | HandleLine: test line
|
---|
34 | Calling readline, streambuf: more
|
---|
35 | async_read_some, invocations: 2
|
---|
36 | HandleLine: more lines
|
---|
37 | Calling readline, streambuf: another line
|
---|
38 |
|
---|
39 | async_read_some, invocations: 3
|
---|
40 |
|
---|
41 | */
|
---|
42 |
|
---|
43 | #include <list>
|
---|
44 | #include <iostream>
|
---|
45 | #include <string>
|
---|
46 |
|
---|
47 | #include <boost/asio.hpp>
|
---|
48 | #include <boost/assert.hpp>
|
---|
49 | #include <boost/bind.hpp>
|
---|
50 | #include <boost/noncopyable.hpp>
|
---|
51 | #include <boost/system/error_code.hpp>
|
---|
52 |
|
---|
53 | const std::string line1 = "test line\nmore ";
|
---|
54 | const std::string line2 = "lines\nanother line\n";
|
---|
55 |
|
---|
56 | namespace asio = boost::asio;
|
---|
57 |
|
---|
58 | namespace {
|
---|
59 |
|
---|
60 | class StreamStub : boost::noncopyable {
|
---|
61 | public:
|
---|
62 | explicit StreamStub(asio::io_service& service)
|
---|
63 | : service_(service), invocations_(0) {}
|
---|
64 |
|
---|
65 | asio::io_service& get_io_service() { return service_; }
|
---|
66 |
|
---|
67 | template <typename MutableBufferSequence,
|
---|
68 | typename Handler>
|
---|
69 | void async_read_some(MutableBufferSequence mb, Handler h) {
|
---|
70 | ++invocations_;
|
---|
71 | std::cout << "async_read_some, invocations: " << invocations_ << "\n";
|
---|
72 | const std::string* line;
|
---|
73 | if (invocations_ == 1) {
|
---|
74 | line = &line1;
|
---|
75 | } else if (invocations_ == 2) {
|
---|
76 | line = &line2;
|
---|
77 | } else {
|
---|
78 | // don't call the handler on later reads
|
---|
79 | return;
|
---|
80 | }
|
---|
81 |
|
---|
82 | size_t bufsize = asio::buffer_size(*mb.begin());
|
---|
83 | BOOST_ASSERT(bufsize >= line->size());
|
---|
84 | memcpy(asio::buffer_cast<char*>(*mb.begin()), line->data(), line->size());
|
---|
85 | h(boost::system::error_code(), line->size());
|
---|
86 | }
|
---|
87 |
|
---|
88 | private:
|
---|
89 | asio::io_service& service_;
|
---|
90 | int invocations_;
|
---|
91 | };
|
---|
92 |
|
---|
93 | class Reader : boost::noncopyable {
|
---|
94 | public:
|
---|
95 | Reader()
|
---|
96 | : stream_(service_) {}
|
---|
97 |
|
---|
98 | void Readline() {
|
---|
99 | std::cout << "Calling readline, streambuf: " <<
|
---|
100 | std::string(
|
---|
101 | asio::buffer_cast<const char*>(*streambuf_.data().begin()),
|
---|
102 | asio::buffer_size(*streambuf_.data().begin())) <<
|
---|
103 | "\n";
|
---|
104 | asio::async_read_until(
|
---|
105 | stream_, streambuf_, "\n",
|
---|
106 | boost::bind(&Reader::HandleLine, this,
|
---|
107 | boost::asio::placeholders::error,
|
---|
108 | boost::asio::placeholders::bytes_transferred));
|
---|
109 | }
|
---|
110 |
|
---|
111 | asio::io_service service_;
|
---|
112 |
|
---|
113 | private:
|
---|
114 | void HandleLine(boost::system::error_code ec, size_t len) {
|
---|
115 | BOOST_ASSERT(!ec);
|
---|
116 |
|
---|
117 | std::istream is(&streambuf_);
|
---|
118 | std::string line;
|
---|
119 | std::getline(is, line);
|
---|
120 | std::cout << "HandleLine: " << line << "\n";
|
---|
121 | }
|
---|
122 |
|
---|
123 | StreamStub stream_;
|
---|
124 | std::list<std::string> lines_;
|
---|
125 | asio::streambuf streambuf_;
|
---|
126 |
|
---|
127 | };
|
---|
128 | }
|
---|
129 |
|
---|
130 | int main(int ac, char *av[]) {
|
---|
131 |
|
---|
132 | Reader reader;
|
---|
133 |
|
---|
134 | reader.Readline();
|
---|
135 | reader.service_.poll();
|
---|
136 | reader.service_.reset();
|
---|
137 |
|
---|
138 | reader.Readline();
|
---|
139 | reader.service_.poll();
|
---|
140 | reader.service_.reset();
|
---|
141 |
|
---|
142 | reader.Readline();
|
---|
143 | reader.service_.poll();
|
---|
144 | reader.service_.reset();
|
---|
145 |
|
---|
146 | }
|
---|