This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: time.sleep ignores errors on Windows
Type: behavior Stage: needs patch
Components: Windows Versions: Python 3.10, Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: tim.golden Nosy List: eryksun, paul.moore, steve.dower, tim.golden, zach.ware
Priority: normal Keywords:

Created on 2020-06-08 18:40 by steve.dower, last changed 2022-04-11 14:59 by admin.

Messages (8)
msg371037 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2020-06-08 18:40
In time.sleep on Windows, if the WaitForSingleObject call fails, the call returns success. It essentially looks like the timeout was 0.

Errors should be highly unlikely, as the event object is leaked (see issue40912), but if they _do_ occur, we should raise them.
msg371225 - (view) Author: Tim Golden (tim.golden) * (Python committer) Date: 2020-06-10 17:03
Thinking about testing here.. is there any straightforward way to cause WaitForSingleObjectEx to fail?

The code change would be fairly slight and amenable to inspection, but it would be good to actually test it ;)
msg371235 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2020-06-10 19:36
> is there any straightforward way to cause WaitForSingleObjectEx to fail?

The wait can fail for ERROR_INVALID_HANDLE or ERROR_ACCESS_DENIED (i.e. the handle lacks SYNCHRONIZE access). If _PyOS_SigintEvent were replaced with get/set functions, then a non-waitable handle could be set temporarily via ctypes.
msg371333 - (view) Author: Tim Golden (tim.golden) * (Python committer) Date: 2020-06-12 05:41
Thanks, Eryk. I've had a couple of casts at this (and also with an eye to https://bugs.python.org/issue40912 in a very similar area).

Trouble is I can't come up with a way of adding a set.. function which doesn't seem wholly artificial, given that it's basically creating an anonymous event and checking its return. I can't come up with a non-testing scenario where the ability to override would be useful.

If I understand your proposal, a tentative "set..." function would have to take a HANDLE parameter so that it could be overridden by a test? That means its normal use would be something like:

setSigintEvent(CreateEvent(NULL, ....));

so either the error checking for that would be inside the function, which feels weird, or would happen outside, which feels like the functions not doing anything. (I appreciate I may be overthinking here).

I'm very much open to suggestions here, but it seems to me that either:

We make the (simple) change without tests;

or we add a setSigintEvent function as above whose only purpose is to be overridden -- and then only for testing.
msg371408 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2020-06-12 18:56
You could test this by getting the event and CloseHandle-ing it. A function to do this could be added to _testcapimodule. It'd have to run in its own process, but we have (a few) helpers around for this.

Given the concerns, I don't think we should change this in any maintenance releases, so I removed 3.7 and 3.8 from the versions list. I'd be equally happy without an explicit test in
msg371409 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2020-06-12 18:57
... equally happy without an explicit test in anything that's only prerelease right now.
msg371413 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2020-06-12 19:50
If WaitForSingleObjectEx fails, do you think the system error code should be raised as an OSError? Probably an invalid-handle or access-denied error is too cryptic here. It may be better to raise something like RuntimeError('time.sleep(): invalid SIGINT event handle'). 

> You could test this by getting the event and CloseHandle-ing it. 

Yes, that's a simpler approach. It should work in a child process that's well controlled. 

I was thinking of a less controlled environment, in which there's a chance that another waitable object will reuse the handle, such as a file object. The test would be reliable regardless of process context (but only in the main thread, of course) if there were a _PyOS_SetSigintEvent function -- or if sigint_event were directly accessible in _testcapimodule. It could just temporarily set a duplicate handle with no access. For example:

    >>> h1 = CreateEvent(None, True, True, None)
    >>> WaitForSingleObject(h1, 0)
    0
    >>> hp = GetCurrentProcess()
    >>> h2 = DuplicateHandle(hp, h1, hp, 0, False, 0)
    >>> WaitForSingleObject(h2, 0)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    pywintypes.error: (5, 'WaitForSingleObject', 'Access is denied.')
msg371420 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2020-06-12 21:08
> If WaitForSingleObjectEx fails, do you think the system error code should be raised as an OSError?

It's invalid (and unfixable) internal state, so perhaps SystemError makes the most sense? There's no point catching it in most cases.

Or since we don't want to worry too much about formatting the message, why not raise the OSError with the helper function and then immediately chain it with a fixed SystemError?
History
Date User Action Args
2022-04-11 14:59:32adminsetgithub: 85090
2020-06-12 21:08:35steve.dowersetmessages: + msg371420
2020-06-12 19:50:09eryksunsetmessages: + msg371413
2020-06-12 18:57:00steve.dowersetmessages: + msg371409
2020-06-12 18:56:42steve.dowersetmessages: + msg371408
versions: - Python 3.7, Python 3.8
2020-06-12 05:42:05tim.goldensetassignee: tim.golden
2020-06-12 05:41:43tim.goldensetmessages: + msg371333
2020-06-10 19:36:50eryksunsetnosy: + eryksun
messages: + msg371235
2020-06-10 17:03:58tim.goldensetmessages: + msg371225
2020-06-08 18:40:16steve.dowercreate