Skip to content

Validate modules that are part of a version bubble#31822

Closed
MichalStrehovsky wants to merge 2 commits into
dotnet:masterfrom
MichalStrehovsky:mvidValidate
Closed

Validate modules that are part of a version bubble#31822
MichalStrehovsky wants to merge 2 commits into
dotnet:masterfrom
MichalStrehovsky:mvidValidate

Conversation

@MichalStrehovsky
Copy link
Copy Markdown
Member

This adds validation that ensures the modules that we compiled as part of the large version bubble are the same modules that we see at runtime. If a different module is detected at runtime a FileLoadException will be thrown.

This includes the change to the runtime, change to the crossgen2 compiler, and change to r2rdump.

Cc @dotnet/crossgen-contrib

This adds validation that ensures the modules that we compiled as part of the large version bubble are the same modules that we see at runtime. If a different module is detected at runtime a FileLoadException will be thrown.

This includes the change to the runtime, change to the crossgen2 compiler, and change to r2rdump.
@jkotas
Copy link
Copy Markdown
Member

jkotas commented Feb 5, 2020

Could you please add a test(s) for this? I know such tests are not pretty (like the current R2R versioning test), but I think it is important to have at least some coverage for it.


// Check our own assembly first
GetAppDomain()->CheckForMismatchedNativeImages(&spec, &pVersionInfo->sourceAssembly.mvid);
GetLoaderAllocator()->CheckForMismatchedNativeImages(&spec, &pVersionInfo->sourceAssembly.mvid);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think that loader allocator is the right place to attach this to. If you have multiple (non-unlodable) AssemblyLoadContexts, all of them will share the one loader allocator, but it should be possible to load different versions of assemblies into each one.

In other words, loader allocator is lifetime unit; but this should be attached to assembly binding unit.

I know that the assembly loader is a mess and so the best way to do this may not be obvious.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davidwrighton could you help me find a home for this? I kicked it out of AppDomain based on your feedback, but it can't live in LoaderAllocator either.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have looked around:

  • The unmanaged equivalent of AssemblyLoadContext is ICLRPrivBinder interface
  • ICLRPrivBinder interface is implemented by several actual types
  • There does not seem to be a good way to share stuff between these actual types

I think we need to:

  • Create unmanaged class AssemblyLoadContext
  • Put it between the managed AssemblyLoadContext and ICLRPrivBinder (e.g. the unmanaged AssemblyLoadContext is going to have ICLRPrivBinder* m_pCLRBinder field)
  • Attach this structure to it

@elinor-fung @vitek-karas Thoughts?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that would be reasonable. However, the assembly loader is such a tangle of indirection that I'm not sure how nice adding another layer would be. Potential related (existing) weirdness: the managed default AssemblyLoadContext class is created on demand, so default binder (and corresponding unmanaged AssemblyLoadContext) would exist without it, and the WinRT binder has no dedicated managed ALC representation

There is also the ApplicationContext instance (on each binder implementation). It has things like the cache of loaded managed assemblies, so I think it is kind of representative of the ALC as well. It might be fitting to have the mapping of the native image names/mvids there? It is currently only exposed on the concrete implementations (not ICLRPrivBinder) though.

The CLRPrivBinderCoreCLR and CLRPrivBinderAssemblyLoadContext implementations do have a lot of duplication (a bit less so for CLRPrivBinderWinRT). Adding a shared base for them might be nice in general.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I remember correctly we already discussed the fact that the interfaces (IClrPrivBinder) are not necessary and should be mostly removed (especially the fact that they are defined the "COM" way). I think that the solution here could be that we replace the IClrPrivBinder with an abstract base class, which can then store whatever additional state we need. It would also allow for an easier way to share code between the binders (as @elinor-fung notes, there's quite a bit of overlap in some cases).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have done some minimal refactoring to introduce AssemblyLoadContext base class in: #32097

publicKeyOrToken: metadataBuilder.GetOrAddBlob(publicKeyOrToken),
publicKeyOrToken: publicKeyOrToken == null ? default : metadataBuilder.GetOrAddBlob(publicKeyOrToken),
flags: assemblyFlags,
hashValue: default(BlobHandle) /* TODO */);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we just use the hashValue here to store the MVID instead of a new node type?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless of course we have plans to use hashValue for something else, but the list of assemblies written in this MD blob seem to only be used for the version bubble stuff.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This table only has references to assemblies that don't exist in the original AssemblyRef table. There's a complex scheme of how to make sense of it.

We can't modify the original AssemblyRef table because it's visible to user code. We would need an alternative storage mechanism for those entries anyway - people do weird stuff with user visible parts of these things - e.g. I've seen an app that used the assembly's public key to encrypt network traffic 😱).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok Thanks Michal for the clarification

@davidwrighton
Copy link
Copy Markdown
Member

When we update this PR, we need to add #35231 (comment) part 4 to this PR's code.

@stephentoub
Copy link
Copy Markdown
Member

@MichalStrehovsky, are you still working on this? Hasn't been updated in 8 months. Thanks.

@ghost ghost locked as resolved and limited conversation to collaborators Dec 10, 2020
@MichalStrehovsky MichalStrehovsky deleted the mvidValidate branch September 30, 2022 04:54
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants