Description
BuildManager.Reset() defensively clears BuildRequestConfiguration.ActivelyBuildingTargets at the end of a build:
https://github.com/dotnet/msbuild/blob/main/src/Build/BackEnd/BuildManager/BuildManager.cs#L2520-L2525
This may be unsafe if a request task ignores cancellation. WaitForCancelCompletion() reports a timeout but cannot terminate the task, so the old TargetBuilder may later resume and execute its normal cleanup.
Potential interleaving
- An old request records
Build -> oldRequestId in ActivelyBuildingTargets.
- Cancellation times out while that request remains alive.
- End-of-build cleanup clears
ActivelyBuildingTargets.
- A later build records
Build -> newRequestId on the retained configuration.
- The old request resumes and calls
Remove("Build").
- The new request's entry is removed even though its target is still executing.
Target removal currently checks only the target name, not the owning request ID:
https://github.com/dotnet/msbuild/blob/main/src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs#L529-L530
Potential impact
The configuration can incorrectly report that no target is active. This could cause:
- another request to execute the same target concurrently instead of waiting;
- incorrect circular-dependency or target-blocking behavior;
CacheIfPossible() to cache the ProjectInstance while the new target is still using it.
Related discussion
This was identified while discussing cancellation cleanup in PR #14679:
Description
BuildManager.Reset()defensively clearsBuildRequestConfiguration.ActivelyBuildingTargetsat the end of a build:https://github.com/dotnet/msbuild/blob/main/src/Build/BackEnd/BuildManager/BuildManager.cs#L2520-L2525
This may be unsafe if a request task ignores cancellation.
WaitForCancelCompletion()reports a timeout but cannot terminate the task, so the oldTargetBuildermay later resume and execute its normal cleanup.Potential interleaving
Build -> oldRequestIdinActivelyBuildingTargets.ActivelyBuildingTargets.Build -> newRequestIdon the retained configuration.Remove("Build").Target removal currently checks only the target name, not the owning request ID:
https://github.com/dotnet/msbuild/blob/main/src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs#L529-L530
Potential impact
The configuration can incorrectly report that no target is active. This could cause:
CacheIfPossible()to cache theProjectInstancewhile the new target is still using it.Related discussion
This was identified while discussing cancellation cleanup in PR #14679: