Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

plugins fail to load for dotnet 6 single file - self contained app #59961

Closed
freddyrios opened this issue Oct 4, 2021 · 17 comments
Closed

plugins fail to load for dotnet 6 single file - self contained app #59961

freddyrios opened this issue Oct 4, 2021 · 17 comments

Comments

@freddyrios
Copy link

Description

Running plugins with dotnet 6 rc1 for single file, self contained applications broke. The issue was found originally in Linux, but was also reproduced on windows. Specifically the AssemblyDependencyResolver's constructor throws an exception when loading the plugin.

To reproduce follow the instructions on the readme in this isolated reproduction of the issue: https://github.com/freddyrios/pluginsloadfailure.

Alternatively follow microsoft documentation on creating an application with plugins https://docs.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support and publish it as a single file, self contained app with the runtime identifier that matches your system.

Configuration

dotnet --version: 6.0.100-rc.1.21463.6
reproduced both on windows 10 and raspbian (linux / debian)
windows 10 was x64 and raspbian is arm
doesn't look specific to the OS or architecture

Regression?

It is a regression, see the demo which shows doing the same steps with a different target breaks.

Other information

This is the stacktrace:

System.InvalidOperationException: Cannot load hostpolicy library. AssemblyDependencyResolver is currently only supported if the runtime is hosted through hostpolicy library.
---> System.EntryPointNotFoundException: Entry point was not found.
at Interop.HostPolicy.corehost_set_error_writer(IntPtr errorWriter)
at System.Runtime.Loader.AssemblyDependencyResolver..ctor(String componentAssemblyPath)
--- End of inner exception stack trace ---
at System.Runtime.Loader.AssemblyDependencyResolver..ctor(String componeyntAssemblyPath)
at AppWithPlugin.PluginLoadContext..ctor(String pluginPath) in [redacted]\pluginsloadfailure\AppWithPlugin\PluginLoadContext.cs:line 13
at AppWithPlugin.Program.LoadPlugin(String relativePath) in [redacted]\pluginsloadfailure\AppWithPlugin\Program.cs:line 71
at AppWithPlugin.Program.<>c.

b__0_0(String pluginPath) in [redacted]\pluginsloadfailure\AppWithPlugin\Program.cs:line 29
at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.ToList()
at AppWithPlugin.Program.Main(String[] args) in [redacted]\pluginsloadfailure\AppWithPlugin\Program.cs:line 16

@dotnet-issue-labeler dotnet-issue-labeler bot added area-Single-File untriaged New issue has not been triaged by the area owner labels Oct 4, 2021
@ghost
Copy link

ghost commented Oct 4, 2021

Tagging subscribers to this area: @agocke, @vitek-karas, @VSadov
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

Running plugins with dotnet 6 rc1 for single file, self contained applications broke. The issue was found originally in Linux, but was also reproduced on windows. Specifically the AssemblyDependencyResolver's constructor throws an exception when loading the plugin.

To reproduce follow the instructions on the readme in this isolated reproduction of the issue: https://github.com/freddyrios/pluginsloadfailure.

Alternatively follow microsoft documentation on creating an application with plugins https://docs.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support and publish it as a single file, self contained app with the runtime identifier that matches your system.

Configuration

dotnet --version: 6.0.100-rc.1.21463.6
reproduced both on windows 10 and raspbian (linux / debian)
windows 10 was x64 and raspbian is arm
doesn't look specific to the OS or architecture

Regression?

It is a regression, see the demo which shows doing the same steps with a different target breaks.

Other information

This is the stacktrace:

System.InvalidOperationException: Cannot load hostpolicy library. AssemblyDependencyResolver is currently only supported if the runtime is hosted through hostpolicy library.
---> System.EntryPointNotFoundException: Entry point was not found.
at Interop.HostPolicy.corehost_set_error_writer(IntPtr errorWriter)
at System.Runtime.Loader.AssemblyDependencyResolver..ctor(String componentAssemblyPath)
--- End of inner exception stack trace ---
at System.Runtime.Loader.AssemblyDependencyResolver..ctor(String componeyntAssemblyPath)
at AppWithPlugin.PluginLoadContext..ctor(String pluginPath) in [redacted]\pluginsloadfailure\AppWithPlugin\PluginLoadContext.cs:line 13
at AppWithPlugin.Program.LoadPlugin(String relativePath) in [redacted]\pluginsloadfailure\AppWithPlugin\Program.cs:line 71
at AppWithPlugin.Program.<>c.

b__0_0(String pluginPath) in [redacted]\pluginsloadfailure\AppWithPlugin\Program.cs:line 29
at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.ToList()
at AppWithPlugin.Program.Main(String[] args) in [redacted]\pluginsloadfailure\AppWithPlugin\Program.cs:line 16

Author: freddyrios
Assignees: -
Labels:

area-Single-File, untriaged

Milestone: -

@vitek-karas
Copy link
Member

As far as I can tell it's a "regression" in single-file - specifically when hostpolicy is part of the apphost, which is true for any superhost.

It works a non-single-file SCD app just fine.
My guess - the PInvoke redirection doesn't kick in for hostpolicy - don't know why.

@freddyrios
Copy link
Author

@vitek-karas yes, it is only a regression when making it a single file + self contained app.

Making it non single file or non self contained works.

@freddyrios
Copy link
Author

@vitek-karas forgot to add, that's what we have been running with .net 5.

@agocke agocke added this to Ask Mode in AppModel NET 6.0 Oct 4, 2021
@agocke agocke removed the untriaged New issue has not been triaged by the area owner label Oct 4, 2021
@agocke agocke added this to the 6.0.0 milestone Oct 4, 2021
@vitek-karas
Copy link
Member

I'm actually surprised that it worked on .net 5 - I would expect this to break even on .net 5 (windows or not)

@vitek-karas
Copy link
Member

It does indeed work on .net 5 - interesting...

The theory is that in both cases the hostpolicy is part of the host/superhost, and since it seems the DllImport fails, it's probably because we don't correctly "Redirect" the PInvoke "inside".

This was the case already in .NET 5, but maybe something else changed.

This will be much easier to solve for @VSadov because he knows exactly how this works...

@agocke agocke assigned VSadov and unassigned vitek-karas Oct 4, 2021
freddyrios added a commit to copenhagenatomics/CA_DataUploader that referenced this issue Oct 5, 2021
reason: this allows to run without publishing the app as a single file, which at the time of writing allows to workaround dotnet/runtime#59961
freddyrios added a commit to copenhagenatomics/CA_DataUploader that referenced this issue Oct 5, 2021
* breaking change: plugins run from the "plugins" subfolder

reason: this allows to run without publishing the app as a single file, which at the time of writing allows to workaround dotnet/runtime#59961

* Also fixed regression in #127 preventing the full help from showing in the help command.
@am11
Copy link
Member

am11 commented Oct 5, 2021

$ dotnet publish HelloPlugin -c Release -f net6.0 -o test
$ dotnet publish AppWithPlugin -c Release --use-current-runtime --self-contained -p:PublishSingleFile=true -f net6.0 -o test
$ test/AppWithPlugin

Loading commands from: /home/am11/projects/pluginsloadfailure/HelloPlugin.dll
System.InvalidOperationException: Cannot load hostpolicy library. AssemblyDependencyResolver is currently only supported if the runtime is hosted through hostpolicy library.
 ---> System.EntryPointNotFoundException: Unable to find an entry point named 'corehost_set_error_writer' in shared library 'libhostpolicy'.
   at Interop.HostPolicy.corehost_set_error_writer(IntPtr errorWriter)
   at System.Runtime.Loader.AssemblyDependencyResolver..ctor(String componentAssemblyPath)

corehost_set_error_writer is indeed missing from singlefile host:

$ strings ~/.dotnet6/packs/Microsoft.NETCore.App.Host.linux-musl-x64/6.0.0-rtm.21504.6/runtimes/linux-musl-x64/native/singlefilehost |\
    grep corehost_

corehost_main
corehost_main_with_output_buffer
corehost_initialize
corehost_resolve_component_dependencies
Hostpolicy must be initialized and corehost_main must have been called before calling corehost_resolve_component_dependencies.
corehost_resolve_component_dependencies results: {

vs. 5.0

$ strings ~/.dotnet5/packs/Microsoft.NETCore.App.Host.linux-musl-x64/5.0.10/runtimes/linux-musl-x64/native/singlefilehost |\
    grep corehost_

corehost_resolve_component_dependencies
corehost_main
corehost_load
corehost_set_error_writer
corehost_main_with_output_buffer
corehost_initialize
corehost_unload
corehost_main
corehost_main_with_output_buffer
corehost_initialize
corehost_resolve_component_dependencies
Hostpolicy must be initialized and corehost_main must have been called before calling corehost_resolve_component_dependencies.
corehost_resolve_component_dependencies results: {

@VSadov
Copy link
Member

VSadov commented Oct 5, 2021

Most likely reason for the failure is indeed missing PInvoke overrides.
We override known PInvokes in system libraries (like System.IO.Compression.Native) so they end up calling embedded implementations, but not in Interop.HostPolicy. It looks like we just missed that we have internal PInvokes there too.

I will work on a fix. It should not be too involved.

@VSadov
Copy link
Member

VSadov commented Oct 6, 2021

I have implemented a fix, and it works on 6.0, but I see 1 failure in Bundled_Framework_dependent_Targeting50_App
(PR for reference: #60046)

It is a framework dependent singlefile configuration targeting 5.0. (so far I only tested on Windows).
It fails with

2147450750. Detailed error: Hostpolicy must be initialized and corehost_main must have been called before calling corehost_resolve_component_dependencies.\\r\\n\\r\\n   at System.Runtime.Loader.AssemblyDependencyResolver..ctor(String componentAssembl

@vitek-karas - do we expect this configuration to work?
I am not entirely sure what the error means. We should have called main, I think.

Self-contained 5.0 seems to be fine, BTW, just framework-dependent has issues.

@vitek-karas
Copy link
Member

It should not fail like that. I'll have to look into this.

@vitek-karas
Copy link
Member

That failure is a test-only issue. In the tests we create the apphost (before bundling) and stamp it with a full path to the application dll. So something like F:\dotnet\runtime\artifacts\...\publish\App.dll. Then we bundle and the produced executable goes into F:\dotnet\runtime\artifacts\...\bundle\App.exe. Both locations have hostpolicy.dll in them (the publish because it's a self-contained publish output, and the bundle because hostpolicy is excluded from the bundle).

When starting the app, because the App.dll path is absolute the apphost takes its location as the "app base path" and ends up loading hostfxr and hostpolicy from the publish directory. But at runtime when we PInvoke to hostpolicy, the path to the exe is considered first, and so we load hostpolicy from the bundle path. That second copy of hostpolicy is not initialized, and thus fails with the above error message.

SDK will never do this because it doesn't write absolute paths to the apphost, it only writes relative paths and so the "app base" will be the location of the "exe".

Ideally CreateAppHost would prevent absolute paths completely, but that's something to consider for future.

@vitek-karas
Copy link
Member

I prepared a fix and sent it to your PR via another PR VSadov#3.

@eglasius
Copy link

@VSadov did the fix merged into the dotnet 6 branch made it to the rc2?

@am11
Copy link
Member

am11 commented Oct 12, 2021

I have tested @freddyrios' application and can confirm that fix is available in 6.0.0-rtm.21511.12 (but not rc2), downloaded from https://github.com/dotnet/installer#installers-and-binaries (second column in the table). The app does not throw missing entrypoint exception for corehost_set_error_writer anymore.

Note that rc2 is not getting the recent runtime changes, use rtm daily snapshots for the latest of net6.

@freddyrios
Copy link
Author

I can confirm the latest daily for dotnet 6 rtm works for our full app running on linux - raspbian.

Are there any additional steps needed to ensure it makes it to the full release, or is the presence in the daily snapshots already confirmation it will make it?

ps. I assume daily snapshots are not covered by the golive

@vitek-karas
Copy link
Member

The fix will make it to 6.0 release.

Are there any additional steps needed to ensure it makes it to the full release, or is the presence in the daily snapshots already confirmation it will make it?

Just clarifying if you used the Release/6.0.1XX daily snapshots, then yes, those are builds which will eventually become the final release. (Not the main/7.0.x).

ps. I assume daily snapshots are not covered by the golive

No, the only golive releases are the RC1 and RC2 official builds (and then the final release).

AppModel NET 6.0 automation moved this from Ask Mode to Done Oct 13, 2021
AppModel .NET 7 automation moved this from Needs triage to Closed Oct 13, 2021
@freddyrios
Copy link
Author

freddyrios commented Oct 13, 2021

thanks all for the quick response

@dotnet dotnet locked as resolved and limited conversation to collaborators Nov 12, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
No open projects
Development

No branches or pull requests

6 participants