Skip to content

socket.close() doesn't play well with __del__ #39247

Closed

Description

@perrygreenfield
BPO 808164
Nosy @pitrou, @devdanzin
Files
  • issue808164-27.patch
  • issue808164-py3k.patch
  • 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 = None
    closed_at = <Date 2010-08-31.21:21:22.596>
    created_at = <Date 2003-09-17.21:16:55.000>
    labels = ['extension-modules', 'type-bug']
    title = "socket.close() doesn't play well with __del__"
    updated_at = <Date 2010-08-31.21:21:22.592>
    user = 'https://bugs.python.org/perrygreenfield'

    bugs.python.org fields:

    activity = <Date 2010-08-31.21:21:22.592>
    actor = 'stutzbach'
    assignee = 'stutzbach'
    closed = True
    closed_date = <Date 2010-08-31.21:21:22.596>
    closer = 'stutzbach'
    components = ['Extension Modules']
    creation = <Date 2003-09-17.21:16:55.000>
    creator = 'perrygreenfield'
    dependencies = []
    files = ['18570', '18571']
    hgrepos = []
    issue_num = 808164
    keywords = ['patch']
    message_count = 13.0
    messages = ['60385', '60386', '82029', '84883', '87961', '104383', '104385', '104421', '104541', '114272', '114281', '114282', '115277']
    nosy_count = 7.0
    nosy_names = ['jbrouwers', 'perrygreenfield', 'pitrou', 'ajaksu2', 'stutzbach', 'isterika', 'BreamoreBoy']
    pr_nums = []
    priority = 'normal'
    resolution = 'accepted'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue808164'
    versions = ['Python 2.7', 'Python 3.2']

    Activity

    1. perrygreenfield commented on Sep 17, 2003

      perrygreenfieldmannequin
      MannequinAuthor

      It appears that 2.3 changed how socket.close() works.
      We now find errors when terminating Python when we
      reference socket.close() in a __del__ method. We have
      worked around it by removing calls to socket.close() but
      note the following differences between the same section
      of code between 2.2 and 2.3 which suggest that the 2.3
      behavior is not ideal and should be fixed.

      In Python 2.3:

          def close(self):
              self._sock = _closedsocket()
              self.send = self.recv = self.sendto = self.recvfrom \
                              = self._sock._dummy

      In Python 2.2:

          def close(self):
              # Avoid referencing globals here
              self._sock = self.__class__._closedsocket()

      Note the reference to avoiding globals which is
      presumably the source of the problem with 2.3. Perhaps
      I'm naive but I would guess that calling a close method
      should be considered a safe operation for use in a
      __del__ method.

    2. added
      stdlibStandard Library Python modules in the Lib/ directory
      on Sep 17, 2003
    3. jbrouwers commented on Feb 25, 2004

      jbrouwersmannequin
      Mannequin

      Logged In: YES
      user_id=832557

      Two other comments on socket.close() in Python 2.3.

      In addition, the socket.close() method in the Lib/socket.py
      class does not even call the _realsocket.close() method.

      Before zapping the _sock attribute, shouldn't the latter
      close() method be called first? If not, what happens to
      any data which may be buffered by the _realsocket?

      Also, every time the socket.close() method is called
      another, new instance of the _closedsocket class is
      created. That seems unnecessary waste.

      Why not use a single instance created once at the
      module level?

    4. added
      type-bugAn unexpected behavior, bug, or error
      and removed
      stdlibStandard Library Python modules in the Lib/ directory
      on Jan 20, 2008
    5. devdanzin commented on Feb 14, 2009

      devdanzinmannequin
      Mannequin

      Current code is:

          def close(self):
              self._sock = _closedsocket()
              dummy = self._sock._dummy
              for method in _delegate_methods:
                  setattr(self, method, dummy)
          close.__doc__ = _realsocket.close.__doc__

      It sure seems to be trying to avoid __del__ issues, does it fix this bug?

    6. stutzbach commented on Mar 31, 2009

      stutzbachmannequin
      Mannequin

      Daniel,

      _closedsocket is a global, so it isn't safe to be used within __del__
      during shutdown.

      In the py3k branch, socket.__del__ calls socket._real_close which
      references the global _socket. So it's not safe their, either.

    7. isterika commented on May 17, 2009

      isterikamannequin
      Mannequin

      The same is happened when you are trying to close pycurl handler at
      __del__ method.

    8. pitrou commented on Apr 27, 2010

      @pitrou
      Member

      Well, realistically, if you have open sockets at shutdown, there isn't a big difference between closing and not closing them. They will be reaped with the process anyway.

    9. stutzbach commented on Apr 28, 2010

      stutzbachmannequin
      Mannequin

      The purpose of calling .close() in __del__ is to close the socket when the owner is destroyed yet the program is still running.

      This prevents the socket from staying open if some other part of the program has somehow acquired a reference to it. telnetlib, urllib, and even the socket module itself contain classes that call .close() within __del__ for this purpose.

      Unfortunately, that can result in ugly error messages when the interpreter is exiting.

    10. pitrou commented on Apr 28, 2010

      @pitrou
      Member

      Unfortunately, that can result in ugly error messages when the
      interpreter is exiting.

      The classical solution is to early bind the necessary globals to
      argument defaults, such as:

          def __del__(self, _socketclose=_socketclose):
              _socketclose(self._socket)
    11. stutzbach commented on Apr 29, 2010

      stutzbachmannequin
      Mannequin

      How do I write a unit test to check that socket.__del__ doesn't refer to any globals?

    12. BreamoreBoy commented on Aug 18, 2010

      BreamoreBoymannequin
      Mannequin

      Can someone reply to Daniel Stutzbach's query in msg104541, thanks.

    13. stutzbach commented on Aug 18, 2010

      stutzbachmannequin
      Mannequin

      I suspect that it's not possible.

      I'm uploading patches that fix the .close method to avoid referencing globals that might be None during interpreter shutdown. Since the .close method has changed significantly in py3k, I'm uploading separate patches for py3k and 2.7.

    14. stutzbach commented on Aug 18, 2010

      stutzbachmannequin
      Mannequin

      Here is the py3k version of the patch

    15. stutzbach commented on Aug 31, 2010

      stutzbachmannequin
      Mannequin

      Fixed in r84380 and r84382.

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

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      extension-modulesC modules in the Modules dirtype-bugAn unexpected behavior, bug, or error

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions