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.
This commit is contained in:
parent
b9f8a4a477
commit
ae13c93b7d
12
CHANGES
12
CHANGES
@ -6,6 +6,18 @@
|
|||||||
|
|
||||||
Changelog
|
Changelog
|
||||||
|
|
||||||
|
Daniel (28 September 2006)
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
Daniel (27 September 2006)
|
||||||
|
- The URL in the cookie jar file is now changed since it was giving a 404.
|
||||||
|
Reported by Timothy Stone. The new URL will take the visitor to a curl web
|
||||||
|
site mirror with the document.
|
||||||
|
|
||||||
Daniel (24 September 2006)
|
Daniel (24 September 2006)
|
||||||
- Bernard Leak fixed configure --with-gssapi-libs.
|
- Bernard Leak fixed configure --with-gssapi-libs.
|
||||||
|
|
||||||
|
@ -11,10 +11,11 @@ Curl and libcurl 7.16.0
|
|||||||
|
|
||||||
This release includes the following changes:
|
This release includes the following changes:
|
||||||
|
|
||||||
|
o curl_multi_socket() and family are suitable to start using
|
||||||
o uses WSAPoll() on Windows Vista
|
o uses WSAPoll() on Windows Vista
|
||||||
o (FTP) --ftp-ssl-control was added
|
o (FTP) --ftp-ssl-control was added
|
||||||
o CURLOPT_SSL_SESSIONID_CACHE and --no-sessionid added
|
o CURLOPT_SSL_SESSIONID_CACHE and --no-sessionid added
|
||||||
o CURLMOPT_PIPELINING added for enabling pipelined transfers
|
o CURLMOPT_PIPELINING added for enabling HTTP pipelined transfers
|
||||||
o multi handles now have a shared connection cache
|
o multi handles now have a shared connection cache
|
||||||
o Added support for other MS-DOS compilers (besides djgpp)
|
o Added support for other MS-DOS compilers (besides djgpp)
|
||||||
o CURLOPT_SOCKOPTFUNCTION and CURLOPT_SOCKOPTDATA were added
|
o CURLOPT_SOCKOPTFUNCTION and CURLOPT_SOCKOPTDATA were added
|
||||||
@ -23,6 +24,9 @@ This release includes the following changes:
|
|||||||
|
|
||||||
This release includes the following bugfixes:
|
This release includes the following bugfixes:
|
||||||
|
|
||||||
|
o multi interface crash if bad function call order was used for cleanup
|
||||||
|
o put a new URL in saved cookie jar files
|
||||||
|
o configure --with-gssapi-libs
|
||||||
o SOCKS proxy connection fixes
|
o SOCKS proxy connection fixes
|
||||||
o (FTP) a failed upload does not invalidate the control connection
|
o (FTP) a failed upload does not invalidate the control connection
|
||||||
o proxy URL with user name and empty password or no password at all now work
|
o proxy URL with user name and empty password or no password at all now work
|
||||||
@ -55,6 +59,6 @@ advice from friends like these:
|
|||||||
Domenico Andreoli, Armel Asselin, Gisle Vanem, Yang Tse, Andrew Biggs,
|
Domenico Andreoli, Armel Asselin, Gisle Vanem, Yang Tse, Andrew Biggs,
|
||||||
Peter Sylvester, David McCreedy, Dmitriy Sergeyev, Dmitry Rechkin,
|
Peter Sylvester, David McCreedy, Dmitriy Sergeyev, Dmitry Rechkin,
|
||||||
Jari Sundell, Ravi Pratap, Michele Bini, Jeff Pohlmeyer, Michael Wallner,
|
Jari Sundell, Ravi Pratap, Michele Bini, Jeff Pohlmeyer, Michael Wallner,
|
||||||
Mike Protts, Cory Nelson
|
Mike Protts, Cory Nelson, Bernard Leak
|
||||||
|
|
||||||
Thanks! (and sorry if I forgot to mention someone)
|
Thanks! (and sorry if I forgot to mention someone)
|
||||||
|
38
lib/multi.c
38
lib/multi.c
@ -172,6 +172,8 @@ static bool multi_conn_using(struct Curl_multi *multi,
|
|||||||
struct SessionHandle *data);
|
struct SessionHandle *data);
|
||||||
static void singlesocket(struct Curl_multi *multi,
|
static void singlesocket(struct Curl_multi *multi,
|
||||||
struct Curl_one_easy *easy);
|
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 */
|
/* always use this function to change state, to make debugging easier */
|
||||||
static void multistate(struct Curl_one_easy *easy, CURLMstate state)
|
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
|
we need to add this handle to the list of "easy handles kept around for
|
||||||
nice connection closures".
|
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
|
/* There's at least one connection using this handle so we must keep
|
||||||
this handle around. We also keep the connection cache pointer
|
this handle around. We also keep the connection cache pointer
|
||||||
pointing to the shared one since that will be used on close as
|
pointing to the shared one since that will be used on close as
|
||||||
well. */
|
well. */
|
||||||
easy->easy_handle->state.shared_conn = multi;
|
easy->easy_handle->state.shared_conn = multi;
|
||||||
else
|
|
||||||
if(easy->easy_handle->state.connc->type == CONNCACHE_MULTI)
|
/* this handle is still being used by a shared connection cache and
|
||||||
/* if this was using the shared connection cache we clear the pointer
|
thus we leave it around for now */
|
||||||
to that */
|
add_closure(multi, easy->easy_handle);
|
||||||
easy->easy_handle->state.connc = NULL;
|
}
|
||||||
|
|
||||||
|
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
|
/* change state without using multistate(), only to make singlesocket() do
|
||||||
what we want */
|
what we want */
|
||||||
@ -1320,15 +1333,20 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle)
|
|||||||
/* go over all connections that have close actions */
|
/* go over all connections that have close actions */
|
||||||
for(i=0; i< multi->connc->num; i++) {
|
for(i=0; i< multi->connc->num; i++) {
|
||||||
if(multi->connc->connects[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]);
|
Curl_disconnect(multi->connc->connects[i]);
|
||||||
|
multi->connc->connects[i] = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* now walk through the list of handles we kept around only to be
|
/* now walk through the list of handles we kept around only to be
|
||||||
able to close connections "properly" */
|
able to close connections "properly" */
|
||||||
cl = multi->closure;
|
cl = multi->closure;
|
||||||
while(cl) {
|
while(cl) {
|
||||||
cl->easy_handle->state.shared_conn = NULL; /* no more shared */
|
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;
|
n = cl->next;
|
||||||
free(cl);
|
free(cl);
|
||||||
cl= n;
|
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
|
/* add the given data pointer to the list of 'closure handles' that are
|
||||||
kept around only to be able to close some connections nicely */
|
kept around only to be able to close some connections nicely */
|
||||||
void Curl_multi_add_closure(struct Curl_multi *multi,
|
static void add_closure(struct Curl_multi *multi,
|
||||||
struct SessionHandle *data)
|
struct SessionHandle *data)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct closure *cl = (struct closure *)calloc(sizeof(struct closure), 1);
|
struct closure *cl = (struct closure *)calloc(sizeof(struct closure), 1);
|
||||||
|
@ -32,9 +32,6 @@ void Curl_multi_rmeasy(void *multi, CURL *data);
|
|||||||
|
|
||||||
bool Curl_multi_canPipeline(struct Curl_multi* multi);
|
bool Curl_multi_canPipeline(struct Curl_multi* multi);
|
||||||
|
|
||||||
void Curl_multi_add_closure(struct Curl_multi *multi,
|
|
||||||
struct SessionHandle *data);
|
|
||||||
|
|
||||||
/* the write bits start at bit 16 for the *getsock() bitmap */
|
/* the write bits start at bit 16 for the *getsock() bitmap */
|
||||||
#define GETSOCK_WRITEBITSTART 16
|
#define GETSOCK_WRITEBITSTART 16
|
||||||
|
|
||||||
|
30
lib/url.c
30
lib/url.c
@ -269,13 +269,23 @@ CURLcode Curl_close(struct SessionHandle *data)
|
|||||||
the multi handle, since that function uses the magic
|
the multi handle, since that function uses the magic
|
||||||
field! */
|
field! */
|
||||||
|
|
||||||
if(data->state.connc && (data->state.connc->type == CONNCACHE_PRIVATE)) {
|
if(data->state.connc) {
|
||||||
/* close all connections still alive that are in the private connection
|
|
||||||
cache, as we no longer have the pointer left to the shared one. */
|
|
||||||
close_connections(data);
|
|
||||||
|
|
||||||
/* free the connection cache if allocated privately */
|
if(data->state.connc->type == CONNCACHE_PRIVATE) {
|
||||||
Curl_rm_connc(data->state.connc);
|
/* close all connections still alive that are in the private connection
|
||||||
|
cache, as we no longer have the pointer left to the shared one. */
|
||||||
|
close_connections(data);
|
||||||
|
|
||||||
|
/* free the connection cache if allocated privately */
|
||||||
|
Curl_rm_connc(data->state.connc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data->state.shared_conn) {
|
||||||
|
/* marked to be used by a pending connection so we can't kill this handle
|
||||||
|
just yet */
|
||||||
|
data->state.closed = TRUE;
|
||||||
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! (data->share && data->share->hostcache) ) {
|
if ( ! (data->share && data->share->hostcache) ) {
|
||||||
@ -284,14 +294,6 @@ CURLcode Curl_close(struct SessionHandle *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(data->state.shared_conn) {
|
|
||||||
/* this handle is still being used by a shared connection cache and thus
|
|
||||||
we leave it around for now */
|
|
||||||
Curl_multi_add_closure(data->state.shared_conn, data);
|
|
||||||
|
|
||||||
return CURLE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free the pathbuffer */
|
/* Free the pathbuffer */
|
||||||
Curl_safefree(data->reqdata.pathbuffer);
|
Curl_safefree(data->reqdata.pathbuffer);
|
||||||
Curl_safefree(data->reqdata.proto.generic);
|
Curl_safefree(data->reqdata.proto.generic);
|
||||||
|
@ -1053,6 +1053,9 @@ struct UrlState {
|
|||||||
must keep it around and add it to the list of handles to kill once all
|
must keep it around and add it to the list of handles to kill once all
|
||||||
its connections are gone */
|
its connections are gone */
|
||||||
void *shared_conn;
|
void *shared_conn;
|
||||||
|
bool closed; /* set to TRUE when curl_easy_cleanup() has been called on this
|
||||||
|
handle, but it is kept around as mentioned for
|
||||||
|
shared_conn */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,6 +35,4 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \
|
|||||||
test256 test257 test258 test259 test260 test261 test262 test263 test264 \
|
test256 test257 test258 test259 test260 test261 test262 test263 test264 \
|
||||||
test265 test266 test267 test268 test269 test270 test271 test272 test273 \
|
test265 test266 test267 test268 test269 test270 test271 test272 test273 \
|
||||||
test274 test275 test524 test525 test276 test277 test526 test527 test528 \
|
test274 test275 test524 test525 test276 test277 test526 test527 test528 \
|
||||||
test530 DISABLED test278 test279 test531 test280
|
test530 DISABLED test278 test279 test531 test280 test529
|
||||||
|
|
||||||
|
|
||||||
|
55
tests/data/test529
Normal file
55
tests/data/test529
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<info>
|
||||||
|
<keywords>
|
||||||
|
FTP
|
||||||
|
PORT
|
||||||
|
STOR
|
||||||
|
</keywords>
|
||||||
|
</info>
|
||||||
|
# Server-side
|
||||||
|
<reply>
|
||||||
|
<data>
|
||||||
|
</data>
|
||||||
|
</reply>
|
||||||
|
|
||||||
|
# Client-side
|
||||||
|
<client>
|
||||||
|
<server>
|
||||||
|
ftp
|
||||||
|
</server>
|
||||||
|
<tool>
|
||||||
|
lib529
|
||||||
|
</tool>
|
||||||
|
<name>
|
||||||
|
FTP PORT upload using multi interface (weird cleanup function sequence)
|
||||||
|
</name>
|
||||||
|
<command>
|
||||||
|
ftp://%HOSTIP:%FTPPORT/path/529 log/upload529
|
||||||
|
</command>
|
||||||
|
<file name="log/upload529">
|
||||||
|
Moooooooooooo
|
||||||
|
upload this
|
||||||
|
</file>
|
||||||
|
</client>
|
||||||
|
|
||||||
|
# Verify data after the test has been "shot"
|
||||||
|
<verify>
|
||||||
|
<strip>
|
||||||
|
^PORT .*
|
||||||
|
^EPRT .*
|
||||||
|
^LPRT .*
|
||||||
|
</strip>
|
||||||
|
<protocol>
|
||||||
|
USER anonymous
|
||||||
|
PASS curl_by_daniel@haxx.se
|
||||||
|
PWD
|
||||||
|
CWD path
|
||||||
|
PORT 127,0,0,1,5,109
|
||||||
|
TYPE I
|
||||||
|
STOR 529
|
||||||
|
QUIT
|
||||||
|
</protocol>
|
||||||
|
<upload>
|
||||||
|
Moooooooooooo
|
||||||
|
upload this
|
||||||
|
</upload>
|
||||||
|
</verify>
|
@ -39,9 +39,10 @@ LIBDIR = $(top_builddir)/lib
|
|||||||
SUPPORTFILES = first.c test.h
|
SUPPORTFILES = first.c test.h
|
||||||
|
|
||||||
# These are all libcurl test programs
|
# These are all libcurl test programs
|
||||||
noinst_PROGRAMS = lib500 lib501 lib502 lib503 lib504 lib505 lib506 lib507 \
|
noinst_PROGRAMS = lib500 lib501 lib502 lib503 lib504 lib505 lib506 \
|
||||||
lib508 lib509 lib510 lib511 lib512 lib513 lib514 lib515 lib516 lib517 \
|
lib507 lib508 lib509 lib510 lib511 lib512 lib513 lib514 lib515 lib516 \
|
||||||
lib518 lib519 lib520 lib521 lib523 lib524 lib525 lib526 lib527 lib530
|
lib517 lib518 lib519 lib520 lib521 lib523 lib524 lib525 lib526 lib527 \
|
||||||
|
lib529 lib530
|
||||||
|
|
||||||
lib500_SOURCES = lib500.c $(SUPPORTFILES)
|
lib500_SOURCES = lib500.c $(SUPPORTFILES)
|
||||||
lib500_LDADD = $(LIBDIR)/libcurl.la
|
lib500_LDADD = $(LIBDIR)/libcurl.la
|
||||||
@ -152,6 +153,11 @@ lib527_CFLAGS = -DLIB527
|
|||||||
lib527_LDADD = $(LIBDIR)/libcurl.la
|
lib527_LDADD = $(LIBDIR)/libcurl.la
|
||||||
lib527_DEPENDENCIES = $(LIBDIR)/libcurl.la
|
lib527_DEPENDENCIES = $(LIBDIR)/libcurl.la
|
||||||
|
|
||||||
|
lib529_SOURCES = lib525.c $(SUPPORTFILES)
|
||||||
|
lib529_CFLAGS = -DLIB529
|
||||||
|
lib529_LDADD = $(LIBDIR)/libcurl.la
|
||||||
|
lib529_DEPENDENCIES = $(LIBDIR)/libcurl.la
|
||||||
|
|
||||||
lib530_SOURCES = lib530.c $(SUPPORTFILES)
|
lib530_SOURCES = lib530.c $(SUPPORTFILES)
|
||||||
lib530_CFLAGS = -DLIB530
|
lib530_CFLAGS = -DLIB530
|
||||||
lib530_LDADD = $(LIBDIR)/libcurl.la
|
lib530_LDADD = $(LIBDIR)/libcurl.la
|
||||||
|
@ -123,9 +123,17 @@ int test(char *URL)
|
|||||||
res = CURLM_CALL_MULTI_PERFORM;
|
res = CURLM_CALL_MULTI_PERFORM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LIB529
|
||||||
|
/* test 529 */
|
||||||
|
curl_multi_remove_handle(m, curl);
|
||||||
|
curl_multi_cleanup(m);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
#else
|
||||||
|
/* test 525 */
|
||||||
curl_multi_remove_handle(m, curl);
|
curl_multi_remove_handle(m, curl);
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
curl_multi_cleanup(m);
|
curl_multi_cleanup(m);
|
||||||
|
#endif
|
||||||
|
|
||||||
fclose(hd_src); /* close the local file */
|
fclose(hd_src); /* close the local file */
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user