首页 > 解决方案 > C++ boost asio 奇怪的缓冲区溢出

问题描述

我已经调试了2天了。我已经尝试过更简单的代码库,据说可以重现错误......但它们工作得很好。我不确定这个错误是否在于我如何滥用 boost asio 功能或其他一些 C++ 功能。

我正在编写一个 TCP 服务器,其中消息结构定义为:

uint64_t size      // Size of the message, in bytes
uint64_t timestamp // Some timestamp
char    *text      // Some ASCII data

编码

size代表and的 Header 类timestamp声明为:

class Header {
private:
    uint64_t buf[2];

    void *data() const {
        return (void *) &buf[0];
    }

public:
    Header() {
        buf[0] = 0UL;
        buf[1] = 0UL;
    }
    
    // Reads the header from the socket
    void readHeader(boost::asio::ip::tcp::socket &socket, std::function<void (void)> cb);

    std::size_t getHeaderSize() const {
        return sizeof(buf);
    }

    uint64_t getDatagramSize() const {
        return buf[0];
    }

    uint64_t getTimestamp() const {
        return buf[1];
    }

};

该类ImuDatagram保存整个消息,并具有从套接字读取数据报的方法。

class ImuDatagram {

public:
    Header header;
    std::string theJson;

    void readDatagram(boost::asio::ip::tcp::socket &socket, std::function<void (void)> cb);
    void readBody(boost::asio::ip::tcp::socket &socket, std::function<void (void)> cb);

};

方法定义如下:

void Header::readHeader(boost::asio::ip::tcp::socket &socket, 
                std::function<void (void)> cb)
{
    boost::asio::mutable_buffer asio_buf = boost::asio::buffer(data(), getHeaderSize());
    boost::asio::async_read(socket, asio_buf,
        [this, cb](const boost::system::error_code &ec, std::size_t bytes_transferred){
                // TAG1
                // bytes_transferred: 16 (as expected)
                // getDatagramSize() == 116 (as expected)
                // getTimestamp() == ... (as expected)
                
                cb();
        });
}

void ImuDatagram::readBody(boost::asio::ip::tcp::socket &socket, std::function<void (void)> cb) {
    uint64_t dgSize = header.getDatagramSize();
    uint64_t jsonSize = dgSize - header.getHeaderSize();
    // TAG2
    // This will throw std::bad_alloc.
    theJson.reserve(jsonSize);

    boost::asio::async_read(socket, boost::asio::buffer(theJson, jsonSize), 
        [this, &socket, cb](const boost::system::error_code &ec, std::size_t bytes_transferred) {
            // Error checks omitted

            cb();
        });
}

void ImuDatagram::readDatagram(boost::asio::ip::tcp::socket &socket, std::function<void (void)> cb) {

    header.readHeader(socket, [this, &socket, cb](){
        readBody(socket, cb);
    });
}

最后,main让一切顺利的是:

tcp::acceptor imuAcceptor(ioc, tcp::endpoint(tcp::v4(), 8081));
imuAcceptor.async_accept(imuSocket, [this](const boost::system::error_code& ec)
    {
        // Error checks omitted
        ImuDatagram imu;
        imu.readDatagram(socket, [this, &imu, &socket]() {
            // Do work
        });
    }

问题描述

  1. 考虑TAG1Header::readHeader. 正如预期的那样,读取了 16 个字节(标头缓冲区的大小)。我确认theJson' 的缓冲区没有溢出。还没有错。
  2. 然后我们移动到TAG2in ImuDatagram::readBody。如前所述,这会抛出std::bad_alloc.

作为调试的一部分,我protection在标头之后插入了一个字节,以查看它是否会被写入。在TAG1,它没有被写入。在TAG2,它被写了。起初,我以为async_read是在写入缓冲区。但事实并非如此,正如protection我添加的字节所验证的那样。

有人可以告诉我这个(对我来说模糊的)错误在哪里吗?我使用 STDIN 而不是套接字编写了一个更简单的版本,它工作得很好。我怀疑问题不是来自套接字。

谢谢你。

标签: c++asynchronousboost-asiobuffer-overflow

解决方案


推荐阅读