Search code examples
c++memory-leaksopensslvalgrind

Can't find cause of Invalid free() / delete / delete[] / realloc()


I am writing HTTP client in C++. When I was testing my program he crashed with this error:

*** Error in `./isabot': free(): invalid pointer: 0x00007ffe7f8d2600 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x81299)[0x7fef1fd86299]
./isabot[0x408eca]
./isabot[0x409afe]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7fef1fd27555]
./isabot[0x402d59]
======= Memory map: ========
.
.
.

I reran my program with valgrind -v and I got this error:

==20879== Invalid free() / delete / delete[] / realloc()
==20879==    at 0x4C2B18A: operator delete(void*) (vg_replace_malloc.c:576)
==20879==    by 0x408EC9: sendRequest(ssl_st*, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /homes/eva/xm/xmimoc01/ISA/isabot)
==20879==    by 0x409AFD: main (in /homes/eva/xm/xmimoc01/ISA/isabot)
==20879==  Address 0x1ffeffee00 is on thread 1's stack
==20879==  in frame #1, created by sendRequest(ssl_st*, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (???:)
==20879==

When I started my program without valgrind, the program crashed on this. But, when I started my program with valgrind, it wrote to me an error and the program continued successfully without repetition this error.

My function sendRequest() looks like:


string sendRequest(SSL *ssl, int requestType, const string &botToken, const string &guildId, const string &channelId, const string &lastMessageId, const string &content)
{
    const char *request;
    string strRequest;
    stringstream response;
    string isChunked;
    char buffer[BUFFER];

    if (requestType == GET_CLIENT_ID) {
        strRequest = createIDRequest(botToken);
    }
    else if (requestType == GET_GUILDS) {
        strRequest = createGuildsRequest(botToken);
    }
    else if (requestType == GET_CHANNELS) {
        strRequest = createChannelRequest(botToken, guildId);
    }
    else if (requestType == GET_MESSAGES) {
        strRequest = createMessagesRequest(botToken, channelId);
    }
    else if (requestType == GET_ACTUAL_MESSAGES) {
        strRequest = createActualMessagesRequest(botToken, channelId, lastMessageId);
    }
    else if(requestType == POST_SEND_MESSAGE) {
        strRequest = createSendMessageRequest(botToken, channelId, content);
    }

    request = strRequest.c_str();

    SSL_write(ssl, request, strlen(request));

    while(true) {
        memset(buffer, 0, sizeof(buffer));
        int n =  SSL_read(ssl, buffer, BUFFER);

        if(n >= 0) {
            buffer[n] = '\0';
        }

        if (n <= 5) {
            break;
        };

        response << buffer;

        if (isResponseChunked(response.str()) != true) {
            break;
        }
    }
    

    return response.str();
}

and I called it from main.cpp in part of code where it crashed like this:

string sendedMessage = sendRequest(conn.ssl, POST_SEND_MESSAGE, botToken, "", channelId, "", content);

Solution

  • buffer[n] = '\0'; will write past the end of buffer when n == BUFFER. This overwrites some part of the stack, likely snother local variable. If it is one of the string variables, the internal state is corrupted which could result in this error.

    The simple fix is to allocate one additional character in buffer.

    char buffer[BUFFER+1];
    

    Alternatively, you could read one less byte in the call to SSL_read.