Skip to content

Segmentation fault when sending http3-only request by multi interface #11449

@Cering

Description

@Cering

I did this

  • Send CURL_HTTP_VERSION_3ONLY request parallelly by using multi interface
  • After some requests finished, a segmentation fault occurred
  • This segmentation fault occurred when using the latest release version(libcurl/8.1.2+quiche/0.17.1), but not found in previous version(libcurl/8.0.1+quiche/0.16.0)

I expected the following

  • Running the test code(see below) in gdb, the segmentation fault info:
Program received signal SIGSEGV, Segmentation fault.
bufcp_take (pchunk=<synthetic pointer>, pool=0xc783a8) at bufq.c:191
191         pool->spare = chunk->next;

(gdb) bt
#0  bufcp_take (pchunk=<synthetic pointer>, pool=0xc783a8) at bufq.c:191
#1  get_spare (q=0xfd67f8) at bufq.c:338
#2  get_non_full_tail (q=q@entry=0xfd67f8) at bufq.c:387
#3  0x00007ffff76818b0 in Curl_bufq_write (q=0xfd67f8, buf=buf@entry=0x7ffff79f19e0 "HTTP/3 ", len=len@entry=7, err=err@entry=0x7fffffffdabc) at bufq.c:412
#4  0x00007ffff76e6adb in write_resp_raw (data=<optimized out>, mem=mem@entry=0x7ffff79f19e0, memlen=memlen@entry=7, cf=<optimized out>) at vquic/curl_quiche.c:356
#5  0x00007ffff76e6bbc in cb_each_header (name=<optimized out>, name_len=<optimized out>, value=0x139ab50 "200", value_len=3, argp=0x7fffffffdb60) at vquic/curl_quiche.c:384
#6  0x00007ffff76fba3c in quiche_h3_event_for_each_header () from /data/yldata/git_workspace/ThirdPartyLibs/libcurl/demo/deps/curl/lib/libcurl.so.4
#7  0x00007ffff76e6fc8 in h3_process_event (ev=0x1373860, stream3_id=0, data=0x615370, cf=0x125ba00) at vquic/curl_quiche.c:515
#8  cf_poll_events (data=0x615370, cf=0x125ba00) at vquic/curl_quiche.c:591
#9  cf_process_ingress (cf=cf@entry=0x125ba00, data=data@entry=0x615370) at vquic/curl_quiche.c:680
#10 0x00007ffff76e709f in cf_quiche_recv () at vquic/curl_quiche.c:841
#11 0x00007ffff76c1117 in Curl_read (data=data@entry=0x615370, sockfd=<optimized out>, buf=buf@entry=0x610430 "\210\235\337\366\377\177", 
    sizerequested=sizerequested@entry=16384, n=n@entry=0x7fffffffdca0) at sendf.c:415
#12 0x00007ffff76d2950 in readwrite_data (comeback=0x7fffffffdd1f, done=0x7fffffffdd1d, didwhat=<synthetic pointer>, k=0x615440, conn=0x6216f0, data=0x615370)
    at transfer.c:461
#13 Curl_readwrite (conn=0x6216f0, data=data@entry=0x615370, done=done@entry=0x7fffffffdd1d, comeback=comeback@entry=0x7fffffffdd1f) at transfer.c:1115
#14 0x00007ffff76b89e4 in multi_runsingle (multi=multi@entry=0x605010, nowp=nowp@entry=0x7fffffffdd80, data=0x615370) at multi.c:2448
#15 0x00007ffff76ba3aa in curl_multi_perform (multi=0x605010, running_handles=0x7fffffffde9c) at multi.c:2745
#16 0x000000000040275b in main () at /data/yldata/git_workspace/ThirdPartyLibs/libcurl/demo/test.cpp:60

Test code

#include <string>
#include <vector>
#include <sstream>
#include <unistd.h>
#include "curl/curl.h"

size_t mycurl_onrecv_body(char *ptr, size_t size, size_t nmemb, void *userdata)
{
    return size * nmemb;
}

void mycurl_process(CURLM *multi_handle)
{
    CURLMsg *curl_msg = nullptr;
    int msgs_left = 0;
    while((curl_msg = curl_multi_info_read(multi_handle, &msgs_left))) {
        if(curl_msg->msg == CURLMSG_DONE) {
            CURL *http_handle = curl_msg->easy_handle;
            CURLcode code = curl_msg->data.result;
            curl_multi_remove_handle(multi_handle, http_handle);
            printf("handle %p finished\n", http_handle);
            curl_easy_cleanup(http_handle);
        }
    }
    return;
}

int main()
{
    curl_global_init(CURL_GLOBAL_ALL);
    printf("%s\n", curl_version());

    CURLM *multi_handle = curl_multi_init();

    int reqid = 0;
    std::vector<std::string> url_list {
        "https://cloudflare-quic.com/",
        "https://cloudflare-quic.com/",
        "https://cloudflare-quic.com/",
    };

    int count = 5;
    while(count--) {
        int still_running = 0;
        for(auto url : url_list) {
            printf("New Request[%d]: %s\n", reqid++, url.c_str());
            CURL *http_handle = curl_easy_init();
            curl_easy_setopt(http_handle, CURLOPT_URL, url.c_str());
            curl_easy_setopt(http_handle, CURLOPT_VERBOSE, 1L);
            curl_easy_setopt(http_handle, CURLOPT_WRITEFUNCTION, mycurl_onrecv_body);
            curl_easy_setopt(http_handle, CURLOPT_CONNECTTIMEOUT_MS, 5000L);
            curl_easy_setopt(http_handle, CURLOPT_TIMEOUT_MS, 10000L);
            curl_easy_setopt(http_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3ONLY);
            curl_multi_add_handle(multi_handle, http_handle);
        }

        do {
            int numfds = 0;
            curl_multi_wait(multi_handle, NULL, 0, 10, &numfds);
            curl_multi_perform(multi_handle, &still_running);
            mycurl_process(multi_handle);
        } while(still_running);
        sleep(5);
    }

    curl_multi_cleanup(multi_handle);
    return 0;
}

curl/libcurl version

curl 8.1.2 (x86_64-pc-linux-gnu) libcurl/8.1.2 BoringSSL zlib/1.2.7 brotli/1.0.9 nghttp2/1.41.0 quiche/0.17.1
Release-Date: 2023-05-30
Protocols: dict file ftp ftps gopher gophers http https imap imaps mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS brotli HSTS HTTP2 HTTP3 HTTPS-proxy IPv6 Largefile libz NTLM NTLM_WB SSL threadsafe UnixSockets

operating system

Linux mylinux 3.10.0-693.21.1.el7.x86_64 #1 SMP Wed Mar 7 19:03:37 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

Metadata

Metadata

Assignees

Labels

HTTP/3h3 or quic relatedquicheCloudflare's QUIC and HTTP/3 library

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions