Hello,

Below is a proposal for some changes to how mono handles assemblies with strong 
names during loading.


Cheers,
Aleksey Kliger


Strict strong names assembly loading proposal


Background: assembly names on .NET
=================================
Assemblies on .NET may optionally have a strong name: which includes a simple 
name, a culture, a version number and a public key token. Two names are equal 
when all the components are equal.

Assembly bindings, BCL and Facades
================================
There is a separate more complicated story about configuration files that can 
remap requests for certain assembly versions to others. Additionally, Mono has 
special rules for BCL assemblies that ship as part of Mono itself and for 
Facades. It is interesting and important to get right, but somewhat obscures 
the issue at hand. From this point forward, assume that any remapping of 
requests by all these mechanisms have already happened.

Loading strong named assemblies on .NET
====================================
If there is a request for an assembly with a strong name (either statically - 
via a reference from another assembly, or dynamically via reflection), then the 
names of any assembly images found using the usual search mechanism are 
examined and if that assembly image has an incorrect version or public key, it 
is skipped and the search continues.

Loading strong named assemblies on Mono
======================================
Currently if there is a request for a strong named assembly the following steps 
happen in Mono until one of them returns true.:
1. We look in the search_path of the current application domain 
(ApplicationBase suffixed by each subdir in PrivateBinPath)
2. We look in the MONO_PATH
3. We look in the GAC
4. We look in the default path (typically $prefix/lib/mono/4.5/ and its 
Facades/ subdir)
5. We call back into managed code to the application domain's AssemblyResolve 
event delegate
6. We look in the search_path of the current application domain
7. We look in the MONO_PATH
8. We look in the GAC
9. We look in the base directory of the requesting assembly
10. We look in the default path

(Steps 6-8, and 10 are redundant, but nonetheless this is what we do. I'm not 
planning on changing this right now.)

Only the GAC steps check strong names (indirectly - the directory structure of 
the GAC encodes public key tokens and version numbers).
In all the other steps if we find an image whose filename matches the 
assembly's simple name (ie: "System.Reflection.dll" for "System.Reflection") we 
accept it and don't look at the version or the public key at all.

When Mono's mechanism is not a problem
======================================
The Xamarin.iOS, Xamarin.Mac, and Xamarin.Android products have a limitation 
that multiple versions of the same assembly can't be used.
They copy all the assemblies that an app will need to a single directory, AOT 
(if applicable) all the assemblies and expect all assembly resolution to 
succeed and only look at the chosen set of assemblies. (ie they don't use the 
GAC or domains and generally set things up so that Mono only looks in a single 
directory).
I'm told that support has instructions for a workaround for customers who run 
into this limitation (can't have multiple versions in one app).

When Mono's mechanism is a problem
==================================
On the desktop it is possible (and some frameworks rely on) loading different 
versions of the same assembly into the same application domain.
Because we take the first file that matches, this can sometimes result in 
silently substituting an unexpected version of an assembly. This can result in 
incorrect code execution.

We have a couple of bugzilla bugs about the issue over the years:
• https://bugzilla.xamarin.com/show_bug.cgi?id=580 from 2011
• https://bugzilla.xamarin.com/show_bug.cgi?id=49721 from 2016
originally https://bugzilla.xamarin.com/show_bug.cgi?id=47353

Proposal
========
1. We add a command line argument --assembly-loader=[strict,legacy] Defaulting 
to strict.
In strict mode: Each of the assembly resolution steps, above, checks that any 
assembly image with the right filename also has the right public key and 
version.
In legacy mode: We keep mono's existing behavior.
2. In addition we rename the existing feature flag 
--enable-minimal=assembly_remapping to --enable-minimal=desktop_loader to 
disables strict mode (and the existing feature of assembly_remapping that 
disables the special remapping of BCL assembly versions). The --assembly-loader 
command line option will be silently accepted and ignored. So that products can 
continue to use the existing Mono behavior.
Think of disabling the desktop loader as "I know precisely which assemblies I 
need and I put them all in one place."
 

_______________________________________________
Mono-devel-list mailing list
Mono-devel-list@lists.dot.net
http://lists.dot.net/mailman/listinfo/mono-devel-list

Reply via email to