Guard against empty remote address on macOS accept - #131869
Conversation
When a peer connects and immediately resets a socket (SO_LINGER=0), macOS accept() can return successfully with an empty remote sockaddr (addrlen=0). The 2024 fix (dotnet#108616) guarded the Create call inside FinishOperationAccept, but the shared FinishOperationSyncSuccess path calls EndPoint.Create a second time on the same zero-sized address and throws ArgumentException. For Kestrel this crashes the accept loop and stops accepting new connections while leaving the process alive and the port bound. Guard the second Create call with the same Size > 0 check, and swallow SocketException from the diagnostic NetEventSource.Accepted call whose access of RemoteEndPoint can trigger getpeername returning ENOTCONN. Fixes dotnet#121848
|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
Tagging subscribers to this area: @karelz, @dotnet/ncl |
There was a problem hiding this comment.
Pull request overview
This PR addresses an accept-path robustness issue where an empty remote sockaddr can lead to EndPoint.Create(SocketAddress) throwing during accept completion, potentially breaking server accept loops on macOS. It adds a guard in SocketAsyncEventArgs.FinishOperationSyncSuccess and introduces a functional regression test covering the dual-stack + immediate RST scenario.
Changes:
- Guard
EndPoint.CreateinSocketAsyncEventArgs.FinishOperationSyncSuccesswhen the remoteSocketAddressis empty. - Harden NetEventSource accept logging against remote endpoint lookup failures.
- Add a new functional test (
AcceptDualStackResetTests) to exercise the reset-after-connect accept scenario on a dual-stack listener.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs | Avoids calling EndPoint.Create on zero-sized SocketAddress during accept completion; adjusts accept logging behavior. |
| src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs | Adds a regression test that repeatedly connects/resets against a dual-stack IPv6 listener and verifies the listener remains able to accept new connections. |
|
Confirming this fixes it on 10.0. I applied the patch to the v10.0.10 tag, where the line it changes is identical, and rebuilt System.Net.Sockets. Before, our repro killed the listener on the first iteration, both on a raw dual-stack accept loop and on Kestrel with a wildcard URL. After, 200 iterations clean and still serving. macOS 26.5, arm64. Any chance of a backport to release/10.0? |
|
thanks @akirayamamoto for the confirmation. backport is my goal but we need approval and your verification is useful. |
Addresses Copilot review feedback: passing the local remoteEndPoint variable to NetEventSource.Accepted avoids the extra getpeername syscall and removes the need for the broad SocketException catch.
Marks the test as skipped rather than silently passing on hosts without IPv6 support, matching the [ConditionalFact(typeof(Socket), nameof(Socket.OSSupportsUnixDomainSockets))] pattern used elsewhere in this test project.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (1)
src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs:508
- The regression being exercised is macOS-specific (per the comment), but this test currently runs on all platforms. That increases runtime/flake risk without adding coverage elsewhere. Prefer gating it to macOS with standard test attributes, and use ConditionalFact rather than an early return so the test is reported as skipped when prerequisites aren’t met.
[ConditionalFact(typeof(Socket), nameof(Socket.OSSupportsIPv6))]
public async Task AcceptAsync_DualStackListener_PeerImmediatelyResets_ListenerStaysHealthy()
{
using Socket listener = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
listener.DualMode = true;
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (1)
src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs:505
- This test targets a macOS-specific accept(2) behavior (empty remote sockaddr on immediate RST), but it will currently run on any platform that supports IPv6. That adds significant extra work to all CI legs and risks platform-specific differences in SO_LINGER/RST semantics causing flakiness. Consider restricting the test to macOS (the affected platform).
[ConditionalFact(typeof(Socket), nameof(Socket.OSSupportsIPv6))]
public async Task AcceptAsync_DualStackListener_PeerImmediatelyResets_ListenerStaysHealthy()
There was a problem hiding this comment.
🟡 Changes recommended
The new functional test can often accept the healthy connection first and exit early, which may fail to reliably exercise the reset/empty-sockaddr regression scenario as written.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 1
- Review effort level: Lite
Connect and reset the IPv4 peer before establishing the healthy IPv6 connection so the regression path is exercised more reliably. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟢 Approval recommended
The changes are narrowly scoped, align with existing accept-socket initialization behavior (supporting remoteEP == null), and add a targeted regression test.
Review details
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs:505
- The hard-coded iteration count
200is a magic number in a stress-style regression test. Giving it a named constant makes it clearer that the repetition is intentional (and makes it easier to adjust later without hunting through the loop body).
- Files reviewed: 3/3 changed files
- Comments generated: 0 new
- Review effort level: Lite
|
/backport to release/10.0 Note This backport command was posted with assistance from GitHub Copilot. |
|
/backport to release/11.0 Note This backport command was posted with assistance from GitHub Copilot. |
|
Started backporting to |
|
Started backporting to |
…indows/Linux (refs #133778) (#133925) Workflow artifact: ci-fix Artifact kind: help Linked KBE: #133778 > [!NOTE] > This is an AI/Copilot-generated **best-effort** fix attempt that I could not fully validate. It is a starting point for a maintainer, not a finished change. Please review the analysis below before merging. ## Root cause (best analysis) `System.Net.Sockets.Tests.AcceptDualStackResetTests.Accept_DualStackListener_PeerImmediatelyResets_ListenerStaysHealthy(useAsync: True)` fails on `windows-x64`/`linux-x64` (`TestReadyToRun_Libraries` and the runtime pipeline): ``` System.Net.Sockets.SocketException : An existing connection was forcibly closed by the remote host. at System.Net.Sockets.Tests.AcceptDualStackResetTests.Accept_DualStackListener_PeerImmediatelyResets_ListenerStaysHealthy(Boolean useAsync) in /_/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs:line 527 ``` Line 527 is the `AcceptAsync`/`Accept` call, **not** the receive. The test (added by #131869) closes an IPv4 peer with `SO_LINGER=0` so the kernel sends an immediate RST, then expects the listener to still deliver the healthy IPv6 peer's byte. The `try { ... } catch (SocketException)` block only wraps the `ReceiveAsync`; the `accept` that precedes it sits **outside** the `try`. On Windows and Linux the reset is surfaced by `accept` itself (`WSAECONNRESET` / "connection forcibly closed"), which escapes the catch and fails the test, even though the very next accept iteration would return the healthy peer. macOS discards the reset at accept (which #131869 hardened `EndPoint.Create` for), so it doesn't hit this path — which is why the test passed there but not on Windows/Linux. The test comment already anticipates this ("Some platforms surface the reset connection from accept()"), but the code doesn't guard the accept accordingly. ## Attempted fix Move the `accept` inside the existing `try` block so a `SocketException` from either the accept or the following receive is tolerated, and the loop retries to accept the healthy peer on the next iteration (the loop already runs up to 2 accepts). No production code changes; the listener-stays-healthy assertion is preserved. This is **not** a test-disable — the test still runs and still asserts the healthy peer's message is received. ## What is unverified / where I need help - I could not build and run `System.Net.Sockets.Tests` in this environment, so I have not confirmed the test now passes on windows-x64/linux-x64 while still catching a genuine listener regression. - Please confirm the intended contract: on Windows/Linux, should the RST be observable at `accept` (making tolerating it here correct), or should the runtime itself suppress the reset connection from the accept loop the way macOS does? If the latter, the real fix belongs in the socket accept path rather than the test. ## Validation - Command: `not run because the sockets functional test suite could not be built/executed within the run budget` - Result: not run ## Evidence - Failing build: https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1593787 - First build it occurred: after #131869 (merged 2026-09-09, commit 7c35b7d), which introduced this test (computed within the scanned window; may not be the true origin) - Suspected regressing change: #131869 (added the test with the accept outside the catch) ## Help wanted - Likely author: `@wfurt` (authored #131869 that added the test) - Area owners (`area-System.Net.Sockets`): `@dotnet/ncl` --- Filed by [`ci-failure-fix`](https://github.com/dotnet/runtime/blob/main/.github/workflows/ci-failure-fix.md). Comment here or on the workflow file to suggest changes; [`ci-failure-scan-feedback`](https://github.com/dotnet/runtime/blob/main/.github/workflows/ci-failure-scan-feedback.md) reads in-scope feedback daily and opens (or updates) a PR with prompt edits. Structured data: ```json { "artifact_kind": "help", "linked_kbe": 133778, "workflow_artifact": "ci-fix" } ``` > Generated by [CI Outer-Loop Failure Fixer](https://github.com/dotnet/runtime/actions/runs/34916254170) · opus48 · 764.8 AIC · ⌖ 20.8 AIC · ⊞ 19.6K · [◷](https://github.com/search?q=repo%3Adotnet%2Fruntime+%22gh-aw-workflow-id%3A+ci-failure-fix%22&type=pullrequests) <!-- gh-aw-agentic-workflow: CI Outer-Loop Failure Fixer, engine: copilot, model: claude-opus-4.8, id: 34916254170, workflow_id: ci-failure-fix, run: https://github.com/dotnet/runtime/actions/runs/34916254170 --> <!-- gh-aw-workflow-id: ci-failure-fix --> <!-- gh-aw-workflow-call-id: dotnet/runtime/ci-failure-fix --> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixes #121848 ## Problem On macOS, when a peer connects to an `AF_INET6` listening socket and immediately resets the connection (`SO_LINGER=0`), `accept(2)` returns a valid file descriptor but leaves the remote sockaddr buffer untouched and reports `addrlen=0`. This kernel behavior was measured with a plain C repro in the [issue comment](#121848 (comment)) and does not depend on dual-mode or `IPV6_V6ONLY`. The 2024 fix (#108616) guarded the `EndPoint.Create` call inside `FinishOperationAccept` on the Unix path, but the shared `FinishOperationSyncSuccess` in [`SocketAsyncEventArgs.cs`](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs#L1016) calls `Create` a second time on the same zero-sized `SocketAddress` and throws `ArgumentException`. For Kestrel this kills the accept loop permanently while the process stays alive and the port stays bound. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…indows/Linux (refs #133778) (#133925) Workflow artifact: ci-fix Artifact kind: help Linked KBE: #133778 > [!NOTE] > This is an AI/Copilot-generated **best-effort** fix attempt that I could not fully validate. It is a starting point for a maintainer, not a finished change. Please review the analysis below before merging. ## Root cause (best analysis) `System.Net.Sockets.Tests.AcceptDualStackResetTests.Accept_DualStackListener_PeerImmediatelyResets_ListenerStaysHealthy(useAsync: True)` fails on `windows-x64`/`linux-x64` (`TestReadyToRun_Libraries` and the runtime pipeline): ``` System.Net.Sockets.SocketException : An existing connection was forcibly closed by the remote host. at System.Net.Sockets.Tests.AcceptDualStackResetTests.Accept_DualStackListener_PeerImmediatelyResets_ListenerStaysHealthy(Boolean useAsync) in /_/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs:line 527 ``` Line 527 is the `AcceptAsync`/`Accept` call, **not** the receive. The test (added by #131869) closes an IPv4 peer with `SO_LINGER=0` so the kernel sends an immediate RST, then expects the listener to still deliver the healthy IPv6 peer's byte. The `try { ... } catch (SocketException)` block only wraps the `ReceiveAsync`; the `accept` that precedes it sits **outside** the `try`. On Windows and Linux the reset is surfaced by `accept` itself (`WSAECONNRESET` / "connection forcibly closed"), which escapes the catch and fails the test, even though the very next accept iteration would return the healthy peer. macOS discards the reset at accept (which #131869 hardened `EndPoint.Create` for), so it doesn't hit this path — which is why the test passed there but not on Windows/Linux. The test comment already anticipates this ("Some platforms surface the reset connection from accept()"), but the code doesn't guard the accept accordingly. ## Attempted fix Move the `accept` inside the existing `try` block so a `SocketException` from either the accept or the following receive is tolerated, and the loop retries to accept the healthy peer on the next iteration (the loop already runs up to 2 accepts). No production code changes; the listener-stays-healthy assertion is preserved. This is **not** a test-disable — the test still runs and still asserts the healthy peer's message is received. ## What is unverified / where I need help - I could not build and run `System.Net.Sockets.Tests` in this environment, so I have not confirmed the test now passes on windows-x64/linux-x64 while still catching a genuine listener regression. - Please confirm the intended contract: on Windows/Linux, should the RST be observable at `accept` (making tolerating it here correct), or should the runtime itself suppress the reset connection from the accept loop the way macOS does? If the latter, the real fix belongs in the socket accept path rather than the test. ## Validation - Command: `not run because the sockets functional test suite could not be built/executed within the run budget` - Result: not run ## Evidence - Failing build: https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1593787 - First build it occurred: after #131869 (merged 2026-09-09, commit 7c35b7d), which introduced this test (computed within the scanned window; may not be the true origin) - Suspected regressing change: #131869 (added the test with the accept outside the catch) ## Help wanted - Likely author: `@wfurt` (authored #131869 that added the test) - Area owners (`area-System.Net.Sockets`): `@dotnet/ncl` --- Filed by [`ci-failure-fix`](https://github.com/dotnet/runtime/blob/main/.github/workflows/ci-failure-fix.md). Comment here or on the workflow file to suggest changes; [`ci-failure-scan-feedback`](https://github.com/dotnet/runtime/blob/main/.github/workflows/ci-failure-scan-feedback.md) reads in-scope feedback daily and opens (or updates) a PR with prompt edits. Structured data: ```json { "artifact_kind": "help", "linked_kbe": 133778, "workflow_artifact": "ci-fix" } ``` > Generated by [CI Outer-Loop Failure Fixer](https://github.com/dotnet/runtime/actions/runs/34916254170) · opus48 · 764.8 AIC · ⌖ 20.8 AIC · ⊞ 19.6K · [◷](https://github.com/search?q=repo%3Adotnet%2Fruntime+%22gh-aw-workflow-id%3A+ci-failure-fix%22&type=pullrequests) <!-- gh-aw-agentic-workflow: CI Outer-Loop Failure Fixer, engine: copilot, model: claude-opus-4.8, id: 34916254170, workflow_id: ci-failure-fix, run: https://github.com/dotnet/runtime/actions/runs/34916254170 --> <!-- gh-aw-workflow-id: ci-failure-fix --> <!-- gh-aw-workflow-call-id: dotnet/runtime/ci-failure-fix --> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixes #121848 ## Problem On macOS, when a peer connects to an `AF_INET6` listening socket and immediately resets the connection (`SO_LINGER=0`), `accept(2)` returns a valid file descriptor but leaves the remote sockaddr buffer untouched and reports `addrlen=0`. This kernel behavior was measured with a plain C repro in the [issue comment](#121848 (comment)) and does not depend on dual-mode or `IPV6_V6ONLY`. The 2024 fix (#108616) guarded the `EndPoint.Create` call inside `FinishOperationAccept` on the Unix path, but the shared `FinishOperationSyncSuccess` in [`SocketAsyncEventArgs.cs`](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs#L1016) calls `Create` a second time on the same zero-sized `SocketAddress` and throws `ArgumentException`. For Kestrel this kills the accept loop permanently while the process stays alive and the port stays bound. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…indows/Linux (refs #133778) (#133925) Workflow artifact: ci-fix Artifact kind: help Linked KBE: #133778 > [!NOTE] > This is an AI/Copilot-generated **best-effort** fix attempt that I could not fully validate. It is a starting point for a maintainer, not a finished change. Please review the analysis below before merging. ## Root cause (best analysis) `System.Net.Sockets.Tests.AcceptDualStackResetTests.Accept_DualStackListener_PeerImmediatelyResets_ListenerStaysHealthy(useAsync: True)` fails on `windows-x64`/`linux-x64` (`TestReadyToRun_Libraries` and the runtime pipeline): ``` System.Net.Sockets.SocketException : An existing connection was forcibly closed by the remote host. at System.Net.Sockets.Tests.AcceptDualStackResetTests.Accept_DualStackListener_PeerImmediatelyResets_ListenerStaysHealthy(Boolean useAsync) in /_/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs:line 527 ``` Line 527 is the `AcceptAsync`/`Accept` call, **not** the receive. The test (added by #131869) closes an IPv4 peer with `SO_LINGER=0` so the kernel sends an immediate RST, then expects the listener to still deliver the healthy IPv6 peer's byte. The `try { ... } catch (SocketException)` block only wraps the `ReceiveAsync`; the `accept` that precedes it sits **outside** the `try`. On Windows and Linux the reset is surfaced by `accept` itself (`WSAECONNRESET` / "connection forcibly closed"), which escapes the catch and fails the test, even though the very next accept iteration would return the healthy peer. macOS discards the reset at accept (which #131869 hardened `EndPoint.Create` for), so it doesn't hit this path — which is why the test passed there but not on Windows/Linux. The test comment already anticipates this ("Some platforms surface the reset connection from accept()"), but the code doesn't guard the accept accordingly. ## Attempted fix Move the `accept` inside the existing `try` block so a `SocketException` from either the accept or the following receive is tolerated, and the loop retries to accept the healthy peer on the next iteration (the loop already runs up to 2 accepts). No production code changes; the listener-stays-healthy assertion is preserved. This is **not** a test-disable — the test still runs and still asserts the healthy peer's message is received. ## What is unverified / where I need help - I could not build and run `System.Net.Sockets.Tests` in this environment, so I have not confirmed the test now passes on windows-x64/linux-x64 while still catching a genuine listener regression. - Please confirm the intended contract: on Windows/Linux, should the RST be observable at `accept` (making tolerating it here correct), or should the runtime itself suppress the reset connection from the accept loop the way macOS does? If the latter, the real fix belongs in the socket accept path rather than the test. ## Validation - Command: `not run because the sockets functional test suite could not be built/executed within the run budget` - Result: not run ## Evidence - Failing build: https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1593787 - First build it occurred: after #131869 (merged 2026-09-09, commit 7c35b7d), which introduced this test (computed within the scanned window; may not be the true origin) - Suspected regressing change: #131869 (added the test with the accept outside the catch) ## Help wanted - Likely author: `@wfurt` (authored #131869 that added the test) - Area owners (`area-System.Net.Sockets`): `@dotnet/ncl` --- Filed by [`ci-failure-fix`](https://github.com/dotnet/runtime/blob/main/.github/workflows/ci-failure-fix.md). Comment here or on the workflow file to suggest changes; [`ci-failure-scan-feedback`](https://github.com/dotnet/runtime/blob/main/.github/workflows/ci-failure-scan-feedback.md) reads in-scope feedback daily and opens (or updates) a PR with prompt edits. Structured data: ```json { "artifact_kind": "help", "linked_kbe": 133778, "workflow_artifact": "ci-fix" } ``` > Generated by [CI Outer-Loop Failure Fixer](https://github.com/dotnet/runtime/actions/runs/34916254170) · opus48 · 764.8 AIC · ⌖ 20.8 AIC · ⊞ 19.6K · [◷](https://github.com/search?q=repo%3Adotnet%2Fruntime+%22gh-aw-workflow-id%3A+ci-failure-fix%22&type=pullrequests) <!-- gh-aw-agentic-workflow: CI Outer-Loop Failure Fixer, engine: copilot, model: claude-opus-4.8, id: 34916254170, workflow_id: ci-failure-fix, run: https://github.com/dotnet/runtime/actions/runs/34916254170 --> <!-- gh-aw-workflow-id: ci-failure-fix --> <!-- gh-aw-workflow-call-id: dotnet/runtime/ci-failure-fix --> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…indows/Linux (refs dotnet#133778) (dotnet#133925) Workflow artifact: ci-fix Artifact kind: help Linked KBE: dotnet#133778 > [!NOTE] > This is an AI/Copilot-generated **best-effort** fix attempt that I could not fully validate. It is a starting point for a maintainer, not a finished change. Please review the analysis below before merging. ## Root cause (best analysis) `System.Net.Sockets.Tests.AcceptDualStackResetTests.Accept_DualStackListener_PeerImmediatelyResets_ListenerStaysHealthy(useAsync: True)` fails on `windows-x64`/`linux-x64` (`TestReadyToRun_Libraries` and the runtime pipeline): ``` System.Net.Sockets.SocketException : An existing connection was forcibly closed by the remote host. at System.Net.Sockets.Tests.AcceptDualStackResetTests.Accept_DualStackListener_PeerImmediatelyResets_ListenerStaysHealthy(Boolean useAsync) in /_/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs:line 527 ``` Line 527 is the `AcceptAsync`/`Accept` call, **not** the receive. The test (added by dotnet#131869) closes an IPv4 peer with `SO_LINGER=0` so the kernel sends an immediate RST, then expects the listener to still deliver the healthy IPv6 peer's byte. The `try { ... } catch (SocketException)` block only wraps the `ReceiveAsync`; the `accept` that precedes it sits **outside** the `try`. On Windows and Linux the reset is surfaced by `accept` itself (`WSAECONNRESET` / "connection forcibly closed"), which escapes the catch and fails the test, even though the very next accept iteration would return the healthy peer. macOS discards the reset at accept (which dotnet#131869 hardened `EndPoint.Create` for), so it doesn't hit this path — which is why the test passed there but not on Windows/Linux. The test comment already anticipates this ("Some platforms surface the reset connection from accept()"), but the code doesn't guard the accept accordingly. ## Attempted fix Move the `accept` inside the existing `try` block so a `SocketException` from either the accept or the following receive is tolerated, and the loop retries to accept the healthy peer on the next iteration (the loop already runs up to 2 accepts). No production code changes; the listener-stays-healthy assertion is preserved. This is **not** a test-disable — the test still runs and still asserts the healthy peer's message is received. ## What is unverified / where I need help - I could not build and run `System.Net.Sockets.Tests` in this environment, so I have not confirmed the test now passes on windows-x64/linux-x64 while still catching a genuine listener regression. - Please confirm the intended contract: on Windows/Linux, should the RST be observable at `accept` (making tolerating it here correct), or should the runtime itself suppress the reset connection from the accept loop the way macOS does? If the latter, the real fix belongs in the socket accept path rather than the test. ## Validation - Command: `not run because the sockets functional test suite could not be built/executed within the run budget` - Result: not run ## Evidence - Failing build: https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1593787 - First build it occurred: after dotnet#131869 (merged 2026-09-09, commit 7c35b7d), which introduced this test (computed within the scanned window; may not be the true origin) - Suspected regressing change: dotnet#131869 (added the test with the accept outside the catch) ## Help wanted - Likely author: `@wfurt` (authored dotnet#131869 that added the test) - Area owners (`area-System.Net.Sockets`): `@dotnet/ncl` --- Filed by [`ci-failure-fix`](https://github.com/dotnet/runtime/blob/main/.github/workflows/ci-failure-fix.md). Comment here or on the workflow file to suggest changes; [`ci-failure-scan-feedback`](https://github.com/dotnet/runtime/blob/main/.github/workflows/ci-failure-scan-feedback.md) reads in-scope feedback daily and opens (or updates) a PR with prompt edits. Structured data: ```json { "artifact_kind": "help", "linked_kbe": 133778, "workflow_artifact": "ci-fix" } ``` > Generated by [CI Outer-Loop Failure Fixer](https://github.com/dotnet/runtime/actions/runs/34916254170) · opus48 · 764.8 AIC · ⌖ 20.8 AIC · ⊞ 19.6K · [◷](https://github.com/search?q=repo%3Adotnet%2Fruntime+%22gh-aw-workflow-id%3A+ci-failure-fix%22&type=pullrequests) <!-- gh-aw-agentic-workflow: CI Outer-Loop Failure Fixer, engine: copilot, model: claude-opus-4.8, id: 34916254170, workflow_id: ci-failure-fix, run: https://github.com/dotnet/runtime/actions/runs/34916254170 --> <!-- gh-aw-workflow-id: ci-failure-fix --> <!-- gh-aw-workflow-call-id: dotnet/runtime/ci-failure-fix --> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…33567) Backport of #131869 to release/10.0 /cc @wfurt ## Customer Impact In some cases on Apple platforms, an unexpected error can leave us in a permanently broken state — the listening socket remains bound to its port, but the server stops accepting new connections. This is a small reliability fix for a regression introduced in .NET 10. It was reported by 7 users (GitHub and on the internet). The fix handles this condition gracefully. ## Regression - [x] Yes - introduced in .NET 10 ## Testing A new test was also added to cover this scenario. The fix was verified by a customer using a build from the main branch ## Risk Low. This just checks for error and swallows the exception. --------- Co-authored-by: Tomas Weinfurt <tweinfurt@yahoo.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Copilot-Session: 7ec5412f-9a88-4e9f-a1c4-fcff00d61248
…33566) Backport of #131869 to release/11.0 /cc @wfurt ## Customer Impact In some cases on Apple platforms, an unexpected error can leave us in a permanently broken state — the listening socket remains bound to its port, but the server stops accepting new connections. This is a small reliability fix for a regression introduced in .NET 10. It was reported by 7 users (GitHub and on the internet). The fix handles this condition gracefully. ## Regression - [x] Yes - introduced in .NET 10 ## Testing A new test was also added to cover this scenario. The fix was verified by a customer using a build from the main branch ## Risk Low. This just checks for error and swallows the exception --------- Co-authored-by: Tomas Weinfurt <tweinfurt@yahoo.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Copilot-Session: 7ec5412f-9a88-4e9f-a1c4-fcff00d61248
Fixes #121848
Problem
On macOS, when a peer connects to an
AF_INET6listening socket and immediately resets the connection (SO_LINGER=0),accept(2)returns a valid file descriptor but leaves the remote sockaddr buffer untouched and reportsaddrlen=0. This kernel behavior was measured with a plain C repro in the issue comment and does not depend on dual-mode orIPV6_V6ONLY.The 2024 fix (#108616) guarded the
EndPoint.Createcall insideFinishOperationAccepton the Unix path, but the sharedFinishOperationSyncSuccessinSocketAsyncEventArgs.cscallsCreatea second time on the same zero-sizedSocketAddressand throwsArgumentException. For Kestrel this kills the accept loop permanently while the process stays alive and the port stays bound.