Skip to content

Prevent dual-mode accept tests from hanging - #133457

Merged
wfurt merged 1 commit into
dotnet:mainfrom
wfurt:fix-dualmode-accept-test-hang
Sep 28, 2026
Merged

wfurt merged 1 commit into
dotnet:mainfrom
wfurt:fix-dualmode-accept-test-hang

Conversation

@wfurt

@wfurt wfurt commented Sep 8, 2026

Copy link
Copy Markdown
Member

The negative dual-mode accept tests start an accept operation and then expect a mismatched-address-family connection to fail immediately. On macOS, DualModeAcceptSync.AcceptV6BoundToAnyV4_CantConnect can instead leave both operations pending indefinitely: the worker remains blocked in native accept, while the connect never completes.

This is the same class of problem historically discussed in #16265. These tests were later re-enabled as part of #1481 / #80715, but the shared negative helper still has unbounded operations.

This change:

  • extends PortBlocker to accept an explicit shadow address, since the socket address family does not identify the bound endpoint family for dual-mode sockets;
  • bounds the expected failed connection with the existing TryConnect helper;
  • queues a valid same-family connection before invoking the accept implementation, so synchronous accept completes normally rather than relying on socket disposal for cancellation; and
  • verifies that accept returned the valid client, normalizing IPv4 and IPv4-mapped IPv6 addresses.

The change is test-only and covers the shared Sync, APM, EAP, and Task implementations.

Validation:

System.Net.Sockets.Tests  Total: 32, Errors: 0, Failed: 0, Skipped: 0

A full libraries baseline was not run; the focused System.Net.Sockets test project built successfully while running the affected classes.

Note

This pull request description was generated with GitHub Copilot.

Bound failed connection attempts, reserve the tested address-family port, and queue a valid connection before invoking accept so synchronous test variants cannot remain blocked.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 4 pipeline(s).
12 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @karelz, @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 4 pipeline(s).
12 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Dispose both sockets when bind retries fail to avoid resource leaks.

Pull request overview

Hardens dual-mode socket accept tests against platform-specific hangs by bounding failed connections and validating successful same-family accepts.

Changes:

  • Adds explicit shadow-address support to PortBlocker.
  • Bounds mismatched-family connection attempts.
  • Verifies accepted endpoints across Sync, APM, EAP, and Task implementations.
File summaries
File Summary
src/libraries/System.Net.Sockets/tests/FunctionalTests/DualModeSocketTest.cs Updates negative accept tests to avoid hangs and validate accepted endpoints.
src/libraries/Common/tests/System/Net/Sockets/SocketTestExtensions.cs Supports explicit shadow addresses in PortBlocker.
Review details

Suppressed comments (1)

src/libraries/Common/tests/System/Net/Sockets/SocketTestExtensions.cs:129

  • When TryBindWithoutReuseAddress returns false (the normal bind-conflict path on both Windows and Unix), this loop retries without disposing either MainSocket or _shadowSocket; the next iteration overwrites both references, and exhausting retries also leaks the final pair. The new explicit shadow-address call relies on these retries, so dispose both sockets before continuing whenever success is false.
                    success = TryBindWithoutReuseAddress(_shadowSocket, shadowEndPoint, out _);
  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Lite

@wfurt
wfurt merged commit bae5a8d into dotnet:main Sep 28, 2026
79 of 83 checks passed
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.

3 participants