Skip to content

socketserver: BaseServer.handle_request() infinite loop #81207

Description

@jmberg
mannequin
BPO 37026
Nosy @jmberg

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 = None
created_at = <Date 2019-05-23.22:06:55.515>
labels = ['3.7', 'type-bug', 'library']
title = 'socketserver: BaseServer.handle_request() infinite loop'
updated_at = <Date 2019-05-23.22:06:55.515>
user = 'https://github.com/jmberg'

bugs.python.org fields:

activity = <Date 2019-05-23.22:06:55.515>
actor = 'jmberg'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Library (Lib)']
creation = <Date 2019-05-23.22:06:55.515>
creator = 'jmberg'
dependencies = []
files = []
hgrepos = []
issue_num = 37026
keywords = []
message_count = 1.0
messages = ['343330']
nosy_count = 1.0
nosy_names = ['jmberg']
pr_nums = []
priority = 'normal'
resolution = None
stage = None
status = 'open'
superseder = None
type = 'behavior'
url = 'https://bugs.python.org/issue37026'
versions = ['Python 3.7']

Linked PRs

Activity

  1. jmberg commented on May 23, 2019

    jmbergmannequin
    MannequinAuthor

    Hi,

    Alright - you may very well consider this to be a stupid idea and everything, but I figured I'd report it anyway, just so it's there even if you decide to ignore it.

    For context, I'm running python in a ARCH=um Linux system that has completely virtual time, using basically this patch:
    https://patchwork.ozlabs.org/patch/1095055/

    Now, as I replied there myself, you would in fact think that this can lead to infinite loops, but not really in a select/poll loop in the socket server, hence this report.

    We have the following code:

        [...]
    
            if timeout is not None:
                deadline = time() + timeout
    
            # Wait until a request arrives or the timeout expires - the loop is
            # necessary to accommodate early wakeups due to EINTR.
            with _ServerSelector() as selector:
                selector.register(self, selectors.EVENT_READ)
    
                while True:
                    ready = selector.select(timeout)
                    if ready:
                        return self._handle_request_noblock()
                    else:
                        if timeout is not None:
                            timeout = deadline - time()
                            if timeout < 0:
                                return self.handle_timeout()

    Assume that a timeout is given, so deadline is set to time() + timeout.

    Now, if selector.select(timeout) returns [] because nothing was ready for reading, you'd expect us to treat this as a timeout, right?

    However, in my case of virtual time with infinite processing power, it doesn't.

    Let's say that timeout is 1 (second) and that the call to time() returned 10000 (clearly not realistic, but doesn't matter). Now, in a virtual time implementation with infinite processing power, select(timeout) will sleep for *exactly* 1 second, and return nothing is ready. Then, in the else: branch, we set "timeout = deadline - time()" - but now time will return 10001 (remember we slept for exactly 1 second), and timeout will be 0. We will thus not handle a timeout, instead, we'll go into select() again with a timeout of 0. Due to the "infinite processing power" aspect of this system, this will happen over and over again.

    The trivial fix here is to handle it as a timeout "if timeout <= 0" rather than just "if timeout < 0".

    Obviously, I can also fix my virtual time system, for example, I can give it less processing power by actually interrupting the process after some real time (which I implemented in https://patchwork.ozlabs.org/patch/1095814/).

    An alternative is to make every "what time is it now" request actually take some virtual time, thus the time() calls cannot return the same value over and over again. This also fixes the issue I saw.

    But it stands to reason that if it should happen that the new timeout is actually 0, we should really treat it as a timeout here in this code and make it <=0 rather than just <0.

  2. added
    stdlibStandard Library Python modules in the Lib/ directory
    type-bugAn unexpected behavior, bug, or error
    on May 23, 2019
  3. transferred this issue fromon Apr 10, 2022
  4. iritkatriel commented on Feb 18, 2023

    @iritkatriel
    Member

    I don't understand what the bug report is, or what you are suggesting should change in python.

  5. added
    pendingThe issue will be closed if no feedback is provided
    on Feb 18, 2023
  6. iritkatriel commented on Mar 1, 2023

    @iritkatriel
    Member

    Oh, I see - that code snippet is from the stdlib, it's not your code. I understand now.

  7. added
    type-featureA feature request or enhancement
    and removed
    type-bugAn unexpected behavior, bug, or error
    on Mar 1, 2023
  8. removed
    pendingThe issue will be closed if no feedback is provided
    on May 3, 2023
  9. added
    topic-socketRelated to the socket, socketserver and selectors modules
    type-bugAn unexpected behavior, bug, or error
    and removed
    type-featureA feature request or enhancement
    on Jul 3, 2026
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

    stdlibStandard Library Python modules in the Lib/ directorytopic-socketRelated to the socket, socketserver and selectors modulestype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions