Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OverflowError with asyncio.sleep #259

Closed
Edward-Knight opened this issue Jul 22, 2019 · 2 comments
Closed

OverflowError with asyncio.sleep #259

Edward-Knight opened this issue Jul 22, 2019 · 2 comments

Comments

@Edward-Knight
Copy link

  • uvloop version: 0.12.2
  • Python version: 3.7.3
  • Platform: darwin (OSX)
  • Can you reproduce the bug with PYTHONASYNCIODEBUG in env?: yes

This issue is related to #102 ("Should float("inf") for timeout raise an Overflow error?")

uvloop throws an OverflowError if you pass asyncio.sleep a large enough delay.
Thanks to #102, uvloop handles the float("inf") case, but other large numbers (like sys.maxsize) still cause an exception to be thrown.

uvloop/uvloop/loop.pyx

Lines 1287 to 1294 in 88608b8

if delay < 0:
delay = 0
elif delay == py_inf:
# ~100 years sounds like a good approximation of
# infinity for a Python application.
delay = 3600 * 24 * 365 * 100
when = <uint64_t>round(delay * 1000)

Perhaps if round(delay * 1000) is greater than 2^64 − 1, it should be reduced to be equal to that, to avoid OverflowErrors from occurring.

Here is some code to reproduce the error:

import asyncio
import uvloop
import sys


async def sleep(delay_name, delay):
    log_msg = f"Sleep {delay_name} {type(delay).__name__} {delay}"
    try:
        await asyncio.sleep(delay)
    except asyncio.CancelledError:
        print(f"{log_msg}: OK")
    except Exception as e:
        print(f"{log_msg}: {e.__class__.__name__}: {e}")


async def main():
    tests = [
        sleep("infinity", float("inf")),
        sleep("sys.maxsize", float(sys.maxsize)),
        sleep("sys.maxsize", sys.maxsize),
        sleep("2**55", 2**55),
        sleep("2**54", 2**54),
    ]
    tasks = [asyncio.create_task(test) for test in tests]
    await asyncio.sleep(1)
    for task in tasks:
        task.cancel()
        await task


if __name__ == "__main__":
    uvloop.install()
    asyncio.run(main())

It produces the output:

Sleep sys.maxsize float 9.223372036854776e+18: OverflowError: Python int too large to convert to C unsigned long
Sleep sys.maxsize int 9223372036854775807: OverflowError: Python int too large to convert to C unsigned long
Sleep 2**55 int 36028797018963968: OverflowError: Python int too large to convert to C unsigned long
Sleep infinity float inf: OK
Sleep 2**54 int 18014398509481984: OK
@1st1
Copy link
Member

1st1 commented Jul 30, 2019

Perhaps if round(delay * 1000) is greater than 2^64 − 1, it should be reduced to be equal to that, to avoid OverflowErrors from occurring.

Yeah, makes sense. Care to make a PR?

@1st1
Copy link
Member

1st1 commented Oct 25, 2019

I've just published https://github.com/MagicStack/uvloop/releases/tag/v0.14.0rc1. Please test. The final release will be published some time next week if RC1 is OK.

@1st1 1st1 closed this as completed Oct 25, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants