From ae13c93b7db9f9c68eaf95150ed551b3b649d8c4 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 28 Sep 2006 21:26:06 +0000 Subject: Reported in #1561470 (http://curl.haxx.se/bug/view.cgi?id=1561470), libcurl would crash if a bad function sequence was used when shutting down after using the multi interface (i.e using easy_cleanup after multi_cleanup) so precautions have been added to make sure it doesn't any more - test case 529 was added to verify. --- lib/multi.c | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) (limited to 'lib/multi.c') diff --git a/lib/multi.c b/lib/multi.c index 244994cfe..9d596401a 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -172,6 +172,8 @@ static bool multi_conn_using(struct Curl_multi *multi, struct SessionHandle *data); static void singlesocket(struct Curl_multi *multi, struct Curl_one_easy *easy); +static void add_closure(struct Curl_multi *multi, + struct SessionHandle *data); /* always use this function to change state, to make debugging easier */ static void multistate(struct Curl_one_easy *easy, CURLMstate state) @@ -539,17 +541,28 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, we need to add this handle to the list of "easy handles kept around for nice connection closures". */ - if(multi_conn_using(multi, easy->easy_handle)) + if(multi_conn_using(multi, easy->easy_handle)) { /* There's at least one connection using this handle so we must keep this handle around. We also keep the connection cache pointer pointing to the shared one since that will be used on close as well. */ easy->easy_handle->state.shared_conn = multi; - else - if(easy->easy_handle->state.connc->type == CONNCACHE_MULTI) - /* if this was using the shared connection cache we clear the pointer - to that */ - easy->easy_handle->state.connc = NULL; + + /* this handle is still being used by a shared connection cache and + thus we leave it around for now */ + add_closure(multi, easy->easy_handle); + } + + if(easy->easy_handle->state.connc->type == CONNCACHE_MULTI) { + /* if this was using the shared connection cache we clear the pointer + to that since we're not part of that handle anymore */ + easy->easy_handle->state.connc = NULL; + + /* and modify the connectindex since this handle can't point to the + connection cache anymore */ + if(easy->easy_conn) + easy->easy_conn->connectindex = -1; + } /* change state without using multistate(), only to make singlesocket() do what we want */ @@ -1320,15 +1333,20 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle) /* go over all connections that have close actions */ for(i=0; i< multi->connc->num; i++) { if(multi->connc->connects[i] && - multi->connc->connects[i]->protocol & PROT_CLOSEACTION) + multi->connc->connects[i]->protocol & PROT_CLOSEACTION) { Curl_disconnect(multi->connc->connects[i]); + multi->connc->connects[i] = NULL; + } } /* now walk through the list of handles we kept around only to be able to close connections "properly" */ cl = multi->closure; while(cl) { cl->easy_handle->state.shared_conn = NULL; /* no more shared */ - Curl_close(cl->easy_handle); /* close handle */ + if(cl->easy_handle->state.closed) + /* close handle only if curl_easy_cleanup() already has been called + for this easy handle */ + Curl_close(cl->easy_handle); n = cl->next; free(cl); cl= n; @@ -1780,8 +1798,8 @@ static bool multi_conn_using(struct Curl_multi *multi, /* add the given data pointer to the list of 'closure handles' that are kept around only to be able to close some connections nicely */ -void Curl_multi_add_closure(struct Curl_multi *multi, - struct SessionHandle *data) +static void add_closure(struct Curl_multi *multi, + struct SessionHandle *data) { int i; struct closure *cl = (struct closure *)calloc(sizeof(struct closure), 1); -- cgit v1.2.3