-
Notifications
You must be signed in to change notification settings - Fork 127
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
Linker fails when resolving type reference in sweep step #2260
Comments
I'll have to dig into this deeper. The immediate fix can be to go back to calling |
This uncovers a null ref in sweepstep. The test is order dependent: - Assembly (librarywithnonemtpy) has a virtual method which referes to type from second library (library). This processes the type reference. - The type is removed from library - The virtual method is re-processed again -> hits a type def which does not belong to any assembly/scope For this to happen the virtual method must be processed after the type has been removed. This also requires the method to be meant for removal later on (the body will be rewritten to throw), since otherwise the type would have been marked. This also requires the library with the removed type to be kept (so something else in it must be kept).
The full problem description Setup The assemblies are loaded by the linker in this order (this is easy to achieve). MarkStep
SweepStep
Before #2234 the type resolution didn't go through the context cache. So the second resolution of the type-ref for Additional notes:
|
I don't know the right solution yet. I'm tempted to say that we should run the There's still a question of copyused assemblies - in the new behavior after #2234 it's likely they can also run into the same problem - but for those there's no rewriter which will remove the broken type-refs. We actually want to keep the broken type-refs in that case. This is also related to another issue with Trimming+R2R. In the copyused mode, we produce broken type-refs, but R2R can't process these - the R2R compiler fails on them. |
I've added a (disabled) test for this issue (as a simple repro): #2263 |
Basically a workaround for dotnet#2260. This simply goes back to using the `Resolve` method and avoid the cache for now.
Workaround is here: #2264 |
Thanks for investigating this @vitek-karas! My read of your notes is that after sweeping types in We do still use the cache later in Whether |
This uncovers a null ref in sweepstep. The test is order dependent: - Assembly (librarywithnonemtpy) has a virtual method which referes to type from second library (library). This processes the type reference. - The type is removed from library - The virtual method is re-processed again -> hits a type def which does not belong to any assembly/scope For this to happen the virtual method must be processed after the type has been removed. This also requires the method to be meant for removal later on (the body will be rewritten to throw), since otherwise the type would have been marked. This also requires the library with the removed type to be kept (so something else in it must be kept).
Basically a workaround for dotnet#2260. This simply goes back to using the `Resolve` method and avoid the cache for now.
Basically a workaround for #2260. This simply goes back to using the `Resolve` method and avoid the cache for now.
The workaround (back to original behavior) is merged now. Discussed with @sbomer, outcome:
Proposal
Going forward consider doing also:
|
I think it'll still need to
I think you are saying that with the proposed approach, walking the types/methods won't visit assemblyrefs, so we need to separately sweep them in the second step. And before that's done, the graph will be in an inconsistent state - is that right? What did you mean by "avoid scanning the graph"? |
It might be necessary to do this, but only in cases where the type-ref point to type-forwarder, which is unresolvable. We would still like to remove the type-forwarder in this case, but
Sorry, bad choice of words from me. It's probably easier to say that during sweeping the graph is inconsistent - so it should be treated as such. Meaning that for example we should not be using it to figure out unused assembly refs. |
Sorry, I meant cases where the type-forwarder is resolvable, but points to an assembly that wasn't already referenced by the assembly that contains the typeref.
Good point - I guess today we just keep the original typeref pointing at the removed forwarder, but it might be better to update it to point directly at the target assembly. |
This uncovers a null ref in sweepstep. The test is order dependent: - Assembly (librarywithnonemtpy) has a virtual method which referes to type from second library (library). This processes the type reference. - The type is removed from library - The virtual method is re-processed again -> hits a type def which does not belong to any assembly/scope For this to happen the virtual method must be processed after the type has been removed. This also requires the method to be meant for removal later on (the body will be rewritten to throw), since otherwise the type would have been marked. This also requires the library with the removed type to be kept (so something else in it must be kept). Commit migrated from dotnet/linker@43fb979
Basically a workaround for dotnet/linker#2260. This simply goes back to using the `Resolve` method and avoid the cache for now. Commit migrated from dotnet/linker@a9888c2
This was caused by #2234.
The problem is that first we call
SweepAssemblyReferences
on pretty much all assemblies. This will eventually call intoAssemblyReferenceCorrector.UpdateScopeOfTypeReference
which callLinkContext.TryResolve
. In the failing case the type reference first points to "netstandard". It gets resolved to "System.Collections" and the type reference instance is overwritten to point to that. And the TryResolve cache remembers that this typeref points to "System.Collection" type-def.Later on - we call ProcessAssemblyAction which in turn calls SweepAssembly on "System.Collection", this will remove the type-def from the assembly (not marked). This means that the type-def's Scope is reset to 'null'.
Now we eventually call ProcessAssemblyAction on the assembly which contained the type-ref. This will again end up calling
AssemblyReferenceCorrector.UpdateScopeOfTypeReference
andTryResolve
on the same type-ref. Now the result is cached, so it returns the type-def which is now pointing tonull
scope. We try to "import" this type-def into the target assembly, and this fails, since it doesn't know where type type-def comes from.Before the change, the
TryResolve
was a direct call toResolve
. In the first time around - it would return the same value (type-def). But second time around, the type-ref doesn't resolve anymore, since the type it points to has been removed, toResolve
returned null - and SweepStep has handling for this case - it instead resolves the assembly ref of the type-ref - which now points to "System.Collection" (was fixed up during the first pass) - so it imports that scope and leaves the type-ref pointing to that scope. This means it never actually relies on the type-ref to resolve - which it won't. In this case it's writing an unresolvable type-ref.The text was updated successfully, but these errors were encountered: