Skip to content

Keep strong reference to virtual project's ProjectRootElement to prevent GC#53807

Merged
jjonescz merged 2 commits intodotnet:release/10.0.3xxfrom
jjonescz:52714-sprint-project-not-found
Apr 14, 2026
Merged

Keep strong reference to virtual project's ProjectRootElement to prevent GC#53807
jjonescz merged 2 commits intodotnet:release/10.0.3xxfrom
jjonescz:52714-sprint-project-not-found

Conversation

@jjonescz
Copy link
Copy Markdown
Member

When dotnet run --file builds a virtual .csproj in memory, the ProjectRootElement is only held alive by MSBuild's ProjectRootElementCache which may demote it to a weak reference when many SDK import files fill the cache (e.g., in large repos with Directory.Packages.props). If GC collects the weakly referenced element, nested <MSBuild> tasks during NuGet restore that re-evaluate the project with different properties fail to find it in the cache, try to load from disk, and throw MSB4025 because the virtual file does not exist.

Fix: Store the ProjectRootElement in a field on VirtualProjectBuilder so it stays alive for the duration of the build.

Fixes #52714

…ent GC

When dotnet run --file builds a virtual .csproj in memory, the ProjectRootElement
is only held alive by MSBuild's ProjectRootElementCache which may demote it to a
weak reference when many SDK import files fill the cache (e.g., in large repos
with Directory.Packages.props). If GC collects the weakly referenced element,
nested <MSBuild> tasks during NuGet restore that re-evaluate the project with
different properties fail to find it in the cache, try to load from disk, and
throw MSB4025 because the virtual file does not exist.

Fix: Store the ProjectRootElement in a field on VirtualProjectBuilder so it
stays alive for the duration of the build.

Fixes dotnet#52714

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jjonescz jjonescz added the Area-run-file Items related to the "dotnet run <file>" effort label Apr 10, 2026
Add VirtualProject_SurvivesGCDuringRestore test that forces GC of the
virtual project's ProjectRootElement during NuGet restore by:
- Setting MSBUILDPROJECTROOTELEMENTCACHESIZE=1 to ensure immediate eviction
- Using an inline task in Directory.Build.targets to call GC.Collect()
  before the nested <MSBuild> task in _FilterRestoreGraphProjectInputItems

Without the strong reference fix, this test reliably reproduces MSB4025.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jjonescz jjonescz marked this pull request as ready for review April 10, 2026 15:36
@jjonescz jjonescz requested review from a team and Copilot April 10, 2026 15:36
Copy link
Copy Markdown
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 an intermittent dotnet run --file failure where MSBuild can lose the in-memory virtual project (ProjectRootElement) if it is only weakly referenced in the MSBuild cache during restore, leading to MSB4025 when MSBuild attempts to reload the non-existent .csproj from disk.

Changes:

  • Keep a strong reference to the virtual project’s ProjectRootElement on VirtualProjectBuilder for the duration of the build.
  • Add a regression test that forces MSBuild’s strong PRE cache eviction and triggers GC during NuGet restore.

Reviewed changes

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

File Description
test/dotnet.Tests/CommandTests/Run/RunFileTests.cs Adds a regression test covering GC + MSBuild PRE cache eviction during restore for file-based dotnet run.
src/Microsoft.DotNet.ProjectTools/VirtualProjectBuilder.cs Stores the created ProjectRootElement in an instance field to prevent GC when MSBuild demotes cache entries to weak references.

@jjonescz jjonescz requested review from 333fred and MiYanni April 11, 2026 08:16
@jjonescz
Copy link
Copy Markdown
Member Author

/ba-g known: #53796, #53789

@jjonescz jjonescz merged commit c2f9314 into dotnet:release/10.0.3xx Apr 14, 2026
30 of 33 checks passed
@jjonescz jjonescz deleted the 52714-sprint-project-not-found branch April 14, 2026 07:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-run-file Items related to the "dotnet run <file>" effort

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants