]> granicus.if.org Git - curl/commitdiff
delayed easy handle kill caused double Curl_close() call
authorDaniel Stenberg <daniel@haxx.se>
Tue, 23 Mar 2010 12:18:30 +0000 (13:18 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 23 Mar 2010 12:18:30 +0000 (13:18 +0100)
Hauke Duden provided an example program that made the multi
interface crash.  His example simply used the multi interface and
did first one FTP transfer and after completion it used a second
easy handle and did another FTP transfer on the same FTP server.

This triggered a bug in the "delayed easy handle kill" system
that curl uses: when an FTP connection is left alive it must keep
an easy handle around internally - only for the purpose of having
an easy handle when it later disconnects it. The code assumed
that when the easy handle was removed and an internal reference
was made, that version could be killed later on when a new easy
handle came using the same connection. This was wrong as Hauke's
example showed that the removed handle wasn't killed for real
until later. This caused a double close attempt => segfault.

CHANGES
RELEASE-NOTES
lib/multi.c

diff --git a/CHANGES b/CHANGES
index 8d812727f8fceed59479da0aa23cadbae17f9af0..174fbc69f55b893aa3bc0294bc01606be6d64bd3 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,21 @@
 
                                   Changelog
 
+Daniel Stenberg (23 Mar 2010)
+- Hauke Duden provided an example program that made the multi interface crash.
+  His example simply used the multi interface and did first one FTP transfer
+  and after completion it used a second easy handle and did another FTP
+  transfer on the same FTP server.
+
+  This triggered a bug in the "delayed easy handle kill" system that curl
+  uses: when an FTP connection is left alive it must keep an easy handle
+  around internally - only for the purpose of having an easy handle when it
+  later disconnects it. The code assumed that when the easy handle was removed
+  and an internal reference was made, that version could be killed later on
+  when a new easy handle came using the same connection. This was wrong as
+  Hauke's example showed that the removed handle wasn't killed for real until
+  later. This caused a double close attempt => segfault.
+
 Daniel Stenberg (22 Mar 2010)
 - Thomas Lopatic fixed the alarm()-based DNS timeout:
 
index 072ad7e6b8d36aba0901cd90ff9689aaeaf8f400..6d0b7963dcb8470df48bc99172ac97a6ce9a2739 100644 (file)
@@ -36,6 +36,7 @@ This release includes the following bugfixes:
  o TFTP fixed TSIZE handling for uploads
  o SSL possible double free when reusing curl handle
  o alarm()-based DNS timeout bug
+ o re-used FTP connection multi interface crash
 
 This release includes the following known bugs:
 
@@ -47,6 +48,6 @@ advice from friends like these:
  Steven M. Schweda, Yang Tse, Jack Zhang, Tom Donovan, Martin Hager,
  Daniel Fandrich, Patrick Monnerat, Pat Ray, Wesley Miaw, Ben Greear,
  Ryan Chan, Markus Duft, Andrei Benea, Jacob Moshenko, Daniel Johnson,
- Constantine Sapuntzakis, Douglas Steinwand, Thomas Lopatic
+ Constantine Sapuntzakis, Douglas Steinwand, Thomas Lopatic, Hauke Duden
 
         Thanks! (and sorry if I forgot to mention someone)
index b24021280444dab917988698ba2597ca3584feec..d04fcf660974079ec8c1b2a13001aa7b67558356 100644 (file)
@@ -2416,10 +2416,16 @@ static CURLMcode add_closure(struct Curl_multi *multi,
 
     if(!inuse) {
       /* cl->easy_handle is now killable */
-      infof(data, "Delayed kill of easy handle %p\n", cl->easy_handle);
+
       /* unmark it as not having a connection around that uses it anymore */
       cl->easy_handle->state.shared_conn= NULL;
-      Curl_close(cl->easy_handle);
+
+      if(cl->easy_handle->state.closed) {
+        infof(data, "Delayed kill of easy handle %p\n", cl->easy_handle);
+        /* close handle only if curl_easy_cleanup() already has been called
+           for this easy handle */
+        Curl_close(cl->easy_handle);
+      }
       if(p)
         p->next = n;
       else