Skip to content

Conversation

@julianz-
Copy link
Contributor

@julianz- julianz- commented Oct 5, 2025

Fixed race conditions to make socket I/O more resilient during connection teardown.

  1. BufferedWriter's write(): Added error handling to ignore common socket errors (e.g., ECONNRESET, EPIPE, ENOTCONN, EBADF) that occur when the underlying connection has been unexpectedly closed by the client or OS. This prevents a crash when attempting to write to a defunct socket.
  2. BufferedWriters's close(): Made idempotent, allowing safe repeated calls without raising exceptions.
  3. Needed to add explicit handling of WINDOWS environments as these are seen to throw Windows specific WSAENOTSOCK errors.

Includes new unit tests to cover the idempotency and graceful handling of already closed underlying buffers.


This change is Reviewable

@julianz- julianz- closed this Oct 5, 2025
@julianz- julianz- reopened this Oct 5, 2025
@julianz- julianz- changed the title Fix race condition and improve robustness during socket I/O [DRAFT] Fix race condition and improve robustness during socket I/O Oct 5, 2025
@julianz- julianz- force-pushed the fix-socket-teardown branch 2 times, most recently from 887399d to 4f1662e Compare October 5, 2025 19:04
@codecov
Copy link

codecov bot commented Oct 5, 2025

Codecov Report

❌ Patch coverage is 86.56716% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.33%. Comparing base (4a8dc43) to head (342ecf6).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #779      +/-   ##
==========================================
+ Coverage   79.30%   79.33%   +0.03%     
==========================================
  Files          29       29              
  Lines        4203     4269      +66     
  Branches      539      543       +4     
==========================================
+ Hits         3333     3387      +54     
- Misses        728      735       +7     
- Partials      142      147       +5     

@julianz- julianz- force-pushed the fix-socket-teardown branch from 4f1662e to 4833dac Compare October 5, 2025 19:09
@julianz- julianz- marked this pull request as draft October 5, 2025 19:09
@julianz- julianz- changed the title [DRAFT] Fix race condition and improve robustness during socket I/O Fix race condition and improve robustness during socket I/O Oct 5, 2025
@julianz- julianz- changed the title Fix race condition and improve robustness during socket I/O Fix race conditions and improve robustness during socket I/O Oct 5, 2025
@julianz- julianz- marked this pull request as ready for review October 5, 2025 19:26
@julianz- julianz- force-pushed the fix-socket-teardown branch 2 times, most recently from 048d898 to f0471ca Compare October 7, 2025 03:27
@webknjaz
Copy link
Member

@julianz- could you scan the modules more broadly for places where we could stop suppressing connection errors on the low level layers? I'm not looking into the tests until we figure out the architectural overview of the whole thing. But I feel like we're getting closer. I think we might need to split this PR into two at some point, will see.

@julianz-
Copy link
Contributor Author

Thank you @webknjaz for all your great suggestions and points. I will take a look at everything. The layering is actually more complicated than I had realized.

@julianz- julianz- force-pushed the fix-socket-teardown branch 3 times, most recently from b26544f to f7d8469 Compare October 22, 2025 04:34
@webknjaz
Copy link
Member

The layering is actually more complicated than I had realized.

Yep, that's why I have incomplete pieces of code somewhere locally that I never finalized. It does require some effort..

@julianz- julianz- force-pushed the fix-socket-teardown branch from f7d8469 to b0587dd Compare October 31, 2025 05:28
Copy link
Member

Choose a reason for hiding this comment

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

I think the current state of this module is good but Codecov shows that none of the newly added lines are covered with tests. We'll have to fix this before merging.

It looks like the updates to cheroot.ssl.pyopenssl could go into a standalone pull request. Could you extract this and add tests+changenote in a separate PR? I hope this will simplify reviewing this one.

errno.EPIPE,
errno.ESHUTDOWN, # corresponds to BrokenPipeError in Python 3
errno.ECONNRESET, # corresponds to ConnectionResetError in Python 3
*((errno.WSAENOTSOCK,) if _compat.IS_WINDOWS else ()),
Copy link
Member

Choose a reason for hiding this comment

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

Does this exception correspond to EBADF semantically? If so, I'd probably keep them close to each other as suggested in https://github.com/cherrypy/cheroot/pull/779/files#r2432797948.

Additionally, could you add a comment hinting what might be causing it in practice?

'sendall',
'settimeout',
'gettimeout',
'shutdown',
Copy link
Member

Choose a reason for hiding this comment

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

Will this interferre with the newly added decorator/methods? proxy_wrapper() below does effectively what we did with @_morph_syscall_to_connection_error and so shutdown() will end up double-decorated/locked if I'm reading this correctly.

'accept',
'setblocking',
'fileno',
'close',
Copy link
Member

Choose a reason for hiding this comment

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

Will this interferre with the newly added decorator/methods? proxy_wrapper() below does effectively what we did with @_morph_syscall_to_connection_error and so shutdown() will end up double-decorated/locked if I'm reading this correctly.

@julianz- julianz- force-pushed the fix-socket-teardown branch from b0587dd to 97cad94 Compare November 1, 2025 03:51
Fixes to make socket I/O more resilient during connection teardown.

1. BufferedWriter's write(): Added error handling to ignore common
   socket errors (e.g., ECONNRESET, EPIPE, ENOTCONN, EBADF) that occur
   when the underlying connection has been unexpectedly closed by the
   client or OS. This prevents a crash when attempting to write to a
   defunct socket.
2. BufferedWriters's close(): Made idempotent, allowing safe repeated
   calls without raising exceptions.
3. Needed to add explicit handling of WINDOWS environments as these are
   seen to throw Windows specific WSAENOTSOCK errors.

Includes new unit tests to cover the idempotency and graceful handling
of already closed underlying buffers.
@julianz- julianz- force-pushed the fix-socket-teardown branch from 97cad94 to 342ecf6 Compare November 1, 2025 03:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants