Skip to content

[release/11.0] Disable file locking by default on iOS and tvOS - #134331

Merged
steveisok merged 1 commit into
release/11.0from
backport/pr-134060-to-release/11.0
Sep 21, 2026
Merged

steveisok merged 1 commit into
release/11.0from
backport/pr-134060-to-release/11.0

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Backport of #134060 to release/11.0

/cc @vitek-karas @rolfbjarne

Customer Impact

  • Customer reported
  • Found internally

Application on iOS which happens to take a lock on a file can be killed by the OS if it goes to background. For details look at the customer reported issue: #133697

Regression

  • Yes
  • No

This worked on mono, since mono actually didn't lock files in the file system on iOS (effectively what this PR does)

Testing

Manual validation of the customer scenario. Full CI run on extra platforms.

Risk

Low - there will be one difference from mono behavior. mono implemented locking for files from the same process (and from .NET), with this change CoreCLR doesn't do that. This is considered very unlikely to be relied upon by customers. We will document this change as a breaking change for .NET 11.

IMPORTANT: If this backport is for a servicing release, please verify that:

  • For .NET 8 and .NET 9: The PR target branch is release/X.0-staging, not release/X.0.
  • For .NET 10+: The PR target branch is release/X.0 (no -staging suffix).

Package authoring no longer needed in .NET 9

IMPORTANT: Starting with .NET 9, you no longer need to edit a NuGet package's csproj to enable building and bump the version.
Keep in mind that we still need package authoring in .NET 8 and older versions.

## Summary

Disables advisory file locking by default on iOS and tvOS (device and
simulator), while leaving Mac Catalyst — and every other platform —
unchanged. The behavior remains fully configurable: setting
`System.IO.DisableFileLocking=false` (or
`DOTNET_SYSTEM_IO_DISABLEFILELOCKING=0`) restores locking on those
platforms.

## Motivation

On iOS and tvOS, RunningBoard terminates a suspended app with exception
code `0xdead10cc` when the app still holds a file lock on a file outside
its data container. .NET acquires such a lock implicitly: every
`FileStream` opened on Unix takes an advisory `flock` to emulate Windows
`FileShare` semantics, and a `FileShare.Read` open maps to a shared
`LOCK_SH`.

A common way to hit this is stack trace symbolication: when the runtime
opens a PDB from inside the read-only app bundle to produce line numbers
for an exception, the resulting shared lock lives for as long as the
handle does. If the user backgrounds the app while that handle is open,
the system kills the process. The lock provides no real value here — the
app bundle is read-only and the lock is only advisory between .NET
processes — but the termination is fatal and hard to diagnose.

## Implementation

`SafeFileHandle.DisableFileLocking` on Unix already consults the
`System.IO.DisableFileLocking` / `DOTNET_SYSTEM_IO_DISABLEFILELOCKING`
config switch; this change only alters the `defaultValue` passed to that
lookup, so it becomes `true` on iOS and tvOS:

```csharp
defaultValue: (OperatingSystem.IsIOS() && !OperatingSystem.IsMacCatalyst()) || OperatingSystem.IsTvOS()
```

Notes on the predicate:

- `OperatingSystem.IsIOS()` returns `true` for Mac Catalyst as well, so
Mac Catalyst is explicitly excluded — it runs on macOS, is not subject
to RunningBoard suspension policy, and keeps its current locking
behavior.
- iOS and tvOS simulators report as iOS/tvOS, so they follow the device
default. That keeps simulator test runs representative of device
behavior rather than silently diverging.
- Browser and WASI continue to force locking off unconditionally, as
before; they are unaffected by this change.

Because this goes through `AppContextConfigHelper`, an explicit `false`
still wins over the new default, so anyone depending on `FileShare`
enforcement on iOS/tvOS can opt back in.

The observable consequence is that on iOS and tvOS, `FileShare` is no
longer enforced between processes or handles: opening a file with
`FileShare.None` no longer prevents a second open, and the `IOException`
that previously signalled a sharing violation is no longer thrown. This
matches the behavior that Browser and WASI have had for some time.

## Test changes

Add a small iOS/tvOS-specific test asserting that file locking is in
fact off by default, so a future regression in the predicate is caught
directly rather than only as a cascade of sharing-violation test
failures.

Most lock-dependent tests in `System.IO.FileSystem` were already
conditioned on `PlatformDetection.IsFileLockingEnabled`, which reflects
the runtime's `DisableFileLocking` value and therefore picks up the new
default automatically. The second commit extends that same pattern to
the remaining tests that depend on `FileShare` being enforced:

| Area | Change |

|-------------------------------------|---------------------------------------------------------------------------------------------|
| `System.Reflection` | `GetAssemblyName_LockedFile` now uses
`ConditionalFact` on `IsFileLockingEnabled` |
| `System.IO.IsolatedStorage` | `OpenFile_PassesFileShare` now uses
`ConditionalFact` on `IsFileLockingEnabled` |
| `System.IO.MemoryMappedFiles` |
`FileInUse_CreateFromFile_FailsWithExistingNoShareFile` now uses
`ConditionalFact` |
| `System.ComponentModel.Composition` | The four
`ConstructorN_LockedFileAsCodeBaseArgument_ShouldThrowFileLoad` tests
use `ConditionalFact` |

In two of these cases the new condition subsumes an existing
`[SkipOnPlatform(TestPlatforms.Browser, ...)]` attribute — Browser was
skipped precisely because it does not honor file locking — so the
attribute is removed in favor of the more general check.

## Validation

Built and ran locally on macOS:

- `./build.sh clr+libs -rc checked`
- `./build.sh clr.corelib+clr.nativecorelib+libs.pretest -rc checked`

Test results:

| Suite                                          | Total | Failed |
|------------------------------------------------|-------|--------|
| `System.IO.FileSystem.Tests`                   | 9,607 | 0      |
| `System.IO.FileSystem.Tests` (locking disabled) | 2,095 | 0      |
| `System.Reflection` tests                      | 1,778 | 0      |
| `System.IO.IsolatedStorage` tests              | 198   | 0      |
| `System.IO.MemoryMappedFiles` tests            | 937   | 0      |
| `System.ComponentModel.Composition` tests      | 1,431 | 0      |

The "locking disabled" run exercises the new code path by forcing
`DisableFileLocking` on, which is the configuration iOS and tvOS will
now get by default.

Fixes #133697.

> [!NOTE]
> This pull request description was generated with the assistance of
GitHub Copilot.

---------

Co-authored-by: Vitek Karas <10670590+vitek-karas@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@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.

@vitek-karas

Copy link
Copy Markdown
Member

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@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.

@rolfbjarne

Copy link
Copy Markdown
Member

None of the observed CI failures are related to PR #134331.

The failures occur in unrelated networking, browser-WASM numeric, Android compiler, culture/DNS, Apple test-runner, and runtime-test infrastructure paths. MacCatalyst behavior is explicitly unchanged by the PR.

Build Analysis matched several failures to known issues:

Additional failures match or resemble pre-existing reports, including #132059,
#124079, #131990, #133234, #131921, #132074, and #106393.

The remaining failures also have unrelated or infrastructure-specific causes:

  • Two Android NativeAOT legs hit the same CS9377 toolchain error.
  • Two tvOS runtime-test shards failed with No space left on device.
  • Ten independent MacCatalyst runtime-test shards reached the same three-hour
    timeout.
  • Isolated WebSockets, DNS, globalization, and socket failures have clear
    flaky or environmental failure shapes.
  • One tvOS work item lacked a console log, but it occurred in the same job as
    the disk-exhaustion failures and is very likely part of the same incident.

The PR should not be blocked or modified because of this CI run.

Evidence:

@vitek-karas vitek-karas added the Servicing-consider Issue for next servicing release review label Sep 21, 2026
@steveisok steveisok added Servicing-approved Approved for servicing release and removed Servicing-consider Issue for next servicing release review labels Sep 21, 2026
@steveisok
steveisok enabled auto-merge (squash) September 21, 2026 18:58
@vitek-karas

Copy link
Copy Markdown
Member

CI analysis:
The remaining Build Analysis–unmatched failures were unrelated to PR #134331’s file-locking change:

@vitek-karas

Copy link
Copy Markdown
Member

/ba-g per previous comment, all failures are unrelated.

@steveisok
steveisok merged commit e51e925 into release/11.0 Sep 21, 2026
183 of 196 checks passed
@steveisok
steveisok deleted the backport/pr-134060-to-release/11.0 branch September 21, 2026 19:51
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 11.0-rc2 milestone Sep 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-System.IO Servicing-approved Approved for servicing release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants