multi: kill off remaining internal handles in curl_multi_cleanup

- if there are pending internal handles left in the list, they are
  leftovers (from for example Doh) and must be freed.

- unlink_all_msgsent_handles() did not properly move all msgsent
  handles over to the process list as intended

Fixes a DoH memory leak found by oss-fuzz.

Add test 2101 that can reproduce and verify.

Closes #16674
This commit is contained in:
Daniel Stenberg 2025-03-11 17:40:21 +01:00
parent 41a15c8e74
commit b1faac8039
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
3 changed files with 56 additions and 4 deletions

View file

@ -2478,7 +2478,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case MSTATE_PENDING:
case MSTATE_MSGSENT:
/* handles in these states should NOT be in this list */
DEBUGASSERT(0);
break;
default:
@ -2676,8 +2675,10 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
static void unlink_all_msgsent_handles(struct Curl_multi *multi)
{
struct Curl_llist_node *e;
for(e = Curl_llist_head(&multi->msgsent); e; e = Curl_node_next(e)) {
struct Curl_llist_node *n;
for(e = Curl_llist_head(&multi->msgsent); e; e = n) {
struct Curl_easy *data = Curl_node_elem(e);
n = Curl_node_next(e);
if(data) {
DEBUGASSERT(data->mstate == MSTATE_MSGSENT);
Curl_node_remove(&data->multi_queue);
@ -2725,8 +2726,9 @@ CURLMcode curl_multi_cleanup(CURLM *m)
if(data->psl == &multi->psl)
data->psl = NULL;
#endif
if(data->state.internal)
Curl_close(&data);
}
Curl_cpool_destroy(&multi->cpool);
Curl_cshutdn_destroy(&multi->cshutdn, multi->admin);
if(multi->admin) {

View file

@ -252,7 +252,7 @@ test2064 test2065 test2066 test2067 test2068 test2069 test2070 test2071 \
test2072 test2073 test2074 test2075 test2076 test2077 test2078 test2079 \
test2080 test2081 test2082 test2083 test2084 test2085 test2086 test2087 \
\
test2100 \
test2100 test2101 \
\
test2200 test2201 test2202 test2203 test2204 test2205 \
\

50
tests/data/test2101 Normal file
View file

@ -0,0 +1,50 @@
<testcase>
<info>
<keywords>
HTTP
HTTP GET
DOH
</keywords>
</info>
#
# Server-side
<reply>
<servercmd>
idle
</servercmd>
</reply>
#
# Client-side
<client>
<server>
http
</server>
# requires debug so that it can use the DoH server without https
<features>
Debug
DoH
</features>
<name>
DoH without response
</name>
<command>
http://neverreached.example.com/ --doh-url http://%HOSTIP:%HTTPPORT/%TESTNUMBER0001 -m 1
</command>
</client>
#
# Verify data after the test has been "shot"
<verify>
# curl: (28) Resolving timed out
# curl: (6) Could not resolve hostname
<errorcode>
28,6
</errorcode>
</verify>
</testcase>