Skip to content

Conversation

@gvanrossum
Copy link
Member

@gvanrossumgvanrossum commented Jan 11, 2023

@gvanrossum
Copy link
MemberAuthor

@kumaraditya303 Any chance you have time to review this? And maybe @eryksun too?

The only possibly controversial thing is that I added self.call_soon(loop_accept_pipe) to the OSError except clause as well, so that other OS errors don't do the same thing and disable the server.

Comment on lines 270 to 271
asyncdefstat_it():
os.stat(ADDRESS)
Copy link
Contributor

@eryksuneryksunJan 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case the implementation of os.stat() changes, what basically needs to be tested is whether a pipe connection that's closed immediately causes the server to die, such as os.close(os.open(ADDRESS, os.O_RDONLY)).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried it and it does not reproduces the error. Note that I am using Windows 11.

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I found the same problem. I also had to add two await asyncio.sleep(0) calls after server.close() to make the final close(open()) call fail as expected.

So I think I'd rather merge this as is, using os.stat().

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All that os.stat() is doing that's even remotely relevant here is calling h = CreateFileW(ADDRESS, ...), doing a bit of work that takes a little time, and then calling CloseHandle(h).

os.stat() won't be relevant to the error at all if Microsoft provides a better way to implement os.stat() that doesn't require opening a handle to the pipe, or if we decide that we should just inspect a "\\.\PIPE\" path as a string in os.stat() instead of opening a handle.

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then how would you fix the test? os.close(os.open()) doesn’t fail without the fix.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe os.open() actually isn't fast enough to trigger the race condition reliably. Try _winapi.CloseHandle(_overlapped.ConnectPipe(ADDRESS)).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot that os.stat() also calls GetFileAttributesW() on the pipe while the handle is open. This tries to open a second pipe connection before the first one has been closed. The following reproduces the scenario:

h=_overlapped.ConnectPipe(ADDRESS) try: _winapi.CloseHandle(_overlapped.ConnectPipe(ADDRESS)) exceptOSErrorase: ife.winerror!=_overlapped.ERROR_PIPE_BUSY: raisefinally: _winapi.CloseHandle(h)

In the test, 2/5 attempts at opening a second pipe connection fail with ERROR_PIPE_BUSY, so this error is intentionally ignored.

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we don’t need a test. All this is irrelevant for the fix. I can either delete the test, keep the PR as is, or close it unresolved. (Someone else can try again.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code in my last comment reliably triggers the problem for me because it ensures that the client connects and disconnects from the server's next pipe instance, leaving the pipe in a broken state before the server calls ConnectNamedPipe().

If it comes to closing the PR or deleting the test, I vote for deleting the test. It should have been designed from the beginning to handle the broken pipe error. Not every aspect of a correct design has to be tested.

server.close()

withself.assertRaises(FileNotFoundError):
os.stat(ADDRESS)
Copy link
Contributor

@eryksuneryksunJan 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly here, os.close(os.open(ADDRESS, os.O_RDONLY)) will raise FileNotFoundError after the server has closed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For that we need to wait for closing the server so asyncio.sleep(0) is required.

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't look like that's needed with the latest probe code.

@kumaraditya303kumaraditya303 added type-bug An unexpected behavior, bug, or error topic-asyncio needs backport to 3.10 only security fixes needs backport to 3.11 only security fixes labels Jan 12, 2023
Copy link
Contributor

@kumaraditya303kumaraditya303 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@gvanrossum
Copy link
MemberAuthor

Please re-review, I've added Eryk's code. I've confirmed that it reproduces the bug and refactored the test so the probe code only needs to be written once.

@gvanrossumgvanrossum merged commit 1bc7a73 into python:mainJan 13, 2023
@miss-islington
Copy link
Contributor

Thanks @gvanrossum for the PR 🌮🎉.. I'm working now to backport this PR to: 3.10, 3.11.
🐍🍒⛏🤖

@gvanrossumgvanrossum deleted the asyncio-winpipe branch January 13, 2023 21:25
@bedevere-bot
Copy link

GH-101019 is a backport of this pull request to the 3.11 branch.

@bedevere-botbedevere-bot removed the needs backport to 3.11 only security fixes label Jan 13, 2023
@bedevere-bot
Copy link

GH-101020 is a backport of this pull request to the 3.10 branch.

@bedevere-botbedevere-bot removed the needs backport to 3.10 only security fixes label Jan 13, 2023
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Jan 13, 2023
…indows) (pythonGH-100959) (cherry picked from commit 1bc7a73) Co-authored-by: Guido van Rossum <guido@python.org>
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Jan 13, 2023
…indows) (pythonGH-100959) (cherry picked from commit 1bc7a73) Co-authored-by: Guido van Rossum <guido@python.org>
gvanrossum pushed a commit that referenced this pull request Jan 13, 2023
gvanrossum pushed a commit that referenced this pull request Jan 13, 2023
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

topic-asynciotype-bugAn unexpected behavior, bug, or error

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@gvanrossum@miss-islington@bedevere-bot@eryksun@kumaraditya303