Skip to content

socket.readline() interface doesn't handle EINTR properly #44412

Closed

Description

@sobomax
mannequin
BPO 1628205
Nosy @loewis, @gpshead
Files
  • diff: Proposed fix.
  • diff: Updated fix and test case
  • issue1628205-gps01.diff.txt
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/gpshead'
    closed_at = <Date 2010-12-15.20:00:10.644>
    created_at = <Date 2007-01-04.21:37:50.000>
    labels = ['extension-modules', 'type-bug', 'library']
    title = "socket.readline() interface doesn't handle EINTR properly"
    updated_at = <Date 2010-12-15.20:00:10.642>
    user = 'https://bugs.python.org/sobomax'

    bugs.python.org fields:

    activity = <Date 2010-12-15.20:00:10.642>
    actor = 'pitrou'
    assignee = 'gregory.p.smith'
    closed = True
    closed_date = <Date 2010-12-15.20:00:10.644>
    closer = 'pitrou'
    components = ['Extension Modules', 'Library (Lib)']
    creation = <Date 2007-01-04.21:37:50.000>
    creator = 'sobomax'
    dependencies = []
    files = ['7694', '14634', '14667']
    hgrepos = []
    issue_num = 1628205
    keywords = ['patch']
    message_count = 11.0
    messages = ['51655', '51656', '51657', '51658', '51659', '91209', '91359', '91409', '91414', '91532', '106334']
    nosy_count = 8.0
    nosy_names = ['loewis', 'gregory.p.smith', 'jorend', 'orenti', 'exarkun', 'sobomax', 'vila', 'rhettg']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = 'test needed'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue1628205'
    versions = ['Python 2.6', 'Python 3.0', 'Python 3.1', 'Python 2.7']

    Activity

    1. sobomax commented on Jan 4, 2007

      sobomaxmannequin
      MannequinAuthor

      The socket.readline() interface doesn't handle EINTR properly. Currently, when EINTR received exception is not handled and all data that has been in the buffer is lost. There is no way to recover that data from the code that uses the interface.

      Correct behaviour would be to catch EINTR and restart recv(). Patch is attached.

      Following is the real world example of how it affects httplib module:

      File "/usr/local/lib/python2.4/xmlrpclib.py", line 1096, in __call__
      return self.__send(self.__name, args)
      File "/usr/local/lib/python2.4/xmlrpclib.py", line 1383, in __request
      verbose=self.__verbose
      File "/usr/local/lib/python2.4/xmlrpclib.py", line 1131, in request
      errcode, errmsg, headers = h.getreply()
      File "/usr/local/lib/python2.4/httplib.py", line 1137, in getreply
      response = self._conn.getresponse()
      File "/usr/local/lib/python2.4/httplib.py", line 866, in getresponse
      response.begin()
      File "/usr/local/lib/python2.4/httplib.py", line 336, in begin
      version, status, reason = self._read_status()
      File "/usr/local/lib/python2.4/httplib.py", line 294, in _read_status
      line = self.fp.readline()
      File "/usr/local/lib/python2.4/socket.py", line 325, in readline
      data = recv(1)
      error: (4, 'Interrupted system call')

      -Maxim

    2. orenti commented on Jan 7, 2007

      orentimannequin
      Mannequin

      You may have encountered this on sockets but *all* Python I/O does not handle restart on EINTR.

      The right place to fix this is probably in C, not the Python library. The places where an I/O operation could be interrupted are practically anywhere the GIL is released. This kind of change is likely to be controversial.

    3. sobomax commented on Jan 8, 2007

      sobomaxmannequin
      MannequinAuthor

      Well, it's not quite correct since for example httplib.py tries to handle EINTR. The fundamental problem with socket.readline() is that it does internal buffering so that getting EINTR results in data being lost.

      I don't think it has to be fixed in C, since recv() is very low-level interface and it is expected to return EINTR on signal, so that "fixing" it there could possibly break software that relies on this behaviour. And I don't quite buy your reasoning - "since it's broken in few more places let's keep it consistently broken everywhere". To me it sounds like attempt to hide the head in the sand instead of facing the problem at hand. Fixing socket.readline() may be the first step in improvind the library to handle this condition properly.

    4. loewis commented on Feb 16, 2007

      loewismannequin
      Mannequin

      I agree that this should be fixed; I'm not sure I like the proposed fixed, though. It discards the exception and keeps running.

      What it (IMO) should do instead is abort, then return the data on the next invocation. Of course, this may have problems in itself, since the file descriptor might not report read-ready when passed to select or poll, even though data are available.

      Please discuss this on python-dev (and elsewhere), and report what recommendations people made.

    5. jorend commented on Mar 7, 2007

      jorendmannequin
      Mannequin

      loewis: I think your idea is the right answer. I'm not worried about select/poll. Surely no one uses select/poll and socket._fileobject.readline() on the same socket. select/poll are for nonblocking sockets; this readline() method doesn't even catch EWOULDBLOCK.

      ...In fact even if you did use select/poll on the (blocking) socket after readline() threw EINTR--which no one should do--I think it would still work just as expected unless you were doing something truly weird.

    6. added
      stdlibStandard Library Python modules in the Lib/ directory
      type-bugAn unexpected behavior, bug, or error
      on Mar 30, 2009
    7. rhettg commented on Aug 2, 2009

      rhettgmannequin
      Mannequin

      I've hit this issue as well.
      Attached is an updated patch to 2.6 branch and a test case.
      I wrote up more details here:
      http://nullhole.com/2009/08/02/anatomy-of-a-regression-test/

    8. gpshead commented on Aug 6, 2009

      @gpshead
      Member

      nice test case rhettg.

      This is a correctness issue to prevent data loss on EINTR.

      I've attached a patch that builds on rhettg's but allows the EINTR signal
      to propagate upwards as desired by loweis and jorend for both read() and
      readline() calls.

    9. gpshead commented on Aug 7, 2009

      @gpshead
      Member

      realistically, file objects (Objects/fileobject.c) never raise EINTR as
      they use the C library fread/fwrite/fclose underneath. Why should a
      socket based file object every be allowed to raise EINTR rather than
      handling it internally?

      IMHO people should only expect to handle EINTR when doing
      socket.send/recv or os.read/write/close, not using a file-like object.

    10. rhettg commented on Aug 7, 2009

      rhettgmannequin
      Mannequin

      Good addition Gregory.
      Totally agree on handling EINTR in even more cases.
      You can't really expect the caller to know they need to deal with this
      sort of thing when using these higher level call. The whole point is the
      abstract away some of the complexity of dealing with the system call.

    11. gpshead commented on Aug 13, 2009

      @gpshead
      Member

      fixed in trunk r74426. socket.socket.sendall() and all
      socket._fileobject methods (read/readline/write/flush) now properly
      handle EINTR internally.

      sendall will allow a python signal handler to raise an exception
      aborting it in unknown state, otherwise it handles EINTR as it should
      and continues sending.

      I'm leaving this issue open until it is merged into py3k and considered
      for 2.6 and/or 3.1 release backporting.

    12. exarkun commented on May 23, 2010

      exarkunmannequin
      Mannequin

      Backported to release26-maint in r81488.

    13. transferred this issue fromon Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    Labels

    extension-modulesC modules in the Modules dirstdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions