pocoproject / poco

The POCO C++ Libraries are powerful cross-platform C++ libraries for building network- and internet-based applications that run on desktop, server, mobile, IoT, and embedded systems.
https://pocoproject.org
Other
8.05k stars 2.11k forks source link

On Poco::Buffer<char> deallocation, free(): invalid next size (normal) #4508

Closed tovedetered closed 3 months ago

tovedetered commented 3 months ago

Describe the bug When using Poco::Buffer and Poco sockets, when the buffer is deleted whether it be by delete or by stack unwinding, the error free(): invalid next size (normal) is thrown

To Reproduce

#include <Poco/Buffer.h>
#include <Poco/Net/SocketAddress.h>
#include <Poco/Net/StreamSocket.h>

int main(){
    SocketAddress adr("browser.engineering", 80);
    StreamSocket socket(adr);
    std::string message("GET " + std::string("/history.html") + " HTTP/1.1\n" +
                        "Host: " + "browser.engineering" + "\n");
    message += header::connection("keep-alive");
    message += "\r\n";
    auto buf = Poco::Buffer<char>(0);
    socket.sendBytes(message.data(),
                     static_cast<int>(message.size()));

    int recivedBytes =
            socket.receiveBytes(buf);

    int i = 0;
    for (; buf[i] != '\n'; i++)
        ;
    i++;
    std::unordered_map<std::string, std::string> responseHeaders;
    while (true) {
        std::string headerLine;
        for (; buf[i] != '\n'; i++) {
            headerLine.push_back(buf[i]);
        }
        headerLine.push_back(buf[i]);
        i++;//new thing
        if (headerLine == "\r\n") break;
        size_t pivot = headerLine.find(':');
        std::string headerKey = headerLine.substr(0, pivot);
        std::string headerValue = headerLine.substr(pivot + 1);
        for (int j = 0; j < headerKey.length(); j++) {
            headerKey[j] = tolower(static_cast<char>(headerKey[j]));
        }
        headerValue.erase(std::remove_if(headerValue.begin(), headerValue.end(),
                                         ::isspace),
                          headerValue.end());
        responseHeaders.emplace(headerKey, headerValue);
    }
    int toRead;
    int allBytes;
    if (responseHeaders.contains("content-length")) {
        std::string tmp = responseHeaders["content-length"];
        toRead = std::stoi(tmp);
        std::cout << responseHeaders["content-length"];
        allBytes = toRead;
        toRead -= recivedBytes;

    } else
        toRead = 0;
    if (toRead > 0) {
        while (recivedBytes < allBytes)
            recivedBytes += socket.receiveBytes(buf.end(), toRead);
    }

    auto body = std::string();
    for (; i < buf.sizeBytes(); i++) {
        std::cout << buf[i];
    }
    std::cout << std::endl;
    return 0;
}

Expected behavior The Buffer to be deleted successfully without throwing an error.

Please add relevant environment information:

tovedetered commented 3 months ago

Fixed by using an std::vector of buffers

andrewauclair commented 3 months ago

I would recommend testing it with sanitizers. I suspect you're accessing beyond the end of the buffer with some of those [i] accesses.