-
-
Notifications
You must be signed in to change notification settings - Fork 7k
Closed
Labels
Description
Random memory leak is detected when calling curl_multi_cleanup before the associated easy handles are closed.
Steps to reproduce.
Build the following sample multi_app application:
#include <stdio.h>
#include <string.h>
/* somewhat unix-specific */
#include <sys/time.h>
#include <unistd.h>
/* curl stuff */
#include <curl/curl.h>
#define HANDLECOUNT 2 /* Number of simultaneous transfers */
/* The maximum number of curl_multi_perform iterations to perform before
* calling curl_multi_cleanup.
*/
#define MAX_ITERATIONS 14
int main(void)
{
CURL *handles[HANDLECOUNT];
CURLM *multi_handle;
int still_running = 1; /* keep number of running handles */
int i;
int iteration = 0;
CURLMsg *msg; /* for picking up messages with the transfer status */
int msgs_left; /* how many messages are left */
/* Allocate one CURL handle per transfer */
for (i = 0; i < HANDLECOUNT; i++) {
handles[i] = curl_easy_init();
curl_easy_setopt(handles[i], CURLOPT_URL, "https://example.com");
}
/* init a multi stack */
multi_handle = curl_multi_init();
/* add the individual transfers */
for(i = 0; i < HANDLECOUNT; i++)
curl_multi_add_handle(multi_handle, handles[i]);
while (still_running) {
CURLMcode mc = curl_multi_perform(multi_handle, &still_running);
if (iteration++ >= MAX_ITERATIONS)
goto out;
if (still_running)
/* wait for activity, timeout or "nothing" */
mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL);
if (mc)
break;
}
/* Free the CURL handles */
for(i = 0; i < HANDLECOUNT; i++) {
curl_multi_remove_handle(multi_handle, handles[i]);
curl_easy_cleanup(handles[i]);
}
curl_multi_cleanup(multi_handle);
return 0;
}Run the application with valgrind using the following shell script:
#!/bin/sh
while valgrind -q --error-exitcode=1 --leak-check=full ./multi_app > /dev/null; do
echo "Retrying..."
doneDepending on your computer's speed the leak will appear after a few tries:
Retrying...
==146245== 20,162 (1,280 direct, 18,882 indirect) bytes in 2 blocks are definitely lost in loss record 81 of 81
==146245== at 0x483E7C5: malloc (vg_replace_malloc.c:380)
==146245== by 0x495877A: ssl_session_dup (ssl_sess.c:110)
==146245== by 0x496ABD3: tls_process_new_session_ticket (statem_clnt.c:2620)
==146245== by 0x4965D8C: read_state_machine (statem.c:636)
==146245== by 0x4965D8C: state_machine.part.0 (statem.c:434)
==146245== by 0x493C729: ssl3_read_bytes (rec_layer_s3.c:1658)
==146245== by 0x4943765: ssl3_read_internal (s3_lib.c:4465)
==146245== by 0x494EE17: SSL_read (ssl_lib.c:1783)
==146245== by 0x48E5D5B: ossl_closeone.isra.0 (openssl.c:1407)
==146245== by 0x48E5DE5: ossl_close (openssl.c:1427)
==146245== by 0x48ED11E: Curl_ssl_close (vtls.c:676)
==146245== by 0x48DA583: conn_shutdown (url.c:752)
==146245== by 0x48DA583: Curl_disconnect (url.c:870)
==146245== by 0x4889D92: Curl_conncache_close_all_connections (conncache.c:555)
Environment
curl 7.78openSSL 1.1.1.kandopenSSL 1.1.1.l
Notes
The memory leak appeared starting from curl 7.78 with the following commit
b249592d29ae0a2b3e8e07fdbc01f33b5a5b8420.
For know I have managed to reproduce it only with openSSL backend and not with
mbedTLS.
To reproduce the issue there needs to be at least two simultaneous connections
and the cleanup operations need to be close in time to exit.