multi_cleanup: call DONE on handles that never got that

... fixes a memory leak with at least IMAP when remove_handle is never
called and the transfer is abruptly just abandoned early.

Test 1552 added to verify

Detected by OSS-fuzz
Assisted-by: Max Dymond
Closes #1954
This commit is contained in:
Daniel Stenberg 2017-10-06 01:11:17 +02:00
parent 454dae0092
commit 7f1140c8bf
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
5 changed files with 171 additions and 20 deletions

View file

@ -2224,6 +2224,27 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
multi->type = 0; /* not good anymore */
/* Firsrt remove all remaining easy handles */
data = multi->easyp;
while(data) {
nextdata = data->next;
if(!data->state.done && data->easy_conn)
/* if DONE was never called for this handle */
(void)multi_done(&data->easy_conn, CURLE_OK, TRUE);
if(data->dns.hostcachetype == HCACHE_MULTI) {
/* clear out the usage of the shared DNS cache */
Curl_hostcache_clean(data, data->dns.hostcache);
data->dns.hostcache = NULL;
data->dns.hostcachetype = HCACHE_NONE;
}
/* Clear the pointer to the connection cache */
data->state.conn_cache = NULL;
data->multi = NULL; /* clear the association */
data = nextdata;
}
/* Close all the connections in the connection cache */
close_all_connections(multi);
@ -2243,24 +2264,6 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
Curl_llist_destroy(&multi->msglist, NULL);
Curl_llist_destroy(&multi->pending, NULL);
/* remove all easy handles */
data = multi->easyp;
while(data) {
nextdata = data->next;
if(data->dns.hostcachetype == HCACHE_MULTI) {
/* clear out the usage of the shared DNS cache */
Curl_hostcache_clean(data, data->dns.hostcache);
data->dns.hostcache = NULL;
data->dns.hostcachetype = HCACHE_NONE;
}
/* Clear the pointer to the connection cache */
data->state.conn_cache = NULL;
data->multi = NULL; /* clear the association */
data = nextdata;
}
Curl_hash_destroy(&multi->hostcache);
/* Free the blacklists by setting them to NULL */