CLR4 TaskHost does not inherit parent host assembly binding policy
- Dominant language
- C#
- Stars
- 5.5k
- Forks
- 1.5k
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 141
Description
## Summary
CLR4 TaskHost execution does not reproduce the parent host's effective assembly-binding policy for an ordinary task. A task that succeeds in-process through a binding redirect can therefore fail in TaskHost with `MSB4018` / `FileNotFoundException`.
This was found through an **artificial compatibility experiment** using the internal `MSBUILDFORCEALLTASKSOUTOFPROC=1` escape hatch. It is not a report of a known production build break, and forcing every task into TaskHost is not a supported normal build configuration.
## Minimal repro
https://gist.github.com/JanProvaznik/096bb6c1a96a442313ed4ac8eb7927f9
Run:
```powershell
.\build-and-run.ps1 -MSBuildBin C:\path\to\net472\MSBuild\Current\Bin\amd64
```
The repro creates:
- A strong-named `Repro.Dependency` version `1.0.0.0`.
- A task compiled against dependency version 1.
- A strong-named `Repro.Dependency` version `2.0.0.0`, which is the only version deployed beside the task.
- A custom MSBuild host with a binding redirect from versions 0–2 to version 2.
It then builds the same project twice:
1. Normally, with the task executing inside the custom host.
2. With `MSBUILDFORCEALLTASKSOUTOFPROC=1`, which routes the task through an external CLR4 TaskHost.
## Actual behavior
The in-process invocation succeeds:
```text
Building in the custom host process.
Loaded Repro.Dependency 2.0.0.0
Build succeeded.
```
The TaskHost invocation fails:
```text
Building with every task forced into TaskHost.
error MSB4018: The "ReportDependencyVersion" task failed unexpectedly.
error MSB4018: System.IO.FileNotFoundException:
Could not load file or assembly
'Repro.Dependency, Version=1.0.0.0, Culture=neutral, PublicKeyToken=...'
```
Reproduced against MSBuild `18.10.0.35201`, source commit `65f75f9249a01a3ec8e5220f5173eba3b5db7bc5`.
## Expected behavior
TaskHost should apply compatible managed assembly-binding policy so that a task which succeeds in its parent host does not fail solely because execution moved across the TaskHost boundary.
## Mechanism
`TaskHostConfiguration` transports the parent's `AppDomainSetup` configuration bytes. However, those settings are applied only when `TaskLoader` creates a separate AppDomain for a task marked with `[LoadInSeparateAppDomain]`.
An ordinary task executes directly in the external TaskHost process's root AppDomain. That domain was created using the TaskHost executable's configuration, not the custom parent host's binding policy. Consequently:
- The parent host redirects dependency version 1 to the deployed version 2.
- TaskHost requests the exact compiled identity, version 1.
- Version 2 is physically present beside the task, but strong-name binding correctly rejects it without policy redirecting version 1 to version 2.
Adding a resolver that loads any adjacent assembly with the same filename would not be a safe general fix because it would bypass strong-name version policy.
## Possible direction
For CLR4 TaskHost, execute tasks inside an AppDomain created from the transported parent `AppDomainSetup`, with the task loading and execution occurring entirely inside that domain. Reuse would need to be scoped by an effective configuration fingerprint, or the domain could be unloaded per task.
The compatibility and performance implications need evaluation because changing binding behavior could affect existing tasks that already use TaskHost explicitly.
Contributor guide
No contributing guide indexed for this repository
Research direction
Trace TaskHostConfiguration's transported AppDomainSetup and TaskLoader's separate-AppDomain path, then reproduce the discrepancy with the linked minimal repro and MSBUILDFORCEALLTASKSOUTOFPROC=1. Done means ordinary CLR4 TaskHost execution honors the parent's compatible binding policy without unsafe filename-based resolution, with compatibility and performance implications evaluated.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- build-system, tooling
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100