-
Notifications
You must be signed in to change notification settings - Fork 11
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
Bug: System.Runtime.CompilerServices.Unsafe 6.1.0 breaking changes: Entry Point was Not Found Exception #184
Comments
I have found a workaround which works with v6.1 of nuget: if I switch the "Code Optimization" off in Visual Studio/MSBuild for 2 projects then it starts working again. It feels that dotnet nuget tool also plays part in it as it does not reliably/repeatably update packages, I found some inconsitencies as to when it installs v6.0 vs v6.1. Finally, I am wondering if there were changes in the compiler itself as I also had an unusual intermittent issue in one of the xaml/wpf forms where xaml compiler (all of the sudden) would not 'bind by text' to an event handler (as specified in xaml), but when I assigned the event in the code-behind constructor everything was fine. Needless to say, this code worked/compiled perfectly for years without a glitch, ie this wasn't some new code with bugs. It feels, after 25 years in production, C#/VS and the .Net stack still have a long way to go to become a reliable/repetitive platform. |
Hello @moltco. Thank you for your report of this issue, and I'm sorry you are facing this problem in updating dependencies. I've seen two causes for this issue before with
For reference, here's the diff in IL between the 6.0 and 6.1 version of this assembly for .NETFramework. I don't see anything on its own that would explain a regression here. |
Does your app work fine when you replace |
The runtime assumes matching types for things like calling interface methods. If you introduce a type mismatch using invalid use of |
Hi both, thank you so much for your insights and suggestions. My code is fairly simple - if memory serves well, the only reason I use Usafe.As is because c# 7 does not allow default interface implementation and it was struggling to cast in a normal (safe) way when there is a generic type involved. I will have to check the code again but from memory it has a base class that provides default interface implementation and then other classes inherit that and override functionality when required. The normal casts worked in a simplistic example of this but when I introduced generic that is also based on interface with default implementation it could not figure out that these can be cast as well. So when I had something like bindingRedirects <assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1"/>
</dependentAssembly> I have manually removed the bindingRedirect for Unsafe in the past as I was trying to troubleshoot and wasn't sure if bindingRedirect was actually needed so I was hoping VS will be clever enough to put a 'fresh' redirect if it was needed (but it didn't) <!-- <dependentAssembly> -->
<!-- <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/> -->
<!-- <bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0"/> -->
<!-- </dependentAssembly> --> If you suspect bindingRedirects as a possible cause, then it could be part of the toolchain that does not update these 'automatically' as it shoud? Unsure if this is done by VS/MSBuild/Nuget. EntryPoint issue 85990 [https://github.com/dotnet/runtime/issues/85990] This issue looks similar to what I am doing in a way but the suggestion of object becoming null half-way through the operation and therefore not being able to cast doesn't sound right to me at least in this case for three reasons: a) everything works if the code runs in 'debug' mode, b) everything runs if code is compiled to Release without 'code optimizations', c) everything works in unit tests as well. If it was a timing/race issue in my code then it would presentitself at least once in Debug or with 'unoptimized' code. To put it in context, the line where my code breaks is before any real 'work' starts, it is a simple async validation routine that checks that object (thas is Usafe.As cast in the background) has required parameters so it's not as if the object would be disposed or a task completed midway and therefore releasing the object or making it null - only if the compiler optimization decided it could release the object for some reason. |
This suggests that you are doing invalid unsafe cast. Could you please share a small working repro for what you are trying to do? |
I have tried to create a simplified version of the simplified code here https://github.com/moltco/vs-unsafe I have added some tests and code that illustrate usage and where This code has been created quite a while back and I don't recall everything in detail but, as I mentioned before, without Unsafe.As the compiler was complaining. I recall doing quite a few tests using different c# inheritance approaches which didn't work but I don't recall detail. In short, I was trying to achieve a flexible design so I can have default or derived implementations of IListManager and IListEntry and be able to reference concrete implementation by the interface (e.g. DoWork(IListManager object)) without having to cast or check types. Personally, I am not a fan of that code and would be very happy to ditch it if there was a better solution within the constraints of c# v7. Please let me know if you have any questions or suggestions. |
Thank you for sharing a repro.
The C# compiler was trying to tell you that there is no situation where the cast can succeed. You can suppress the C# compiler by casting to
This will make the source compile, but then you get an InvalidCastException at runtime:
Your use of
The weird behaviors that you are seeing is a typical manifestation of runtime instability. You may also see weird crashes, hangs or data corruptions in unrelated code. |
Thanks... Would you know why is the cast considered not possible if the implementation explicitly implements the interface (or inherits implementation)? Or is there another design/pattern that could be used to achieve the same? |
In .NET, all implemented interfaces have to be explicitly declared on a type itself or on a parent type.
In .NET 5+, we have introduced a new feature to implement interfaces dynamically https://learn.microsoft.com/en-us/samples/dotnet/samples/idynamicinterfacecastable/ . This feature is not available in .NET Framework. It is the only way that I can think of how a type can implement an interface that is not explicitly declared on it. |
I believe all objects in my repro follow the correct usage example above - all classes implement interface either via inheritance or directly, e.g. // implements via inheritance
public class ExampleListManager :
ListManagerWFO<ExampleListEntry>, // base class that implements IListManager
IUndo<ExampleListEntry>,
IFilterProvider<ExampleListEntry> // implements via inheritance and interface directly
public class ExampleListEntry :
BaseListEntry, // inheritance
IListEntry, // direct interface implementation
IFilterable, ISelectable,
ISomethingElse, ISomethingElse2 I have spent some more time on the example code and have produced a new brach in the repo - can you please check the The key issue with that code is that .NET is not picking the correct implementation of code in some scenarios, i.e. not picking implementation in the most recent object/ancestor when accessing objects via the interface. Perhaps' that is intended (?) but I can't see why would anyone prefer to access the parent 'by default' instead of the current object. Note: with Usafe.As cast - this works as expected, so at least we can say that the behaviour between cast and Usafe.As is not consistent? If you check the BindingList<IListEntry> IListManager<IListEntry>.Records
{
get => Records as BindingList<IListEntry>;
set => Records = value as BindingList<TRec>;
}
// was:
// BindingList<IListEntry> IListManager<IListEntry>.Records
// {
// get => Unsafe.As<BindingList<IListEntry>>(Records);
// set => Records = Unsafe.As<BindingList<TRec>>(value);
// } After this change, I can get some calls to work correctly, e.g. in
This works OK - so far, so good. However, when I pass this same If one puts a breakpoint on that call and inspect the lists, the various implementations of Records are visible, including the correct one from the concrete object passed with 3 records. I guess, in The apparent need to explicitly cast objects on every call feels counter to the concept of interfaces; ie what is the benefit of having interfaces if I need to hard-code cast on every line of code? If I had several concrete implementations, I would need to duplicate same code many times to be able to hard-code cast for each new concrete implementation. Finally, re Dynamic Interfaces: as all objects implement interfaces explicitly or via inheritance, this does not sound to me like use case for Dynamic Interfaces - everything is 'known' from the start and I should not need to explicitly direct the compiler to use the passed object to find implementation of interface, that sounds like something that should be the default behaviour (?) |
This line The interface implementations and virtual method implementations are independent in .NET. In typical C# code, the C# compiler uses public method to implement interfaces for convenience. This behavior can be suppressed, and the virtual method implementations can be made independent on the interface method implementations like you have done in your example. |
I use System.Runtime.CompilerServices.Unsafe 6.1.0 in a .NET481 solution which uses Usafe.As to cast interface to a concrete type; currently I use VS 2022 17.10 and 17.12 on Win11 Pro.
The code works perfectly/as-exected with System.Runtime.CompilerServices.Unsafe 6.0.0 package.
When I upgrade to 6.1.0 I start getting "Entry Point was Not Found" exception when methods try accessing some of the cast lists (in this particular case it is a Unsafe.As<BindingList> cast).
The issue does not happen when in Debug mode, only when compiled as Release which makes it weirder. It also happens in between an if check and accessing the list. The code roughly goes as:
The error log shows:
Sadly my codebase is too large to share or to be able to easily extract code to reproduce issue and share here. I hope since this is a minor version update on a maintenance package that the changes are fairly small and the description above helps in triaging and identifying the root cause of the issue.
The text was updated successfully, but these errors were encountered: