[PATCH] fix hang because of infinite loop reading EOF

Haojun Bao baohaojun at gmail.com
Thu Mar 3 02:46:33 UTC 2011


Hi, all

Offlineimap sometimes hangs when downloading gmail with large
attachment.

This is because of several infinite loop when reading the socket while
the EOF has happened. It can be seen from 2 facts:

    1. strace will show read(2) syscall repeatedly returning 0 on the
    same fd.

    2. netstat will show the socket in CLOSE_WAIT state. 

Also, when the hang happens, if you don't kill offlineimap, the system
memory will be used up by it in the end, thus causing a system hang. Why
this is so I didn't get it quitely. (BTW, the CPU is 100% as soon as the
read(2) infinite loop begin).

After reading the mailing list, I see Gábor Melis has proposed a patch
(SO_KEEPALIVE) to fix hang, I don't know if my case is same as his. But
anyway, I think the several read methods contain bugs in their
implementation.

You can use the following patch to fix the problem.

(I have posted it on the news server, but not sure did it get through.)

Signed-off-by: Bao Haojun <baohaojun at gmail.com>

---
 offlineimap/imaplibutil.py |    9 ++++++++-
 offlineimap/imapserver.py  |    4 ++++
 2 files changed, 12 insertions(+), 1 deletions(-)

diff --git a/offlineimap/imaplibutil.py b/offlineimap/imaplibutil.py
index 69d3983..ad98ab8 100644
--- a/offlineimap/imaplibutil.py
+++ b/offlineimap/imaplibutil.py
@@ -47,7 +47,10 @@ class IMAP4_Tunnel(IMAP4):
     def read(self, size):
         retval = ''
         while len(retval) < size:
-            retval += self.infd.read(size - len(retval))
+            buf = self.infd.read(size - len(retval))
+            if not buf:
+                break
+            retval += buf
         return retval
 
     def readline(self):
@@ -200,6 +203,8 @@ class WrappedIMAP4_SSL(IMAP4_SSL):
         read = 0
         while read < n:
             data = self._read_upto (n-read)
+            if not data:
+                break
             read += len(data)
             chunks.append(data)
 
@@ -212,6 +217,8 @@ class WrappedIMAP4_SSL(IMAP4_SSL):
         retval = ''
         while 1:
             linebuf = self._read_upto(1024)
+            if not linebuf:
+                return retval
             nlindex = linebuf.find("\n")
             if nlindex != -1:
                 retval += linebuf[:nlindex + 1]
diff --git a/offlineimap/imapserver.py b/offlineimap/imapserver.py
index 2a9f247..c298aa3 100644
--- a/offlineimap/imapserver.py
+++ b/offlineimap/imapserver.py
@@ -71,6 +71,8 @@ class UsefulIMAP4(UsefulIMAPMixIn, imaplibutil.WrappedIMAP4):
             io = StringIO()
             while read < size:
                 data = imaplib.IMAP4.read (self, min(size-read,8192))
+                if not data:
+                    break
                 read += len(data)
                 io.write(data)
             return io.getvalue()
@@ -86,6 +88,8 @@ class UsefulIMAP4_SSL(UsefulIMAPMixIn, imaplibutil.WrappedIMAP4_SSL):
             io = StringIO()
             while read < size:
                 data = imaplibutil.WrappedIMAP4_SSL.read (self, min(size-read,8192))
+                if not data:
+                    break
                 read += len(data)
                 io.write(data)
             return io.getvalue()
-- 
1.7.2.3



More information about the OfflineIMAP-project mailing list