New submission from jmberg <johan...@sipsolutions.net>:

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.

----------
components: Library (Lib)
messages: 343330
nosy: jmberg
priority: normal
severity: normal
status: open
title: socketserver: BaseServer.handle_request() infinite loop
type: behavior
versions: Python 3.7

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue37026>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to