Skip to content

memory leak after using curl_easy_duphandled() #5665

@NobodyXu

Description

@NobodyXu

I did this

I compiled the following code with clang++ -std=c++17 libcurl_bug.cc -lcurl -g -fsanitize=address -o libcurl_bug:

#include <curl/curl.h>
#include <memory>

#include <err.h>
#include <cassert>

class Curl_global {
public:
    Curl_global() noexcept
    {
        auto code = curl_global_init(CURL_GLOBAL_ALL);
        if (code != CURLE_OK)
            errx(1, "curl_global_init(CURL_GLOBAL_ALL) failed with %s", curl_easy_strerror(code));
    }

    ~Curl_global()
    {
        curl_global_cleanup();
    }
};

long get_response_code(CURL *easy) noexcept
{
    long response_code;
    curl_easy_getinfo(easy, CURLINFO_RESPONSE_CODE, &response_code);
    return response_code;
}

int main(int argc, char* argv[])
{
    Curl_global curl_global{};

    auto url = std::unique_ptr<CURLU, void (*)(CURLU*)>{curl_url(), curl_url_cleanup};
    assert(url.get());
    assert(curl_url_set(url.get(), CURLUPART_URL, "http://en.cppreference.com/", 0) == CURLUE_OK);

    auto easy1 = std::unique_ptr<CURL, void (*)(CURL*)>{curl_easy_init(), curl_easy_cleanup};
    assert(easy1.get());

    assert(curl_easy_setopt(easy1.get(), CURLOPT_CURLU, url.get()) == CURLE_OK);

    assert(curl_easy_perform(easy1.get()) == CURLE_OK);
    assert(get_response_code(easy1.get()) == 302L);

    auto easy2 = std::unique_ptr<CURL, void (*)(CURL*)>{curl_easy_duphandle(easy1.get()), curl_easy_cleanup};
    assert(easy2.get());

    assert(curl_easy_perform(easy2.get()) == CURLE_OK);
    assert(get_response_code(easy2.get()) == 302L);

    return 0;
}

and here's the output:

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="https://en.cppreference.com/">here</a>.</p>
</body></html>
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="https://en.cppreference.com/">here</a>.</p>
</body></html>

=================================================================
==60998==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 28 byte(s) in 1 object(s) allocated from:
    #0 0x480ee4 in strdup (/home/nobodyxu/libcurl_bug+0x480ee4)
    #1 0x7ff0330f39c5  (/lib/x86_64-linux-gnu/libcurl.so.4+0x589c5)

SUMMARY: AddressSanitizer: 28 byte(s) leaked in 1 allocation(s).

which shows that libcurl internally leaked 28 bytes.

I expected the following

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="https://en.cppreference.com/">here</a>.</p>
</body></html>
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="https://en.cppreference.com/">here</a>.</p>
</body></html>

curl/libcurl version

curl 7.68.0 (x86_64-pc-linux-gnu) libcurl/7.68.0 OpenSSL/1.1.1f zlib/1.2.11 brotli/1.0.7 libidn2/2.2.0 libpsl/0.21.0 (+libidn2/2.2.0) libssh/0.9.3/openssl/zlib nghttp2/1.40.0 librtmp/2.3
Release-Date: 2020-01-08
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS brotli GSS-API HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM NTLM_WB PSL SPNEGO SSL TLS-SRP UnixSockets

ldd /usr/lib/x86_64-linux-gnu/libcurl.so.4 gives me:

        linux-vdso.so.1 (0x00007ffdcc5e1000)
        libnghttp2.so.14 => /lib/x86_64-linux-gnu/libnghttp2.so.14 (0x00007f14b2f6c000)
        libidn2.so.0 => /lib/x86_64-linux-gnu/libidn2.so.0 (0x00007f14b2f4b000)
        librtmp.so.1 => /lib/x86_64-linux-gnu/librtmp.so.1 (0x00007f14b2f2b000)
        libssh.so.4 => /lib/x86_64-linux-gnu/libssh.so.4 (0x00007f14b2ebd000)
        libpsl.so.5 => /lib/x86_64-linux-gnu/libpsl.so.5 (0x00007f14b2eaa000)
        libssl.so.1.1 => /lib/x86_64-linux-gnu/libssl.so.1.1 (0x00007f14b2e17000)
        libcrypto.so.1.1 => /lib/x86_64-linux-gnu/libcrypto.so.1.1 (0x00007f14b2b3f000)
        libgssapi_krb5.so.2 => /lib/x86_64-linux-gnu/libgssapi_krb5.so.2 (0x00007f14b2af2000)
        libldap_r-2.4.so.2 => /lib/x86_64-linux-gnu/libldap_r-2.4.so.2 (0x00007f14b2a9c000)
        liblber-2.4.so.2 => /lib/x86_64-linux-gnu/liblber-2.4.so.2 (0x00007f14b2a8b000)
        libbrotlidec.so.1 => /lib/x86_64-linux-gnu/libbrotlidec.so.1 (0x00007f14b2a7c000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f14b2a60000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f14b2a3b000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f14b2849000)
        libunistring.so.2 => /lib/x86_64-linux-gnu/libunistring.so.2 (0x00007f14b26c7000)
        libgnutls.so.30 => /lib/x86_64-linux-gnu/libgnutls.so.30 (0x00007f14b24f1000)
        libhogweed.so.5 => /lib/x86_64-linux-gnu/libhogweed.so.5 (0x00007f14b24b9000)
        libnettle.so.7 => /lib/x86_64-linux-gnu/libnettle.so.7 (0x00007f14b247f000)
        libgmp.so.10 => /lib/x86_64-linux-gnu/libgmp.so.10 (0x00007f14b23f9000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f14b304a000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f14b23f3000)
        libkrb5.so.3 => /lib/x86_64-linux-gnu/libkrb5.so.3 (0x00007f14b2316000)
        libk5crypto.so.3 => /lib/x86_64-linux-gnu/libk5crypto.so.3 (0x00007f14b22e5000)
        libcom_err.so.2 => /lib/x86_64-linux-gnu/libcom_err.so.2 (0x00007f14b22de000)
        libkrb5support.so.0 => /lib/x86_64-linux-gnu/libkrb5support.so.0 (0x00007f14b22cd000)
        libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f14b22b1000)
        libsasl2.so.2 => /lib/x86_64-linux-gnu/libsasl2.so.2 (0x00007f14b2294000)
        libgssapi.so.3 => /lib/x86_64-linux-gnu/libgssapi.so.3 (0x00007f14b224f000)
        libbrotlicommon.so.1 => /lib/x86_64-linux-gnu/libbrotlicommon.so.1 (0x00007f14b222c000)
        libp11-kit.so.0 => /lib/x86_64-linux-gnu/libp11-kit.so.0 (0x00007f14b20f6000)
        libtasn1.so.6 => /lib/x86_64-linux-gnu/libtasn1.so.6 (0x00007f14b20de000)
        libkeyutils.so.1 => /lib/x86_64-linux-gnu/libkeyutils.so.1 (0x00007f14b20d7000)
        libheimntlm.so.0 => /lib/x86_64-linux-gnu/libheimntlm.so.0 (0x00007f14b20cb000)
        libkrb5.so.26 => /lib/x86_64-linux-gnu/libkrb5.so.26 (0x00007f14b2038000)
        libasn1.so.8 => /lib/x86_64-linux-gnu/libasn1.so.8 (0x00007f14b1f91000)
        libhcrypto.so.4 => /lib/x86_64-linux-gnu/libhcrypto.so.4 (0x00007f14b1f57000)
        libroken.so.18 => /lib/x86_64-linux-gnu/libroken.so.18 (0x00007f14b1f3e000)
        libffi.so.7 => /lib/x86_64-linux-gnu/libffi.so.7 (0x00007f14b1f32000)
        libwind.so.0 => /lib/x86_64-linux-gnu/libwind.so.0 (0x00007f14b1f08000)
        libheimbase.so.1 => /lib/x86_64-linux-gnu/libheimbase.so.1 (0x00007f14b1ef6000)
        libhx509.so.5 => /lib/x86_64-linux-gnu/libhx509.so.5 (0x00007f14b1ea6000)
        libsqlite3.so.0 => /lib/x86_64-linux-gnu/libsqlite3.so.0 (0x00007f14b1d7d000)
        libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007f14b1d42000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f14b1bf3000)

The libcurl I am using is installed from pop!_os official apt source:

curl/focal-security,focal-updates,now 7.68.0-1ubuntu2.1 amd64 [installed]
libcurl4-doc/focal-security,focal-security,focal-updates,focal-updates,now 7.68.0-1ubuntu2.1 all [installed]
libcurl4-openssl-dev/focal-security,focal-updates,now 7.68.0-1ubuntu2.1 amd64 [installed]
libcurl4/focal-security,focal-updates,now 7.68.0-1ubuntu2.1 amd64 [installed,automatic]

operating system

NAME="Pop!_OS"
VERSION="20.04 LTS"
ID=pop
ID_LIKE="ubuntu debian"
PRETTY_NAME="Pop!_OS 20.04 LTS"
VERSION_ID="20.04"
HOME_URL="https://pop.system76.com"
SUPPORT_URL="https://support.system76.com"
BUG_REPORT_URL="https://github.com/pop-os/pop/issues"
PRIVACY_POLICY_URL="https://system76.com/privacy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
LOGO=distributor-logo-pop-os
Linux pop-os 5.4.0-7634-generic #38~1592497129~20.04~9a1ea2e-Ubuntu SMP Fri Jun 19 22:43:37 UTC  x86_64 x86_64 x86_64 GNU/Linux

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions