From 17f48fe87979f159e2d8769d678641c60f4c0eed Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Fri, 7 Oct 2011 20:50:57 +0200 Subject: [PATCH] libcurl: some OOM handling fixes --- lib/cookie.c | 19 +++++++++---------- lib/easy.c | 17 ++++++++--------- lib/hash.c | 6 +++++- lib/llist.c | 4 ++++ lib/multi.c | 1 + lib/slist.c | 5 +---- lib/sslgen.c | 5 ++++- lib/ssluse.c | 13 ++++++------- lib/telnet.c | 35 ++++++++++++++++++++++++++--------- lib/url.c | 18 ++++++++++++++++++ src/tool_doswin.c | 4 ++-- src/tool_operate.c | 2 +- tests/libtest/lib540.c | 41 +++++++++++++++++++++++++++++++++-------- 13 files changed, 118 insertions(+), 52 deletions(-) diff --git a/lib/cookie.c b/lib/cookie.c index 52a2ccb05..fc684ca1b 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -1107,23 +1107,20 @@ struct curl_slist *Curl_cookie_list(struct SessionHandle *data) c = data->cookies->cookies; - beg = list; while(c) { /* fill the list with _all_ the cookies we know */ line = get_netscape_format(c); - if(line == NULL) { - curl_slist_free_all(beg); + if(!line) { + curl_slist_free_all(list); return NULL; } - list = curl_slist_append(list, line); + beg = curl_slist_append(list, line); free(line); - if(list == NULL) { - curl_slist_free_all(beg); + if(!beg) { + curl_slist_free_all(list); return NULL; } - else if(beg == NULL) { - beg = list; - } + list = beg; c = c->next; } @@ -1148,10 +1145,12 @@ void Curl_flush_cookies(struct SessionHandle *data, int cleanup) data->set.str[STRING_COOKIEJAR]); } else { - if(cleanup && data->change.cookielist) + if(cleanup && data->change.cookielist) { /* since nothing is written, we can just free the list of cookie file names */ curl_slist_free_all(data->change.cookielist); /* clean up list */ + data->change.cookielist = NULL; + } Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); } diff --git a/lib/easy.c b/lib/easy.c index a18321172..9e06dc23b 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -676,16 +676,15 @@ CURL *curl_easy_duphandle(CURL *incurl) if(outcurl) { if(outcurl->state.connc && - (outcurl->state.connc->type == CONNCACHE_PRIVATE)) + (outcurl->state.connc->type == CONNCACHE_PRIVATE)) { Curl_rm_connc(outcurl->state.connc); - if(outcurl->state.headerbuff) - free(outcurl->state.headerbuff); - if(outcurl->change.cookielist) - curl_slist_free_all(outcurl->change.cookielist); - if(outcurl->change.url) - free(outcurl->change.url); - if(outcurl->change.referer) - free(outcurl->change.referer); + outcurl->state.connc = NULL; + } + curl_slist_free_all(outcurl->change.cookielist); + outcurl->change.cookielist = NULL; + Curl_safefree(outcurl->state.headerbuff); + Curl_safefree(outcurl->change.url); + Curl_safefree(outcurl->change.referer); Curl_freeset(outcurl); free(outcurl); } diff --git a/lib/hash.c b/lib/hash.c index 3a6e312a3..15b3efff6 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -72,9 +72,12 @@ Curl_hash_init(struct curl_hash *h, for(i = 0; i < slots; ++i) { h->table[i] = Curl_llist_alloc((curl_llist_dtor) hash_element_dtor); if(!h->table[i]) { - while(i--) + while(i--) { Curl_llist_destroy(h->table[i], NULL); + h->table[i] = NULL; + } free(h->table); + h->table = NULL; return 1; /* failure */ } } @@ -240,6 +243,7 @@ Curl_hash_clean(struct curl_hash *h) } free(h->table); + h->table = NULL; } void diff --git a/lib/llist.c b/lib/llist.c index 9ad1db59b..0aecf1083 100644 --- a/lib/llist.c +++ b/lib/llist.c @@ -131,6 +131,10 @@ Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e, list->dtor(user, e->ptr); + e->ptr = NULL; + e->prev = NULL; + e->next = NULL; + free(e); --list->size; diff --git a/lib/multi.c b/lib/multi.c index 0f7a24993..7786ccced 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -1804,6 +1804,7 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle) /* remove the pending list of messages */ Curl_llist_destroy(multi->msglist, NULL); + multi->msglist = NULL; /* remove all easy handles */ easy = multi->easy.next; diff --git a/lib/slist.c b/lib/slist.c index 8b4bd9d6b..4ddebb609 100644 --- a/lib/slist.c +++ b/lib/slist.c @@ -119,10 +119,7 @@ void curl_slist_free_all(struct curl_slist *list) item = list; do { next = item->next; - - if(item->data) { - free(item->data); - } + Curl_safefree(item->data); free(item); item = next; } while(next); diff --git a/lib/sslgen.c b/lib/sslgen.c index 77c641b24..3b7340244 100644 --- a/lib/sslgen.c +++ b/lib/sslgen.c @@ -504,9 +504,12 @@ void Curl_ssl_free_certinfo(struct SessionHandle *data) struct curl_certinfo *ci = &data->info.certs; if(ci->num_of_certs) { /* free all individual lists used */ - for(i=0; inum_of_certs; i++) + for(i=0; inum_of_certs; i++) { curl_slist_free_all(ci->certinfo[i]); + ci->certinfo[i] = NULL; + } free(ci->certinfo); /* free the actual array too */ + ci->certinfo = NULL; ci->num_of_certs = 0; } } diff --git a/lib/ssluse.c b/lib/ssluse.c index e5b84f93a..51bd909a1 100644 --- a/lib/ssluse.c +++ b/lib/ssluse.c @@ -810,18 +810,16 @@ struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data) { struct curl_slist *list = NULL; #if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H) - struct curl_slist *beg = NULL; + struct curl_slist *beg; ENGINE *e; for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) { - list = curl_slist_append(list, ENGINE_get_id(e)); - if(list == NULL) { - curl_slist_free_all(beg); + beg = curl_slist_append(list, ENGINE_get_id(e)); + if(!beg) { + curl_slist_free_all(list); return NULL; } - else if(beg == NULL) { - beg = list; - } + list = beg; } #endif (void) data; @@ -1859,6 +1857,7 @@ static CURLcode push_certinfo_len(struct SessionHandle *data, nl = curl_slist_append(ci->certinfo[certnum], output); if(!nl) { curl_slist_free_all(ci->certinfo[certnum]); + ci->certinfo[certnum] = NULL; res = CURLE_OUT_OF_MEMORY; } else diff --git a/lib/telnet.c b/lib/telnet.c index 5af7c3970..d1bc43cc9 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -763,18 +763,25 @@ static void printsub(struct SessionHandle *data, static CURLcode check_telnet_options(struct connectdata *conn) { struct curl_slist *head; + struct curl_slist *beg; char option_keyword[128]; char option_arg[256]; char *buf; struct SessionHandle *data = conn->data; struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet; + CURLcode result = CURLE_OK; /* Add the user name as an environment variable if it was given on the command line */ if(conn->bits.user_passwd) { snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user); - tn->telnet_vars = curl_slist_append(tn->telnet_vars, option_arg); - + beg = curl_slist_append(tn->telnet_vars, option_arg); + if(!beg) { + curl_slist_free_all(tn->telnet_vars); + tn->telnet_vars = NULL; + return CURLE_OUT_OF_MEMORY; + } + tn->telnet_vars = beg; tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; } @@ -800,24 +807,33 @@ static CURLcode check_telnet_options(struct connectdata *conn) /* Environment variable */ if(Curl_raw_equal(option_keyword, "NEW_ENV")) { - buf = strdup(option_arg); - if(!buf) - return CURLE_OUT_OF_MEMORY; - tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf); + beg = curl_slist_append(tn->telnet_vars, option_arg); + if(!beg) { + result = CURLE_OUT_OF_MEMORY; + break; + } + tn->telnet_vars = beg; tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; continue; } failf(data, "Unknown telnet option %s", head->data); - return CURLE_UNKNOWN_TELNET_OPTION; + result = CURLE_UNKNOWN_TELNET_OPTION; + break; } else { failf(data, "Syntax error in telnet option: %s", head->data); - return CURLE_TELNET_OPTION_SYNTAX; + result = CURLE_TELNET_OPTION_SYNTAX; + break; } } - return CURLE_OK; + if(result) { + curl_slist_free_all(tn->telnet_vars); + tn->telnet_vars = NULL; + } + + return result; } /* @@ -1109,6 +1125,7 @@ static CURLcode telnet_done(struct connectdata *conn, (void)premature; /* not used */ curl_slist_free_all(tn->telnet_vars); + tn->telnet_vars = NULL; free(conn->data->state.proto.telnet); conn->data->state.proto.telnet = NULL; diff --git a/lib/url.c b/lib/url.c index abb5a9ccc..7813b8285 100644 --- a/lib/url.c +++ b/lib/url.c @@ -2569,6 +2569,11 @@ static void conn_free(struct connectdata *conn) Curl_llist_destroy(conn->pend_pipe, NULL); Curl_llist_destroy(conn->done_pipe, NULL); + conn->send_pipe = NULL; + conn->recv_pipe = NULL; + conn->pend_pipe = NULL; + conn->done_pipe = NULL; + Curl_safefree(conn->localdev); Curl_free_ssl_config(&conn->ssl_config); @@ -3583,6 +3588,12 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) Curl_llist_destroy(conn->recv_pipe, NULL); Curl_llist_destroy(conn->pend_pipe, NULL); Curl_llist_destroy(conn->done_pipe, NULL); + + conn->send_pipe = NULL; + conn->recv_pipe = NULL; + conn->pend_pipe = NULL; + conn->done_pipe = NULL; + Curl_safefree(conn->master_buffer); Curl_safefree(conn->localdev); Curl_safefree(conn); @@ -4650,10 +4661,17 @@ static void reuse_conn(struct connectdata *old_conn, Curl_safefree(old_conn->passwd); Curl_safefree(old_conn->proxyuser); Curl_safefree(old_conn->proxypasswd); + Curl_llist_destroy(old_conn->send_pipe, NULL); Curl_llist_destroy(old_conn->recv_pipe, NULL); Curl_llist_destroy(old_conn->pend_pipe, NULL); Curl_llist_destroy(old_conn->done_pipe, NULL); + + old_conn->send_pipe = NULL; + old_conn->recv_pipe = NULL; + old_conn->pend_pipe = NULL; + old_conn->done_pipe = NULL; + Curl_safefree(old_conn->master_buffer); } diff --git a/src/tool_doswin.c b/src/tool_doswin.c index b45522b53..b23b50af1 100644 --- a/src/tool_doswin.c +++ b/src/tool_doswin.c @@ -109,7 +109,7 @@ char *sanitize_dos_name(char *file_name) strcpy(new_name, msdosify(file_name)); - free(file_name); + Curl_safefree(file_name); return strdup(rename_if_dos_device_name(new_name)); } @@ -288,7 +288,7 @@ CURLcode FindWin32CACert(struct Configurable *config, const char *bundle_file) else result = CURLE_SSL_CACERT; - free(buf); + Curl_safefree(buf); } return result; diff --git a/src/tool_operate.c b/src/tool_operate.c index 3ee1d10d2..481116ddf 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -971,7 +971,7 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) /* libssh2 version older than 1.1.1 */ res = CURLE_OK; } - free(home); + Curl_safefree(home); } if(res) goto show_error; diff --git a/tests/libtest/lib540.c b/tests/libtest/lib540.c index 8fb409f07..467e87dc4 100644 --- a/tests/libtest/lib540.c +++ b/tests/libtest/lib540.c @@ -49,23 +49,45 @@ static int init(CURLM *cm, const char* url, const char* userpwd, } res = curl_easy_setopt(eh, CURLOPT_URL, url); - if(res) return 1; + if(res) { + curl_easy_cleanup(eh); + return 1; + } res = curl_easy_setopt(eh, CURLOPT_PROXY, PROXY); - if(res) return 1; + if(res) { + curl_easy_cleanup(eh); + return 1; + } res = curl_easy_setopt(eh, CURLOPT_PROXYUSERPWD, userpwd); - if(res) return 1; + if(res) { + curl_easy_cleanup(eh); + return 1; + } res = curl_easy_setopt(eh, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY); - if(res) return 1; + if(res) { + curl_easy_cleanup(eh); + return 1; + } res = curl_easy_setopt(eh, CURLOPT_VERBOSE, 1L); - if(res) return 1; + if(res) { + curl_easy_cleanup(eh); + return 1; + } res = curl_easy_setopt(eh, CURLOPT_HEADER, 1L); - if(res) return 1; + if(res) { + curl_easy_cleanup(eh); + return 1; + } res = curl_easy_setopt(eh, CURLOPT_HTTPHEADER, headers); /* custom Host: */ - if(res) return 1; + if(res) { + curl_easy_cleanup(eh); + return 1; + } if ((res = (int)curl_multi_add_handle(cm, eh)) != CURLM_OK) { fprintf(stderr, "curl_multi_add_handle() failed, " "with code %d\n", res); + curl_easy_cleanup(eh); return 1; /* failure */ } @@ -80,13 +102,16 @@ static int loop(CURLM *cm, const char* url, const char* userpwd, int M, Q, U = -1; fd_set R, W, E; struct timeval T; + CURLMcode rc; if(init(cm, url, userpwd, headers)) return 1; /* failure */ while (U) { - (void) curl_multi_perform(cm, &U); + rc = curl_multi_perform(cm, &U); + if(rc == CURLM_OUT_OF_MEMORY) + return 1; /* failure */ if (U) { FD_ZERO(&R);