Skip to content

Fix UF_HIDDEN causing st_flags to be dropped in ConvertFileStatus; add PAL_UF_HIDDEN static assert#125710

Open
Copilot wants to merge 6 commits intomainfrom
copilot/fix-uf-hidden-st-flags-issue
Open

Fix UF_HIDDEN causing st_flags to be dropped in ConvertFileStatus; add PAL_UF_HIDDEN static assert#125710
Copilot wants to merge 6 commits intomainfrom
copilot/fix-uf-hidden-st-flags-issue

Conversation

Copy link
Contributor

Copilot AI commented Mar 18, 2026

ConvertFileStatus was discarding all st_flags bits except UF_HIDDEN — replacing the full flag set with either PAL_UF_HIDDEN or 0. Additionally, there was no static assert ensuring PAL_UF_HIDDEN == UF_HIDDEN, which is required since SystemNative_LChflags/SystemNative_FChflags pass flags directly to the OS without remapping.

Visible effect

On macOS, if managed code read FileStatus.UserFlags and then wrote them back (e.g., toggling hidden), it would silently erase any other BSD user flags on the file. For example, a file marked immutable (UF_IMMUTABLE) could lose that protection after .NET touched its hidden attribute. In practice this was low-impact since .NET rarely manipulates these flags, but it's a correctness bug.

Changes

  • pal_io.cConvertFileStatus: Removed the ternary that collapsed st_flags to a single bit. Now passes all flags through directly, gated on both HAVE_STAT_FLAGS and defined(UF_HIDDEN) to ensure UserFlags remains 0 on platforms that lack UF_HIDDEN (preventing any unrelated st_flags bit from overlapping 0x8000 and falsely reporting files as hidden):

    // Before
    #if HAVE_STAT_FLAGS && defined(UF_HIDDEN)
        dst->UserFlags = ((src->st_flags & UF_HIDDEN) == UF_HIDDEN) ? PAL_UF_HIDDEN : 0;
    
    // After
    #if HAVE_STAT_FLAGS && defined(UF_HIDDEN)
        dst->UserFlags = (uint32_t)src->st_flags;

    The managed code in FileStatus.Unix.cs already uses bitwise ops (& UF_HIDDEN, | UF_HIDDEN, & ~UF_HIDDEN) so it handles additional flags correctly.

  • pal_io.c — static asserts block: Added c_static_assert(PAL_UF_HIDDEN == UF_HIDDEN) under #if HAVE_STAT_FLAGS && defined(UF_HIDDEN) to catch any future divergence between the PAL constant and the OS-defined value.

  • pal_io.c — comment fix: Corrected grammar in the static assert comment from "enum value are" to "enum values are".

Fixes #69004

…rt for PAL_UF_HIDDEN == UF_HIDDEN

Co-authored-by: danmoseley <6385855+danmoseley@users.noreply.github.com>
Copilot AI changed the title [WIP] [GH-123] Fix UF_HIDDEN causing st_flags to get dropped Fix UF_HIDDEN causing st_flags to be dropped in ConvertFileStatus; add PAL_UF_HIDDEN static assert Mar 18, 2026
Copilot AI requested a review from danmoseley March 18, 2026 03:54
@github-actions github-actions bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Mar 18, 2026
@jkotas jkotas added area-System.IO and removed area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI labels Mar 18, 2026
@danmoseley danmoseley requested review from Copilot and tmds and removed request for danmoseley and tmds March 18, 2026 04:53
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the Unix PAL file-status conversion to better surface (and validate) platform stat user flags, particularly around the hidden flag (UF_HIDDEN), by changing what gets assigned into FileStatus.UserFlags.

Changes:

  • Added a compile-time validation that PAL_UF_HIDDEN matches the platform’s UF_HIDDEN when available.
  • Changed ConvertFileStatus to populate FileStatus.UserFlags from st_flags when HAVE_STAT_FLAGS is available (instead of only mapping UF_HIDDEN).

@tmds
Copy link
Member

tmds commented Mar 18, 2026

@danmoseley I left some feedback for @copilot. I assume I can't ask it to act on that.

@adamsitnik
Copy link
Member

@danmoseley I left some feedback for @copilot. I assume I can't ask it to act on that.

@copilot address all of the @tmds feedback

… UF_HIDDEN being defined

Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 18, 2026

@danmoseley I left some feedback for @copilot. I assume I can't ask it to act on that.

@copilot address all of the @tmds feedback

Addressed both review points in 1a6d59a:

  1. Fixed the UserFlags assignment to be gated on HAVE_STAT_FLAGS && defined(UF_HIDDEN) — this prevents st_flags bits from being passed through on platforms that have HAVE_STAT_FLAGS but not UF_HIDDEN, which could otherwise cause files to be incorrectly reported as hidden.
  2. Fixed the comment grammar: "enum value are" → "enum values are".

Copilot AI requested a review from adamsitnik March 18, 2026 12:14
@adamsitnik adamsitnik requested a review from tmds March 18, 2026 12:23
@danmoseley danmoseley requested a review from Copilot March 18, 2026 14:49
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the System.Native stat-to-FileStatus conversion to preserve the platform st_flags value (when available) so managed code can round-trip flags (e.g., when toggling UF_HIDDEN) without unintentionally clearing other existing file flags.

Changes:

  • Add a compile-time validation that PAL_UF_HIDDEN matches the platform’s UF_HIDDEN value when supported.
  • Populate FileStatus.UserFlags with the full st_flags bitmask (instead of only mapping the hidden bit).

Adds a macOS-specific test that sets UF_NODUMP on a file, toggles
Hidden via FileInfo.Attributes, and verifies UF_NODUMP survives
the round-trip through ConvertFileStatus and lchflags.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danmoseley
Copy link
Member

Will have to rely on CI to validate this attempt at a macOS test.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the Unix native stat marshaling to preserve BSD st_flags values (on platforms that support UF_HIDDEN), enabling FileAttributes.Hidden toggling on macOS to retain other user flags (e.g., UF_NODUMP), and adds a regression test for that behavior.

Changes:

  • Return the full st_flags value via FileStatus.UserFlags when supported, instead of only projecting the hidden bit.
  • Add Unix interop sources (Interop.Stat, Interop.LChflags) to the FileSystem test project to validate flag preservation.
  • Add a macOS-specific test ensuring toggling Hidden preserves other user flags.

Reviewed changes

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

File Description
src/native/libs/System.Native/pal_io.c Populate FileStatus.UserFlags with the full st_flags (when supported) and add a static assert for UF_HIDDEN.
src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/System.IO.FileSystem.Tests.csproj Include additional Unix interop sources needed by the new test.
src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/FileInfo/GetSetAttributes.cs Add an OSX-only regression test for preserving other user flags when toggling Hidden.

The test references Interop.Sys.* types that are only available in the
unix ItemGroup. Split the test into GetSetAttributes.Unix.cs (compiled
only for unix TFM) and make the main class partial.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tmds
Copy link
Member

tmds commented Mar 18, 2026

@danmoseley it's been a long time since #69004. After reviewing the PR, I think as long as the native layer maps to what we have in the managed enum we're ok, even if that is only the UF_HIDDEN to PAL_UF_HIDDEN. So no change needed there. It's meaningful to add the static_assert to check SystemNative_LChflags and SystemNative_FChflags are using proper values. I had added this as feedback but @copilot did not understand what I meant.

@danmoseley
Copy link
Member

@tmds sorry I missed that. You're saying -- if I read flags with managed code, flip read only or whatever, and write back, it's OK if we wipe flags not represented in the managed enum? Isn't that arguably data loss (admittedly I didn't check whether we do it right and verify that elsewhere in our libraries)

cc @adamsitnik

@tmds
Copy link
Member

tmds commented Mar 18, 2026

if I read flags with managed code, flip read only or whatever, and write back, it's OK if we wipe flags not represented in the managed enum? Isn't that arguably data loss (admittedly I didn't check whether we do it right and verify that elsewhere in our libraries)

Ah, I had missed #69004 was for the round-trip.

Yes, we should address this (contrary to what I said in the previous comment).

@danmoseley
Copy link
Member

OK thanks then if test passes on macOS I think we are good to sign off.

@danmoseley
Copy link
Member

I had Copilot do a quick scan for any other places we drop flags. It only found the one this fixes. It pointed out that SetAttributes overwrites permissions but that's intentional

Clarify that the static assert exists because LChflags and FChflags
pass UserFlags values directly to the OS without remapping.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danmoseley danmoseley requested a review from Copilot March 18, 2026 19:23
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a correctness issue in the Unix PAL file status conversion on Apple/BSD platforms where FileStatus.UserFlags previously collapsed st_flags down to just the hidden bit, which could cause .NET to accidentally clear other BSD file flags when toggling FileAttributes.Hidden.

Changes:

  • Update ConvertFileStatus to preserve the full st_flags value (when UF_HIDDEN is supported) instead of mapping only UF_HIDDEN.
  • Add a c_static_assert to ensure PAL_UF_HIDDEN matches the platform’s UF_HIDDEN value.
  • Add an OSX test that verifies toggling Hidden preserves another user flag (UF_NODUMP).

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
src/native/libs/System.Native/pal_io.c Preserve all st_flags in FileStatus.UserFlags (when supported) and add a static assert for PAL_UF_HIDDEN.
src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/System.IO.FileSystem.Tests.csproj Include required Unix interop sources and the new Unix-only FileInfo attributes test.
src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/FileInfo/GetSetAttributes.Unix.cs New OSX regression test ensuring hidden toggling preserves other BSD user flags.
src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/FileInfo/GetSetAttributes.cs Make the test class partial so the Unix-specific test can be added in a separate file.

@danmoseley
Copy link
Member

danmoseley commented Mar 18, 2026

Copilot analysis of the failing leg -- it seems it was run on a machine where the AppleClang wasn't present, or at least wasn't found. Did anything change, or this is a misconfigured box?

-===
cc @dotnet/dnceng @akoeplinger

The Build osx-x64 Debug Mono_MiniJIT_LibrariesTests leg on PR #125710 is failing with 2498 errors in Apple SDK headers (Foundation.framework) due to -Weverything -Werror. The errors are all from Xcode 16.4 SDK headers, e.g.:

NSScriptSuiteRegistry.h: error: declaration of instance variables in the interface is deprecated [-Werror,-Wobjc-interface-ivars]
NSSpellServer.h: error: 'assign' property of object type may become a dangling reference [-Werror,-Wobjc-property-assign-on-object-type]

None of these are in our code -- they're all in Apple's own SDK headers.

Root cause

The failing build agent has standalone Clang 18.1.8 (/usr/local/bin/clang-18) as its C compiler, instead of the Xcode-bundled AppleClang. Standalone Clang 18 doesn't suppress these Obj-C deprecation warnings from SDK headers the way AppleClang does, so they become fatal errors when combined with our -Weverything -Werror flags.

Evidence

The same Build osx-x64 Debug Mono_MiniJIT_LibrariesTests leg passed on PR #125687 (same day, same Xcode 16.4). Comparing the CMake output from both builds:

Passing build (PR #125687, buildId=1341143) Failing build (PR #125710, buildId=1341703)
C compiler AppleClang 17.0.0.17000013 Clang 18.1.8 (/usr/local/bin/clang-18)
Xcode SDK 16.4 16.4
Result Success 2498 errors in SDK headers

The agent image that has /usr/local/bin/clang-18 installed is the problem -- CMake picks it up as the default C compiler, and standalone Clang doesn't have the same suppression of Apple SDK header warnings that AppleClang has.

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.

Nit: UF_HIDDEN causes st_flags to get dropped

6 participants