dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.09k stars 4.7k forks source link

infinite recursion during resource lookup with system.private.corelib #23938

Closed chenhuiguo closed 4 years ago

chenhuiguo commented 6 years ago

my program ran on ubuntu 16.04.3 buildied with dotnet2.0.0,but it failed on one machine. stack trace: Assert Failure Expression: [Recursive resource lookup bug] Description: Infinite recursion during resource lookup within System.Private.CoreLib. This may be a bug in System.Private.CoreLib, or potentially in certain extensibility points such as assembly resolve events or CultureInfo names. Resource name: ArgumentNull_Generic Stack Trace: at System.SR.InternalGetResourceString(String key) at System.SR.GetResourceString(String resourceKey, String defaultString) at System.ArgumentNullException..ctor(String paramName) at System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(Assembly assembly) at System.Reflection.Assembly.LoadFromResolveHandler(Object sender, ResolveEventArgs args) at System.AppDomain.OnAssemblyResolveEvent(RuntimeAssembly assembly, String assemblyFullName) at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks, IntPtr ptrLoadContextBinder) at System.Reflection.RuntimeAssembly.InternalGetSatelliteAssembly(String name, CultureInfo culture, Version version, Boolean throwOnFileNotFound, StackCrawlMark& stackMark) at System.Resources.ManifestBasedResourceGroveler.GetSatelliteAssembly(CultureInfo lookForCulture, StackCrawlMark& stackMark) at System.Resources.ManifestBasedResourceGroveler.GrovelForResourceSet(CultureInfo culture, Dictionary2 localResourceSets, Boolean tryParents, Boolean createIfNotExists, StackCrawlMark& stackMark) at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo requestedCulture, Boolean createIfNotExists, Boolean tryParents, StackCrawlMark& stackMark) at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents) at System.Resources.ResourceManager.GetString(String name, CultureInfo culture) at System.SR.InternalGetResourceString(String key) at System.SR.GetResourceString(String resourceKey, String defaultString) at System.ArgumentNullException..ctor(String paramName) at System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(Assembly assembly) at System.Reflection.Assembly.LoadFromResolveHandler(Object sender, ResolveEventArgs args) at System.AppDomain.OnAssemblyResolveEvent(RuntimeAssembly assembly, String assemblyFullName) at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks, IntPtr ptrLoadContextBinder) at System.Reflection.RuntimeAssembly.InternalGetSatelliteAssembly(String name, CultureInfo culture, Version version, Boolean throwOnFileNotFound, StackCrawlMark& stackMark) at System.Resources.ManifestBasedResourceGroveler.GetSatelliteAssembly(CultureInfo lookForCulture, StackCrawlMark& stackMark) at System.Resources.ManifestBasedResourceGroveler.GrovelForResourceSet(CultureInfo culture, Dictionary2 localResourceSets, Boolean tryParents, Boolean createIfNotExists, StackCrawlMark& stackMark) at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo requestedCulture, Boolean createIfNotExists, Boolean tryParents, StackCrawlMark& stackMark) at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents) at System.Resources.ResourceManager.GetString(String name, CultureInfo culture) at System.SR.InternalGetResourceString(String key) at System.SR.GetResourceString(String resourceKey, String defaultString) at System.Runtime.Loader.AssemblyLoadContext.ResolveUsingEvent(AssemblyName assemblyName) at System.Runtime.Loader.AssemblyLoadContext.ResolveUsingResolvingEvent(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName) at System.Reflection.RuntimeAssembly.GetType(RuntimeAssembly assembly, String name, Boolean throwOnError, Boolean ignoreCase, ObjectHandleOnStack type, ObjectHandleOnStack keepAlive) at System.Reflection.RuntimeAssembly.GetType(RuntimeAssembly assembly, String name, Boolean throwOnError, Boolean ignoreCase, ObjectHandleOnStack type, ObjectHandleOnStack keepAlive) at System.Reflection.RuntimeAssembly.GetType(String name, Boolean throwOnError, Boolean ignoreCase) at System.Reflection.Assembly.CreateInstance(String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) at System.Reflection.Assembly.CreateInstance(String typeName)

xneg commented 6 years ago

Same problem.

This code throws similar exception:

System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo("ru-ru");
var appPath = AppDomain.CurrentDomain.BaseDirectory;
Assembly.LoadFrom(Path.Combine(appPath, "SomeProject.dll"));
Task.Run(() => Console.WriteLine("something")).Wait();

And this code works

System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-us");
var appPath = AppDomain.CurrentDomain.BaseDirectory;
Assembly.LoadFrom(Path.Combine(appPath, "SomeProject.dll"));
Task.Run(() => Console.WriteLine("something")).Wait();
danmoseley commented 6 years ago

@chenhuiguo @xneg this is https://github.com/dotnet/corefx/issues/22586. It is fixed in master and we expect the fix to go out in servicing next month. If your thread culture is en-US one workaround is to do something like new ArgumentException() at the top of Main() to force the neutral resources to load. If your thread culture is something else, there is no workaround, except in cases where the bug is being provoked by code you can avoid running. For example, AppInsights registers an assembly load handler that triggers the bug (AppInsights does not have a bug) so temporarily removing it has helped some people.

hanxinimm commented 6 years ago

@danmosemsft Microsoft.Orleans.OrleansCodeGenerator.Build on build the same error I found the issue has been there for several months,hope you to fix it as soon as possible,,thanks

karelz commented 6 years ago

Duplicate of dotnet/runtime#22909

BladeWise commented 6 years ago

@danmosemsft @karelz Is the servicing release 2.0.2? Even using .NET Core 2.0.2 I still hit this issue in one ASP.Net Core project, but only when the site is hosted in IIS. If it is hosted in IIS Express, or launched using dotnet CLI I have no issues.

danmoseley commented 6 years ago

@bladewise 2.0.3 due out in a few days. We expect servicing releases to move more smoothly in future.

danmoseley commented 6 years ago

Fix released https://github.com/dotnet/corefx/releases/tag/v2.0.3

danielcrabtree commented 6 years ago

@danmosemsft How do we get a project to actually use 2.0.3?

I have 2.0.3 installed (and newer releases), but I'm not sure it is actually being used. When I go into NuGet, it lists the package as 2.0.0 and shows 2.0.3 and 2.0.4 in the list, but they cannot be selected as they're "Blocked by project".

I'm getting the Infinite recursion during resource lookup within System.Private.CoreLib error and adding System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-us"); fixed it.

So either the issue is not fixed or I'm not actually using 2.0.3 or newer.

danmoseley commented 6 years ago

@joperezr can you help?

joperezr commented 6 years ago

@danielcrabtree how are you running your code? Are you using Visual Studio or are you using the dotnet command line?

danielcrabtree commented 6 years ago

In this particular case, it's a console program and I'm compiling it to an exe, so it can be run directly on Windows. The error occurs when running it via this exe or via Visual Studio. I have not tried running via the dotnet command line.

The thing I'm unsure about is whether it is actually using the newer point releases or not. Is there some way to confirm which version it is using or to specify it when compiling?

danmoseley commented 6 years ago

Could you start your app (make it pause of necessary) then use process explorer to find the path to and certain of the system.private.corelib.dll that is loaded into your app?

danielcrabtree commented 6 years ago

It's using D:\Users\[Username]\.nuget\packages\runtime.win-x64.microsoft.netcore.app\2.0.0\runtimes\win-x64\native\System.Private.CoreLib.dll

For reference, the csproj is using:

<PropertyGroup>
  <OutputType>Exe</OutputType>
  <TargetFramework>netcoreapp2.0</TargetFramework>
  <LangVersion>latest</LangVersion>
  <RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
joperezr commented 6 years ago

If you build (and run it) using Visual studio it won't actually use the 2.0.3 runtime yet since we use MSBuild directly to compile it and depending on which TFM you are targeting we will use assets coming from packages(like you are seeing above). In order to use the 2.0.3 runtime from the command line, you can try running

dotnet --version //and ensure that the output is 2.0.3 meaning that you do have it installed.
dotnet restore yourProject.csproj
dotnet build yourProject.csproj
dotnet run yourProject.csproj

That should run on the 2.0.3 runtime so you shouldn't see the bug. If you want to fix it on VS side, then you need to update VisualStudio to latest version so that it will contain a newer version of the CLI inserted.

danielcrabtree commented 6 years ago

dotnet --version returns 2.1.2.

On executing those 4 commands, they all work, but the program crashes with the same error when using dotnet run. Using process explorer, it still seems to be using the same incorrect dll: D:\Users\[Username]\.nuget\packages\runtime.win-x64.microsoft.netcore.app\2.0.0\runtimes\win-x64\native\System.Private.CoreLib.dll.

I'm using Visual Studio 2017 15.5.2. I think this is the latest release version. By latest version, do you mean the latest preview version?

karelz commented 6 years ago

I don't understand why execution of the app would load anything from .nuget\packages directory. Maybe I am just naive ... Are you able to repro on clean machine/VM?

danielcrabtree commented 6 years ago

I found that if I remove <RuntimeIdentifier>win-x64</RuntimeIdentifier> from the csproj, dotnet run uses C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.3\System.Private.CoreLib.dll, and the infinite recursion error is gone.

However, without <RuntimeIdentifier>win-x64</RuntimeIdentifier>, the .exe is not generated. So the only way to run the program is via dotnet run.

I expected that I should be able to build / target any particular version of .NET Core from either the dotnet command line or Visual Studio and even have different programs running on different versions. But this doesn't seem to be the case, at least not with the point releases.

I was expecting to be able to set <TargetFramework>netcoreapp2.0</TargetFramework> to something more specific like netcoreapp2.0.3. Is this something that's going to be addressed in the future?

karelz commented 6 years ago

AFAIK, the EXE is generated only for self-contained apps. Not sure how that looks in CSPROJ files.

I don't think the behavior above is any special for point releases - at least I am pretty sure we didn't implement intentionally anything special.

@steveharter do you know who to loop in to shed some light here?

steveharter commented 6 years ago

When you compile\run with a RID (win-x64) the app is considered self-contained meaning it should not look in the shared location \Program Files\dotnet\. When running the published build, all framework\runtime files should be next to the .exe and loaded there. When not running the published build, then .nuget\package could be searched; that nuget location and others are specified in the .runtimeconfig.dev.json file.

steveharter commented 6 years ago

@danielcrabtree

I was expecting to be able to set netcoreapp2.0 to something more specific like netcoreapp2.0.3. Is this something that's going to be addressed in the future?

That is by design - the patch version is not included in the runtimeconfig.json because the host by default will "roll-forward" to the latest patch, so specifying 2.0 will roll forward to the latest patch version available (e.g. 2.0.3).

If you want to use a specific patch version (with no roll-forward), you can use dotnet --fx-version 2.0.3 app.dll

steveharter commented 6 years ago

@danielcrabtree, if you're running with a RID and standalone app \ exe, try running from the publish folder (e.g. C:\myconsoleapp\bin\Debug\netcoreapp2.0\win10-x64\publish). You may have to re-publish your app to get the latest framework binaries in there.

Also to debug, set COREHOST_TRACE=1 and then re-run your app to capture the output. It'll have information on whether the app is in standalone mode or not, and if not, then what version of the framework it is using and where it is located, in additional to the location of every assembly that will be loaded.

danielcrabtree commented 6 years ago

@steveharter

When running the published build, all framework\runtime files should be next to the .exe and loaded there.

Just tested publish and it does copy all the required framework/runtime files.

Unfortunately, it copies in the older / wrong libraries, presumably from .nuget\package as the files match those exactly. So running the published version produces the infinite recursion error.

The behavior is the same whether you publish in Visual Studio or via dotnet publish at the command line.

Also to debug, set COREHOST_TRACE=1 and then re-run your app to capture the output. It'll have information on whether the app is in standalone mode or not, and if not, then what version of the framework it is using and where it is located, in additional to the location of every assembly that will be loaded.

If I execute the published exe with COREHOST_TRACE=1, it says Executing in standalone mode. It also shows that it is loading the wrong 2.0.0 dlls from the publish folder:

Adding native asset 
runtimes/win-x64/native/System.Private.CoreLib.dll from 
runtime.win-x64.Microsoft.NETCore.App/2.0.0
...
System.Private.CoreLib from package: 
runtime.win-x64.Microsoft.NETCore.App, version: 2.0.0, 
relpath: runtimes/win-x64/native/System.Private.CoreLib.dll
...
Processing native/culture for deps entry 
[runtime.win-x64.Microsoft.NETCore.App, 2.0.0, 
runtimes/win-x64/native/System.Private.CoreLib.dll]
  Considering entry [runtime.win-x64.Microsoft.NETCore.App/2.0
.0/runtimes/win-x64/native/System.Private.CoreLib.dll] and 
probe dir []
    Local path query exists D:\Users\[username]\Desktop\U
rlGen\UrlGenerator\UrlGenerator\bin\Release\PublishOutput\Syst
em.Private.CoreLib.dll
    Probed deps dir and matched 'D:\Users\[username]\Desk
top\UrlGen\UrlGenerator\UrlGenerator\bin\Release\PublishOutput
\System.Private.CoreLib.dll'
...
Property TRUSTED_PLATFORM_ASSEMBLIES = 
D:\Users\[username]\Desktop\UrlGen\UrlGenerator\UrlGenerator\bin\Rele
ase\PublishOutput\System.Private.CoreLib.dll;
...
Property NATIVE_DLL_SEARCH_DIRECTORIES = D:\Users\[username]\Desktop\UrlGen\UrlGenerator\UrlGenerator\bin\Release\Publi
shOutput\;
steveharter commented 6 years ago

So in summary this is an issue with CLI build\publish of standalone apps where the newer runtime files are not used when running a non-published build or when publishing.

dotnet --version returns 2.1.2.

This returns the version of the SDK\CLI which in turn depends on 2.0.3 of the runtime.

@joperezr so dotnet build\publish is tied to the TFM (netcoreapp2.0 I presume), and not the version of the runtime the SDK\CLI depends on? Is there a way to control that, other than perhaps manually removing older copies of the nuget cache?

danielcrabtree commented 6 years ago

Is there a way to control that, other than perhaps manually removing older copies of the nuget cache?

Deleting the version in the nuget cache does not work. When you build, the nuget cache is repopulated with the wrong version and that is what gets used.

Here's what I think needs resolving:

1) I think that in all circumstances, the behavior should be consistent: whether you build or publish, whether you create a standalone app or not, whether you build via dotnet command line or Visual Studio, the same project should end up using the same runtime.

2) You should be able to control which version is used via csproj either via <TargetFramework> or an additional element that lets you specify the point release. This additional "point release" element could be set to "latest version" by default. So that things work as they are supposed to work now, unless you specify a particular point release.

I think (1) is the status quo, so should be fixed. I think (2) is important, because in the event a bug is introduced in a point release that breaks your application, you need some way to revert back to the earlier working version until a fix is released.

There does seem to be a general issue with different build technologies introducing different and incompatible versions of libraries and sourcing them from different places in different situations. I ran into this issue where the libraries in C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net471\lib\ and C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.1\ end up being used in the same project and they are actually different.

iga1976 commented 6 years ago

Same issue with SLES 12.2 x86_64. I am attaching the out file with the exception. If i get right from this issue thread, they say it is fixed in dotnet sdk 2.0.3 (?!) That is why I try to set the project target framework to 2.0.3 but when i run "dotnet clean" in the project dir i get error as follows: dotnet clean Microsoft (R) Build Engine version 15.4.8.50001 for .NET Core Copyright (C) Microsoft Corporation. All rights reserved.

/usr/share/dotnet/sdk/2.0.3/Sdks/Microsoft.NET.Sdk/build/Microsoft.NET.TargetFrameworkInference.targets(135,5): error : The current .NET SDK does not support targeting .NET Core 2.0.3. Either target .NET Core 2.0 or lower, or use a version of the .NET SDK that supports .NET Core 2.0.3. [/home/tony/sandbox/tsm/tdp/agents/sqlonlinux/mssqlsmoapp/mssqlsmoapp.csproj] Please clarify and let know if it is fixed or not, and, in any case, what to do. I am attaching the files with details. THANKS github_dotnet_clean.txt github_exception.txt

.

iga1976 commented 6 years ago

anyway how do you target app for 2.0.3 since dotnet new accepts only 2.0 This is from https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-new?tabs=netcore20

classlib

-f|--framework - Specifies the framework to target. Values: netcoreapp2.0 to create a .NET Core Class Library or netstandard2.0 to create a .NET Standard Class Library. The default value is netstandard2.0.

karelz commented 6 years ago

@iga1976 please check response above: https://github.com/dotnet/corefx/issues/24832#issuecomment-353442401 Did you try to just install 2.0.3 and run your app? (no app retargeting needed)

iga1976 commented 6 years ago

@karelz, Thanks for clarifying the targeting question. I posted "dotnet --info --version" out in dotnet/corefx#30208 It says 2.0.3. Pls take a look. The issue happens when i run: sudo bash dotnet app exit The issue does not happen if i run: sudo "dotnet app" Could you pls clarify this? Thanks

karelz commented 6 years ago

OK, let's keep the main discussion in dotnet/corefx#30208 - the right experts are involved there.

danmoseley commented 6 years ago

Incidentally @iga1976 you might want to upgrade to 2.1 as it is released and 2.0 will go out of support in the fall.

danmoseley commented 6 years ago

https://github.com/dotnet/corefx/issues/30593

tarekgh commented 6 years ago

@danmosemsft this is not related to dotnet/corefx#30593

tarekgh commented 6 years ago

https://github.com/dotnet/coreclr/issues/12668