diff --git a/pkg/Microsoft.Private.PackageBaseline/packageIndex.json b/pkg/Microsoft.Private.PackageBaseline/packageIndex.json index cff47e9ba910..795573e32150 100644 --- a/pkg/Microsoft.Private.PackageBaseline/packageIndex.json +++ b/pkg/Microsoft.Private.PackageBaseline/packageIndex.json @@ -3913,13 +3913,15 @@ "System.Reflection.MetadataLoadContext": { "StableVersions": [ "4.6.0", - "4.7.0" + "4.7.0", + "4.7.1" ], "BaselineVersion": "4.7.0", "InboxOn": {}, "AssemblyVersionInPackageVersion": { "4.0.0.0": "4.6.0", - "4.0.1.0": "4.7.0" + "4.0.1.0": "4.7.0", + "4.0.1.1": "4.7.1" } }, "System.Reflection.Primitives": { diff --git a/pkg/test/frameworkSettings/netcoreapp3.1/settings.targets b/pkg/test/frameworkSettings/netcoreapp3.1/settings.targets index 42748342b17e..fe177695deb9 100644 --- a/pkg/test/frameworkSettings/netcoreapp3.1/settings.targets +++ b/pkg/test/frameworkSettings/netcoreapp3.1/settings.targets @@ -1,25 +1,9 @@ - netcoreapp3.1 - 3.1 $(MicrosoftNETCoreAppPackageVersion) - - - - - diff --git a/src/System.Reflection.MetadataLoadContext/Directory.Build.props b/src/System.Reflection.MetadataLoadContext/Directory.Build.props index 75494287ea74..6ad1324afccd 100644 --- a/src/System.Reflection.MetadataLoadContext/Directory.Build.props +++ b/src/System.Reflection.MetadataLoadContext/Directory.Build.props @@ -1,7 +1,8 @@  - 4.0.1.0 + 4.7.1 + 4.0.1.1 Open \ No newline at end of file diff --git a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/MetadataLoadContext.Loading.cs b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/MetadataLoadContext.Loading.cs index 6dbfe2dc1fb8..30baa5eec352 100644 --- a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/MetadataLoadContext.Loading.cs +++ b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/MetadataLoadContext.Loading.cs @@ -36,7 +36,7 @@ private RoAssembly LoadFromStreamCore(Stream peStream) { pkt = defNameData.PublicKey.ComputePublicKeyToken(); } - RoAssemblyName defName = new RoAssemblyName(defNameData.Name, defNameData.Version, defNameData.CultureName, pkt); + RoAssemblyName defName = new RoAssemblyName(defNameData.Name, defNameData.Version, defNameData.CultureName, pkt, defNameData.Flags); RoAssembly winner = _loadedAssemblies.GetOrAdd(defName, candidate); if (winner == candidate) diff --git a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/PathAssemblyResolver.cs b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/PathAssemblyResolver.cs index c2c7948c46c5..94bea3a5ffd3 100644 --- a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/PathAssemblyResolver.cs +++ b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/PathAssemblyResolver.cs @@ -77,8 +77,10 @@ public override Assembly Resolve(MetadataLoadContext context, AssemblyName assem candidateWithSamePkt = assemblyFromPath; } } - // If assemblyName does not specify a PublicKeyToken, then still consider those with a PublicKeyToken. - else if (candidateWithSamePkt == null && pktFromName.IsEmpty) + // If assemblyName does not specify a PublicKeyToken, or assemblyName is marked 'Retargetable', + // then still consider those with a PublicKeyToken and take the highest version available. + else if ((candidateWithSamePkt == null && pktFromName.IsEmpty) || + ((assemblyName.Flags & AssemblyNameFlags.Retargetable) != 0)) { // Pick the highest version. if (candidateIgnoringPkt == null || assemblyNameFromPath.Version > candidateIgnoringPkt.GetName().Version) diff --git a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Ecma/EcmaHelpers.cs b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Ecma/EcmaHelpers.cs index a6ecedc4d220..f84ce3b9c61b 100644 --- a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Ecma/EcmaHelpers.cs +++ b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Ecma/EcmaHelpers.cs @@ -20,12 +20,13 @@ public static RoAssemblyName ToRoAssemblyName(this AssemblyReferenceHandle h, Me string culture = a.Culture.GetStringOrNull(reader); byte[] pkOrPkt = a.PublicKeyOrToken.GetBlobBytes(reader); AssemblyFlags flags = a.Flags; + AssemblyNameFlags assemblyNameFlags = Helpers.ConvertAssemblyFlagsToAssemblyNameFlags(flags); if ((flags & AssemblyFlags.PublicKey) != 0) { pkOrPkt = pkOrPkt.ComputePublicKeyToken(); } - return new RoAssemblyName(name, version, culture, pkOrPkt); + return new RoAssemblyName(name, version, culture, pkOrPkt, assemblyNameFlags); } public static CoreType ToCoreType(this PrimitiveTypeCode typeCode) diff --git a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Helpers.cs b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Helpers.cs index 78f1e50174cf..c633fc029fd2 100644 --- a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Helpers.cs +++ b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/Helpers.cs @@ -154,6 +154,18 @@ public static byte[] ComputePublicKeyToken(this byte[] pkt) return an.GetPublicKeyToken(); } + public static AssemblyNameFlags ConvertAssemblyFlagsToAssemblyNameFlags(AssemblyFlags assemblyFlags) + { + AssemblyNameFlags assemblyNameFlags = AssemblyNameFlags.None; + + if ((assemblyFlags & AssemblyFlags.Retargetable) != 0) + { + assemblyNameFlags |= AssemblyNameFlags.Retargetable; + } + + return assemblyNameFlags; + } + // // Note that for a top level type, the resulting ns is string.Empty, *not* null. // This is a concession to the fact that MetadataReader's fast String equal methods @@ -350,7 +362,7 @@ public static RoAssemblyName ToRoAssemblyName(this AssemblyName assemblyName) // as the original is wide open to tampering by anyone. byte[] pkt = assemblyName.GetPublicKeyToken().CloneArray(); - return new RoAssemblyName(assemblyName.Name, assemblyName.Version, assemblyName.CultureName, pkt); + return new RoAssemblyName(assemblyName.Name, assemblyName.Version, assemblyName.CultureName, pkt, assemblyName.Flags); } public static byte[] ToUtf8(this string s) => Encoding.UTF8.GetBytes(s); diff --git a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/RoAssemblyName.cs b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/RoAssemblyName.cs index 1d787dd427a1..67631b7720d8 100644 --- a/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/RoAssemblyName.cs +++ b/src/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/General/RoAssemblyName.cs @@ -25,13 +25,14 @@ internal sealed class RoAssemblyName : IEquatable public string CultureName { get; } public byte[] PublicKeyToken; - // We don't need to store the flags. The only flag allowed in an ECMA-335 AssemblyReference is the "PublicKey" bit. Since - // RoAssemblyName always normalizes to the short form public key token, that bit would always be 0, and hence the flag enum as a whole - // would always be zero. + // We store the flags to support "Retargetable". + // The only flag allowed in an ECMA-335 AssemblyReference is the "PublicKey" bit. Since + // RoAssemblyName always normalizes to the short form public key token, that bit would always be 0. + public AssemblyNameFlags Flags { get; } private static readonly Version s_Version0000 = new Version(0, 0, 0, 0); - public RoAssemblyName(string name, Version version, string cultureName, byte[] publicKeyToken) + public RoAssemblyName(string name, Version version, string cultureName, byte[] publicKeyToken, AssemblyNameFlags flags) { // We forcefully normalize the representation so that Equality is dependable and fast. Debug.Assert(name != null); @@ -40,6 +41,7 @@ public RoAssemblyName(string name, Version version, string cultureName, byte[] p Version = version ?? s_Version0000; CultureName = cultureName ?? string.Empty; PublicKeyToken = publicKeyToken ?? Array.Empty(); + Flags = flags; } public string FullName => ToAssemblyName().FullName; @@ -57,6 +59,9 @@ public bool Equals(RoAssemblyName other) return false; if (!(((ReadOnlySpan)PublicKeyToken).SequenceEqual(other.PublicKeyToken))) return false; + + // Do not compare Flags; we do not want to treat AssemblyNames as not being equal due to Flags. + return true; } @@ -71,6 +76,7 @@ public AssemblyName ToAssemblyName() Name = Name, Version = Version, CultureName = CultureName, + Flags = Flags, }; // We must not hand out our own copy of the PKT to AssemblyName as AssemblyName is amazingly trusting and gives untrusted callers diff --git a/src/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestData.cs b/src/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestData.cs index ea532403db41..940624bcfefa 100644 --- a/src/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestData.cs +++ b/src/System.Reflection.MetadataLoadContext/tests/src/TestUtils/TestData.cs @@ -3011,5 +3011,69 @@ internal static class TestData "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAA" ); + + //// Metadata version: v4.0.30319 + //.assembly extern retargetable mscorlib + // { + // .publickeytoken = (7C EC 85 D7 BE A7 79 8E ) // |.....y. + // .ver 2:0:5:0 + //} + //.assembly SimpleAssembly + // { + // .custom instance void [mscorlib] + // System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) + // .custom instance void [mscorlib] + // System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx + // 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. + // // --- The following custom attribute is added automatically, do not uncomment ------- + // // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) + // .hash algorithm 0x00008004 + // .ver 0:0:0:0 + //} + //.module SimpleAssembly.dll + //// MVID: {DCD1E0C4-4B2E-4E02-952F-DA6B0600F478} + //.imagebase 0x10000000 + //.file alignment 0x00000200 + //.stackreserve 0x00100000 + //.subsystem 0x0003 // WINDOWS_CUI + //.corflags 0x00000001 // ILONLY + //// Image base: 0x03550000 + public static readonly string s_RetargetableAssemblySimpleName = "SimpleAssembly"; + public static readonly byte[] s_RetargetableImage = Convert.FromBase64String( + "TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFt" + + "IGNhbm5vdCBiZSBydW4gaW4gRE9TIG1vZGUuDQ0KJAAAAAAAAABQRQAATAEDAP1PYF0AAAAAAAAAAOAAIiALATAAAAQAAAAGAAAAAAAAfiMAAAAgAAAAQAAA" + + "AAAAEAAgAAAAAgAABAAAAAAAAAAEAAAAAAAAAACAAAAAAgAAAAAAAAMAQIUAABAAABAAAAAAEAAAEAAAAAAAABAAAAAAAAAAAAAAACwjAABPAAAAAEAAAMAC" + + "AAAAAAAAAAAAAAAAAAAAAAAAAGAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAACAAAAAAAAAAAAAAA" + + "CCAAAEgAAAAAAAAAAAAAAC50ZXh0AAAAhAMAAAAgAAAABAAAAAIAAAAAAAAAAAAAAAAAACAAAGAucnNyYwAAAMACAAAAQAAAAAQAAAAGAAAAAAAAAAAAAAAA" + + "AABAAABALnJlbG9jAAAMAAAAAGAAAAACAAAACgAAAAAAAAAAAAAAAAAAQAAAQgAAAAAAAAAAAAAAAAAAAABgIwAAAAAAAEgAAAACAAUAXCAAANACAAABAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACICKAQAAAoAKgAAAEJTSkIBAAEAAAAAAAwAAAB2NC4wLjMwMzE5" + + "AAAAAAUAbAAAAPAAAAAjfgAAXAEAABABAAAjU3RyaW5ncwAAAABsAgAABAAAACNVUwBwAgAAEAAAACNHVUlEAAAAgAIAAFAAAAAjQmxvYgAAAAAAAAACAAAB" + + "VxQAAAkAAAAA+gEzABYAAAEAAAAGAAAAAgAAAAEAAAABAAAABAAAAAMAAAABAAAAAQAAAAAAdAABAAAAAAAGADAApwAGAFAApwAGABwAlAAPAMcAAAAGAPEA" + + "hwAGAPgA1gAAAAAAAQAAAAAAAQABAAEAEADpABMAFQABAAEAFgBuABkAUCAAAAAAhhiOAAYAAQAJAI4AAQARAI4ABgAZAI4ACgApAI4ABgAuAAsAHQAuABMA" + + "JgAuABsARQAEgAAAAAAAAAAAAAAAAAAAAAABAQAAAgAAAAUAAAAAAQAAEAAKAAAAAAAAAAA8TW9kdWxlPgBtc2NvcmxpYgBSZWxvY2F0ZQBEZWJ1Z2dhYmxl" + + "QXR0cmlidXRlAENvbXBpbGF0aW9uUmVsYXhhdGlvbnNBdHRyaWJ1dGUAUnVudGltZUNvbXBhdGliaWxpdHlBdHRyaWJ1dGUATXlPYmoAU2ltcGxlQXNzZW1i" + + "bHkuZGxsAFN5c3RlbQAuY3RvcgBTeXN0ZW0uRGlhZ25vc3RpY3MAU3lzdGVtLlJ1bnRpbWUuQ29tcGlsZXJTZXJ2aWNlcwBEZWJ1Z2dpbmdNb2RlcwBTeXN0" + + "ZW0uQ29sbGVjdGlvbnMATXlDbGFzcwBPYmplY3QAQml0QXJyYXkAU2ltcGxlQXNzZW1ibHkAAAAAAMTg0dwuSwJOlS/aawYA9HgABCABAQgDIAABBSABARER" + + "CHzshde+p3mOAwYSGQgBAAgAAAAAAB4BAAEAVAIWV3JhcE5vbkV4Y2VwdGlvblRocm93cwEIAQAHAQAAAAAAAFQjAAAAAAAAAAAAAG4jAAAAIAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAABgIwAAAAAAAAAAAAAAAF9Db3JEbGxNYWluAG1zY29yZWUuZGxsAAAAAAD/JQAgABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAABABAAAAAYAACAAAAAAAAAAAAAAAAAAAABAAEAAAAwAACAAAAAAAAAAAAAAAAAAAABAAAAAABIAAAAWEAAAGQCAAAAAAAA" + + "AAAAAGQCNAAAAFYAUwBfAFYARQBSAFMASQBPAE4AXwBJAE4ARgBPAAAAAAC9BO/+AAABAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAQAAAACAAAAAAAAAAAA" + + "AAAAAAAARAAAAAEAVgBhAHIARgBpAGwAZQBJAG4AZgBvAAAAAAAkAAQAAABUAHIAYQBuAHMAbABhAHQAaQBvAG4AAAAAAAAAsATEAQAAAQBTAHQAcgBpAG4A" + + "ZwBGAGkAbABlAEkAbgBmAG8AAACgAQAAAQAwADAAMAAwADAANABiADAAAAAsAAIAAQBGAGkAbABlAEQAZQBzAGMAcgBpAHAAdABpAG8AbgAAAAAAIAAAADAA" + + "CAABAEYAaQBsAGUAVgBlAHIAcwBpAG8AbgAAAAAAMAAuADAALgAwAC4AMAAAAEYAEwABAEkAbgB0AGUAcgBuAGEAbABOAGEAbQBlAAAAUwBpAG0AcABsAGUA" + + "QQBzAHMAZQBtAGIAbAB5AC4AZABsAGwAAAAAACgAAgABAEwAZQBnAGEAbABDAG8AcAB5AHIAaQBnAGgAdAAAACAAAABOABMAAQBPAHIAaQBnAGkAbgBhAGwA" + + "RgBpAGwAZQBuAGEAbQBlAAAAUwBpAG0AcABsAGUAQQBzAHMAZQBtAGIAbAB5AC4AZABsAGwAAAAAADQACAABAFAAcgBvAGQAdQBjAHQAVgBlAHIAcwBpAG8A" + + "bgAAADAALgAwAC4AMAAuADAAAAA4AAgAAQBBAHMAcwBlAG0AYgBsAHkAIABWAGUAcgBzAGkAbwBuAAAAMAAuADAALgAwAC4AMAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAMAAAAgDMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAA"); } } diff --git a/src/System.Reflection.MetadataLoadContext/tests/src/Tests/MetadataLoadContext/PathAssemblyResolver.cs b/src/System.Reflection.MetadataLoadContext/tests/src/Tests/MetadataLoadContext/PathAssemblyResolver.cs index 4cc6fcf5d1b1..0675f651eef7 100644 --- a/src/System.Reflection.MetadataLoadContext/tests/src/Tests/MetadataLoadContext/PathAssemblyResolver.cs +++ b/src/System.Reflection.MetadataLoadContext/tests/src/Tests/MetadataLoadContext/PathAssemblyResolver.cs @@ -245,7 +245,7 @@ public static void DuplicateUnsignedAssembliesSameVersions() } } - [Fact] + [Fact] public static void DuplicateUnsignedAssembliesSameVersionsDifferentLocale() { using (TempDirectory dir = new TempDirectory()) @@ -324,5 +324,54 @@ public static void DuplicateSignedAndUnsignedAssemblies() } } } + + [Fact] + public static void RelocatableAssembly() + { + string coreAssemblyPath = TestUtils.GetPathToCoreAssembly(); + string coreAssemblyName = Path.GetFileNameWithoutExtension(coreAssemblyPath); + + // Ensure mscorlib is specified since we want to relocate an older mscorlib later. + string coreDirectory = Path.GetDirectoryName(coreAssemblyPath); + string mscorLibPath = Path.Combine(coreDirectory, "mscorlib.dll"); + + using (TempDirectory dir = new TempDirectory()) + using (TempFile relocatableAsmFile = new TempFile(Path.Combine(dir.Path, TestData.s_RetargetableAssemblySimpleName), TestData.s_RetargetableImage)) + { + var resolver = new PathAssemblyResolver(new string[] { coreAssemblyPath, mscorLibPath, relocatableAsmFile.Path }); + + using (MetadataLoadContext lc = new MetadataLoadContext(resolver, coreAssemblyName)) + { + Assembly retargetableAssembly = lc.LoadFromAssemblyName(TestData.s_RetargetableAssemblySimpleName); + Assert.NotNull(retargetableAssembly); + + // The assembly only contains a reference to an older, retargetable mscorlib. + AssemblyName[] assemblyNames = retargetableAssembly.GetReferencedAssemblies(); + AssemblyName retargetableAssemblyName = assemblyNames[0]; + Assert.Equal(AssemblyNameFlags.Retargetable, retargetableAssemblyName.Flags); + Assert.Equal(new Version(2,0,5,0), retargetableAssemblyName.Version); + + // Trigger PathAssemblyResolver.Resolve for the older mscorlib. + Type myType = retargetableAssembly.GetType("Relocate.MyClass"); + FieldInfo[] fields = myType.GetFields(); + Assert.Equal(1, fields.Length); + FieldInfo field = fields[0]; + Assert.Equal("MyObj", field.Name); + + // Verify that LoadFromAssemblyName also finds the newer mscorlib. + Assembly mscorlib = lc.LoadFromAssemblyName(retargetableAssemblyName); + Assert.True(mscorlib.GetName().Version > retargetableAssemblyName.Version); + + // The older reference has a different public key token, which requires AssemblyNameFlags.Retargetable to find the newer assembly. + byte[] newerPKT = mscorlib.GetName().GetPublicKeyToken(); + Assert.NotEmpty(newerPKT); + + byte[] olderPKT = retargetableAssemblyName.GetPublicKeyToken(); + Assert.NotEmpty(olderPKT); + + Assert.False(Enumerable.SequenceEqual(newerPKT, olderPKT)); + } + } + } } } diff --git a/src/packages.builds b/src/packages.builds index 55f7886509ec..54efe3c3736c 100644 --- a/src/packages.builds +++ b/src/packages.builds @@ -26,6 +26,9 @@ $(AdditionalProperties) + + $(AdditionalProperties) +