lost_with_coding lost_with_coding - 15 days ago 7x
C++ Question

boost::asio::buffer: Getting the buffer size and preventing buffer overflow?

I have the two following functions for sending and receiving packets.

void send(std::string protocol)
char *request=new char[protocol.size()+1];
request[protocol.size()] = 0;

request_length = std::strlen(request);
boost::asio::write(s, boost::asio::buffer(request, request_length));
void receive()
char reply[max_length];
size_t reply_length = boost::asio::read(s, boost::asio::buffer(reply, request_length));
std::cout << "Reply is: ";
std::cout.write(reply, reply_length);
std::cout << "\n";

The questions pertain to this part
boost::asio::buffer(reply, request_length)
where the request length is the length of a string which was initially setup when the packet was sent. How do I check the size of the buffer without knowing
? Another question is how do I prevent buffer overflow?


To get the size of a buffer, the boost::asio::buffer_size() function can be used. However, in your example, this will most likely be of little use to you.

As explained in the buffer overview, Boost.Asio use buffer classes to represent buffers. These classes provide an abstraction and protect Boost.Asio operations against buffer overruns. Although the result of boost::asio::buffer() is passed to operations, the meta-data, such as the size of the buffer or its underlying type, is not transmitted. Also, these buffers do not own the memory, so it is the applications responsibility to ensure the underlying memory remains valid throughout the duration of the buffer abstraction's lifetime.

The boost::asio::buffer() function provides a convenient way to create the buffer classes, where the size of the buffer is deduced from the type possible. When Boost.Asio is able to deduce the buffer length, then Boost.Asio operations will not invoke a buffer overflow when using the resulting buffer type. However, if the application code specifies the size of the buffer to boost::asio::buffer(), then it is the applications responsibility to ensure that the size is not larger than the underlying memory.

When reading data, a buffer is required. The fundamental question becomes how does one know how much memory to allocate, if Boost.Asio does not transmit the size. There are a few solutions to this problem:

  • Query the socket for how much data is available via socket::available(), then allocate the buffer accordingly.

    std::vector<char> data(socket_.available());
    boost::asio::read(socket_, boost::asio::buffer(data));
  • Use a class that Boost.Asio can grow in memory, such as boost::asio::streambuf. Some operations, such as boost::asio::read() accept streambuf objects as their buffer and will allocate memory as is required for the operation. However, a completion condition should be provided; otherwise, the operation will continue until the buffer is full.

    boost::asio::streambuf data;
    boost::asio::read(socket_, data,
  • As Öö Tiib suggests, incorporate length as part of the communication protocol. Check the Boost.Asio examples for examples of communication protocols. Focus on the protocol, not necessarily on the Boost.Asio API.

    • In a fixed size protocol, both the data producer and consumer use the same size message. As the reader knows the size of the message, the reader can allocate a buffer in advance.
    • In a variable length protocol, the messages are often divided into two parts: a header and a body. The header is normally fixed size, and can contain various meta-information, such as the length of the body. This allows a reader to read a header into a fixed size buffer, extract the body length, allocate a buffer for the body, then read the body.

      // Read fixed header.
      std::vector<char> data(fixed_header_size);
      boost::asio::read(socket_, boost::asio::buffer(data));
      protocol::header header(data);
      network_to_local(header); // Handle endianess.
      // Read body.
      boost::asio::read(socket_, boost::asio::buffer(data));  
      protocol::body body(data);
      network_to_local(body); // Handle endianess.