Skip to content

Fix Unix file descriptor assertion - #132136

Merged
adamsitnik merged 4 commits into
mainfrom
copilot/remove-fd-condition-add-unix-test
Aug 12, 2026
Merged

adamsitnik merged 4 commits into
mainfrom
copilot/remove-fd-condition-add-unix-test

Conversation

Copilot AI commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

The Unix descriptor assertion treated the mutable soft open-file limit as a validity bound.

Changes

  • Retain only the non-negative descriptor assertion.
  • Add an isolated Unix dup2 regression test that lowers RLIMIT_NOFILE after duplicating a handle, then writes through the resulting SafeFileHandle with RandomAccess.Write.

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

Copy link
Copy Markdown
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.

@adamsitnik adamsitnik linked an issue Aug 11, 2026 that may be closed by this pull request

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.

Pull request overview

Fixes an incorrect Unix file-descriptor debug assertion that treated the mutable soft RLIMIT_NOFILE as a validity bound, and adds a Unix regression test covering dup2 + lowering RLIMIT_NOFILE + RandomAccess.Write via SafeFileHandle.

Changes:

  • Removes the _SC_OPEN_MAX-based upper-bound assertion from ToFileDescriptor.
  • Adds a Unix-only regression test that duplicates a file descriptor, lowers RLIMIT_NOFILE, then writes through the duplicated SafeFileHandle.
  • Wires the new test and required Unix interop into the System.Runtime filesystem test project.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/native/libs/Common/pal_utilities.h Adjusts Unix file-descriptor assertion to avoid using a mutable soft-limit as a validity bound.
src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/System.IO.FileSystem.Tests.csproj Adds the new Unix dup2 regression test and required RLIMIT interop file to the test compilation list.
src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/RandomAccess/Dup2.Unix.cs Introduces a new Unix regression test exercising dup2 + lowered RLIMIT_NOFILE + RandomAccess.Write.

Comment thread src/native/libs/Common/pal_utilities.h

@adamsitnik adamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@copilot please address my feedback

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 11, 2026 15:47

Copilot AI commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please address my feedback

Addressed in 0cb66306.

Note

This response was generated by Copilot.

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.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/native/libs/Common/pal_utilities.h:83

  • ToFileDescriptorUnchecked truncates intptr_t to int. After removing the sysconf(_SC_OPEN_MAX) bound, ToFileDescriptor no longer asserts that the value is representable as an int, so a large fd could silently wrap/truncate in debug builds. Consider keeping an upper-bound assertion that doesn’t depend on the mutable soft limit, e.g. fd <= INT_MAX.
inline static int ToFileDescriptor(intptr_t fd)
{
#ifndef TARGET_WASI // the valid range of file descriptors is probably INT32_MIN <= fd && fd <= INT32_MAX, the negative handles are valid for console.
    assert(0 <= fd);
#endif

@adamsitnik adamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@copilot address the feedback

Comment thread src/native/libs/Common/pal_utilities.h
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 11, 2026 16:45

Copilot AI commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

@copilot address the feedback

Addressed in 3ee4b61d.

Note

This response was generated by Copilot.

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.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/native/libs/Common/pal_utilities.h:83

  • ToFileDescriptor casts intptr_t to int. The new upper-bound assert uses fd < INT_MAX, but INT_MAX itself is representable by int and the comment above says fd <= INT32_MAX. Using < can trip debug builds for a theoretically valid descriptor value; the check should match the cast range (<= INT_MAX).
#ifndef TARGET_WASI // the valid range of file descriptors is probably INT32_MIN <= fd && fd <= INT32_MAX, the negative handles are valid for console.
    assert(0 <= fd);
    assert(fd < INT_MAX);

src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/SafeFileHandle/GetFileType.Unix.cs:113

  • The test potentially targets low file descriptors when the current soft limit is already small (e.g., 3 => maxAllowedFileDescriptor becomes 2, overwriting stderr via dup2). This can break the RemoteExecutor process (pipes/std* fds) and make the test flaky. Consider raising the soft limit up to the hard limit (capped), and skip when the resulting limit is too small for a safe high descriptor.
                Assert.Equal(0, Interop.Sys.GetRLimit(Interop.Sys.RlimitResources.RLIMIT_NOFILE, out Interop.Sys.RLimit limits));

                limits.CurrentLimit = Math.Min(limits.CurrentLimit, MaximumFileDescriptorLimit);
                Assert.InRange(limits.CurrentLimit, 2UL, (ulong)int.MaxValue);
                Assert.Equal(0, Interop.Sys.SetRLimit(Interop.Sys.RlimitResources.RLIMIT_NOFILE, ref limits));

@adamsitnik adamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@copilot address my feedback

Comment thread src/native/libs/Common/pal_utilities.h
…side ifdef

Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 11, 2026 17:07
Copilot AI requested a review from adamsitnik August 11, 2026 17:08

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.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/native/libs/Common/pal_utilities.h:85

  • ToFileDescriptor still allows values < INT_MIN (when TARGET_WASI is defined) to pass the assertions, even though the subsequent cast to int would truncate/produce an invalid descriptor. It would be safer for the debug-time contract to assert the full int range before narrowing.
#ifndef TARGET_WASI // the valid range of file descriptors is probably INT32_MIN <= fd && fd <= INT32_MAX, the negative handles are valid for console.
    assert(0 <= fd);
#endif
    assert(fd <= INT_MAX);

src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/SafeFileHandle/GetFileType.Unix.cs:113

  • This test can end up dup2'ing onto fd 0/1/2 when RLIMIT_NOFILE is very small (e.g., 2 or 3), which can break the remote test process’ stdin/stdout/stderr and make the failure mode noisy/flaky. Guard against too-small limits and skip in that case.
                limits.CurrentLimit = Math.Min(limits.CurrentLimit, MaximumFileDescriptorLimit);
                Assert.InRange(limits.CurrentLimit, 2UL, (ulong)int.MaxValue);
                Assert.Equal(0, Interop.Sys.SetRLimit(Interop.Sys.RlimitResources.RLIMIT_NOFILE, ref limits));

@adamsitnik
adamsitnik marked this pull request as ready for review August 11, 2026 17:35
@azure-pipelines

Copy link
Copy Markdown
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.

@adamsitnik adamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@adamsitnik
adamsitnik requested a review from jkotas August 12, 2026 12:54
@adamsitnik

Copy link
Copy Markdown
Member

/ba-g Helix Job Monitor timeout is unrelated

@adamsitnik
adamsitnik merged commit 98e33f5 into main Aug 12, 2026
159 of 161 checks passed
@adamsitnik
adamsitnik deleted the copilot/remove-fd-condition-add-unix-test branch August 12, 2026 17:17
@dotnet-milestone-bot dotnet-milestone-bot Bot modified the milestones: 11.0.0, 11.0-rc1 Aug 13, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Possibly incorrect fd assertion in pal_utilities.h

4 participants