From 8ce60a16a42d677cc00a5175ea4f098e1dcf5d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Wed, 5 Feb 2020 21:12:17 +0100 Subject: [PATCH] Validate modules that are part of a version bubble 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. --- src/coreclr/src/inc/CrstTypes.def | 3 + src/coreclr/src/inc/crsttypes.h | 129 +++++++++--------- src/coreclr/src/inc/pedecoder.h | 4 +- src/coreclr/src/inc/readytorun.h | 7 + .../SortableDependencyNode.cs | 2 + .../Common/Internal/Runtime/ModuleHeaders.cs | 1 + .../Common/TypeSystem/Ecma/EcmaAssembly.cs | 3 +- .../ReadyToRun/InliningInfoNode.cs | 6 +- .../ReadyToRun/ManifestMetadataTableNode.cs | 30 +++- .../ReadyToRun/NativeDependenciesNode.cs | 51 +++++++ .../ReadyToRunCodegenCompilationBuilder.cs | 12 ++ .../ILCompiler.ReadyToRun.csproj | 1 + .../NativeDependenciesSection.cs | 44 ++++++ .../ReadyToRunSection.cs | 1 + .../src/tools/crossgen2/crossgen2/Program.cs | 1 + src/coreclr/src/tools/r2rdump/TextDumper.cs | 6 + src/coreclr/src/utilcode/pedecoder.cpp | 50 ++++--- src/coreclr/src/vm/appdomain.cpp | 95 ------------- src/coreclr/src/vm/appdomain.hpp | 30 ---- src/coreclr/src/vm/domainfile.cpp | 64 ++++++++- src/coreclr/src/vm/domainfile.h | 8 ++ src/coreclr/src/vm/loaderallocator.cpp | 101 +++++++++++++- src/coreclr/src/vm/loaderallocator.hpp | 28 ++++ 23 files changed, 460 insertions(+), 217 deletions(-) create mode 100644 src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/NativeDependenciesNode.cs create mode 100644 src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/NativeDependenciesSection.cs diff --git a/src/coreclr/src/inc/CrstTypes.def b/src/coreclr/src/inc/CrstTypes.def index 42ba9fe5922596..ad24d2cc1ff1a8 100644 --- a/src/coreclr/src/inc/CrstTypes.def +++ b/src/coreclr/src/inc/CrstTypes.def @@ -705,3 +705,6 @@ Crst MethodDescBackpatchInfoTracker AcquiredBefore FuncPtrStubs ThreadStore SystemDomain AcquiredAfter ReJITGlobalRequest End + +Crst NativeImageDependencies +End diff --git a/src/coreclr/src/inc/crsttypes.h b/src/coreclr/src/inc/crsttypes.h index f497a540f66f9b..64d280186e4563 100644 --- a/src/coreclr/src/inc/crsttypes.h +++ b/src/coreclr/src/inc/crsttypes.h @@ -106,69 +106,70 @@ enum CrstType CrstMUThunkHash = 87, CrstNativeBinderInit = 88, CrstNativeImageCache = 89, - CrstNls = 90, - CrstNotifyGdb = 91, - CrstObjectList = 92, - CrstOnEventManager = 93, - CrstPatchEntryPoint = 94, - CrstPEImage = 95, - CrstPEImagePDBStream = 96, - CrstPendingTypeLoadEntry = 97, - CrstPinHandle = 98, - CrstPinnedByrefValidation = 99, - CrstProfilerGCRefDataFreeList = 100, - CrstProfilingAPIStatus = 101, - CrstPublisherCertificate = 102, - CrstRCWCache = 103, - CrstRCWCleanupList = 104, - CrstRCWRefCache = 105, - CrstReadyToRunEntryPointToMethodDescMap = 106, - CrstReDacl = 107, - CrstReflection = 108, - CrstReJITDomainTable = 109, - CrstReJITGlobalRequest = 110, - CrstRemoting = 111, - CrstRetThunkCache = 112, - CrstRWLock = 113, - CrstSavedExceptionInfo = 114, - CrstSaveModuleProfileData = 115, - CrstSecurityStackwalkCache = 116, - CrstSharedAssemblyCreate = 117, - CrstSigConvert = 118, - CrstSingleUseLock = 119, - CrstSpecialStatics = 120, - CrstSqmManager = 121, - CrstStackSampler = 122, - CrstStressLog = 123, - CrstStrongName = 124, - CrstStubCache = 125, - CrstStubDispatchCache = 126, - CrstStubUnwindInfoHeapSegments = 127, - CrstSyncBlockCache = 128, - CrstSyncHashLock = 129, - CrstSystemBaseDomain = 130, - CrstSystemDomain = 131, - CrstSystemDomainDelayedUnloadList = 132, - CrstThreadIdDispenser = 133, - CrstThreadpoolEventCache = 134, - CrstThreadpoolTimerQueue = 135, - CrstThreadpoolWaitThreads = 136, - CrstThreadpoolWorker = 137, - CrstThreadStaticDataHashTable = 138, - CrstThreadStore = 139, - CrstTieredCompilation = 140, - CrstTPMethodTable = 141, - CrstTypeEquivalenceMap = 142, - CrstTypeIDMap = 143, - CrstUMEntryThunkCache = 144, - CrstUMThunkHash = 145, - CrstUniqueStack = 146, - CrstUnresolvedClassLock = 147, - CrstUnwindInfoTableLock = 148, - CrstVSDIndirectionCellLock = 149, - CrstWinRTFactoryCache = 150, - CrstWrapperTemplate = 151, - kNumberOfCrstTypes = 152 + CrstNativeImageDependencies = 90, + CrstNls = 91, + CrstNotifyGdb = 92, + CrstObjectList = 93, + CrstOnEventManager = 94, + CrstPatchEntryPoint = 95, + CrstPEImage = 96, + CrstPEImagePDBStream = 97, + CrstPendingTypeLoadEntry = 98, + CrstPinHandle = 99, + CrstPinnedByrefValidation = 100, + CrstProfilerGCRefDataFreeList = 101, + CrstProfilingAPIStatus = 102, + CrstPublisherCertificate = 103, + CrstRCWCache = 104, + CrstRCWCleanupList = 105, + CrstRCWRefCache = 106, + CrstReadyToRunEntryPointToMethodDescMap = 107, + CrstReDacl = 108, + CrstReflection = 109, + CrstReJITDomainTable = 110, + CrstReJITGlobalRequest = 111, + CrstRemoting = 112, + CrstRetThunkCache = 113, + CrstRWLock = 114, + CrstSavedExceptionInfo = 115, + CrstSaveModuleProfileData = 116, + CrstSecurityStackwalkCache = 117, + CrstSharedAssemblyCreate = 118, + CrstSigConvert = 119, + CrstSingleUseLock = 120, + CrstSpecialStatics = 121, + CrstSqmManager = 122, + CrstStackSampler = 123, + CrstStressLog = 124, + CrstStrongName = 125, + CrstStubCache = 126, + CrstStubDispatchCache = 127, + CrstStubUnwindInfoHeapSegments = 128, + CrstSyncBlockCache = 129, + CrstSyncHashLock = 130, + CrstSystemBaseDomain = 131, + CrstSystemDomain = 132, + CrstSystemDomainDelayedUnloadList = 133, + CrstThreadIdDispenser = 134, + CrstThreadpoolEventCache = 135, + CrstThreadpoolTimerQueue = 136, + CrstThreadpoolWaitThreads = 137, + CrstThreadpoolWorker = 138, + CrstThreadStaticDataHashTable = 139, + CrstThreadStore = 140, + CrstTieredCompilation = 141, + CrstTPMethodTable = 142, + CrstTypeEquivalenceMap = 143, + CrstTypeIDMap = 144, + CrstUMEntryThunkCache = 145, + CrstUMThunkHash = 146, + CrstUniqueStack = 147, + CrstUnresolvedClassLock = 148, + CrstUnwindInfoTableLock = 149, + CrstVSDIndirectionCellLock = 150, + CrstWinRTFactoryCache = 151, + CrstWrapperTemplate = 152, + kNumberOfCrstTypes = 153 }; #endif // __CRST_TYPES_INCLUDED @@ -269,6 +270,7 @@ int g_rgCrstLevelMap[] = 0, // CrstMUThunkHash -1, // CrstNativeBinderInit -1, // CrstNativeImageCache + 0, // CrstNativeImageDependencies 0, // CrstNls 0, // CrstNotifyGdb 2, // CrstObjectList @@ -426,6 +428,7 @@ LPCSTR g_rgCrstNameMap[] = "CrstMUThunkHash", "CrstNativeBinderInit", "CrstNativeImageCache", + "CrstNativeImageDependencies", "CrstNls", "CrstNotifyGdb", "CrstObjectList", diff --git a/src/coreclr/src/inc/pedecoder.h b/src/coreclr/src/inc/pedecoder.h index 42d6eca9a50f48..6f68d67220e08d 100644 --- a/src/coreclr/src/inc/pedecoder.h +++ b/src/coreclr/src/inc/pedecoder.h @@ -302,6 +302,8 @@ class PEDecoder // Debug directory access, returns NULL if no such entry PTR_IMAGE_DEBUG_DIRECTORY GetDebugDirectoryEntry(UINT index) const; + PTR_IMAGE_DATA_DIRECTORY GetReadyToRunSection(DWORD section) const; + PTR_CVOID GetNativeManifestMetadata(COUNT_T* pSize = NULL) const; #ifdef FEATURE_PREJIT @@ -328,7 +330,7 @@ class PEDecoder BOOL IsNativeILILOnly() const; BOOL IsNativeILDll() const; void GetNativeILPEKindAndMachine(DWORD* pdwKind, DWORD* pdwMachine) const; - CORCOMPILE_DEPENDENCY * GetNativeDependencies(COUNT_T *pCount = NULL) const; + CORCOMPILE_DEPENDENCY* GetNativeDependencies(COUNT_T* pCount = NULL) const; PTR_CORCOMPILE_IMPORT_SECTION GetNativeImportSections(COUNT_T *pCount = NULL) const; PTR_CORCOMPILE_IMPORT_SECTION GetNativeImportSectionFromIndex(COUNT_T index) const; diff --git a/src/coreclr/src/inc/readytorun.h b/src/coreclr/src/inc/readytorun.h index cd06ba68565994..599b994385882c 100644 --- a/src/coreclr/src/inc/readytorun.h +++ b/src/coreclr/src/inc/readytorun.h @@ -68,6 +68,7 @@ enum ReadyToRunSectionType READYTORUN_SECTION_MANIFEST_METADATA = 112, // Added in V2.3 READYTORUN_SECTION_ATTRIBUTEPRESENCE = 113, // Added in V3.1 READYTORUN_SECTION_INLINING_INFO2 = 114, // Added in V4.1 + READYTORUN_SECTION_NATIVE_DEPENDENCIES = 115, // Added in V4.1 // If you add a new section consider whether it is a breaking or non-breaking change. // Usually it is non-breaking, but if it is preferable to have older runtimes fail @@ -370,4 +371,10 @@ enum ReadyToRunRuntimeConstants : DWORD READYTORUN_PInvokeTransitionFrameSizeInPointerUnits = 11 }; +struct READYTORUN_DEPENDENCY +{ + DWORD ModuleId; + GUID Mvid; +}; + #endif // __READYTORUN_H__ diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/SortableDependencyNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/SortableDependencyNode.cs index 81aa110c9d4fb9..2a0933ca3068ea 100644 --- a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/SortableDependencyNode.cs +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/SortableDependencyNode.cs @@ -59,9 +59,11 @@ protected enum ObjectNodeOrder // CorHeaderNode, ReadyToRunHeaderNode, + InliningInfoNode, ImportSectionsTableNode, ImportSectionNode, MethodEntrypointTableNode, + NativeDependenciesNode, // diff --git a/src/coreclr/src/tools/Common/Internal/Runtime/ModuleHeaders.cs b/src/coreclr/src/tools/Common/Internal/Runtime/ModuleHeaders.cs index 07bc53d2ae0561..68a8264ff12772 100644 --- a/src/coreclr/src/tools/Common/Internal/Runtime/ModuleHeaders.cs +++ b/src/coreclr/src/tools/Common/Internal/Runtime/ModuleHeaders.cs @@ -64,6 +64,7 @@ public enum ReadyToRunSectionType ManifestMetadata = 112, // Added in v2.3 AttributePresence = 113, // Added in V3.1 InliningInfo2 = 114, // Added in 4.1 + NativeDependencies = 115, // Added in V4.1 // // CoreRT ReadyToRun sections diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaAssembly.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaAssembly.cs index 7b0805ee713afc..95e27adc76eebb 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaAssembly.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaAssembly.cs @@ -50,7 +50,8 @@ public AssemblyName GetName() AssemblyName an = new AssemblyName(); an.Name = metadataReader.GetString(_assemblyDefinition.Name); an.Version = _assemblyDefinition.Version; - an.SetPublicKey(metadataReader.GetBlobBytes(_assemblyDefinition.PublicKey)); + if ((_assemblyDefinition.Flags & AssemblyFlags.PublicKey) != 0) + an.SetPublicKey(metadataReader.GetBlobBytes(_assemblyDefinition.PublicKey)); an.CultureName = metadataReader.GetString(_assemblyDefinition.Culture); an.ContentType = GetContentTypeFromAssemblyFlags(_assemblyDefinition.Flags); diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InliningInfoNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InliningInfoNode.cs index ce57611186494c..aeac2e2abc5d99 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InliningInfoNode.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InliningInfoNode.cs @@ -22,6 +22,10 @@ public class InliningInfoNode : HeaderTableNode { private readonly EcmaModule _globalContext; + protected internal override int Phase => (int)ObjectNodePhase.Ordered; + + public override int ClassCode => (int)ObjectNodeOrder.InliningInfoNode; + public InliningInfoNode(TargetDetails target, EcmaModule globalContext) : base(target) { @@ -143,7 +147,5 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) alignment: 8, definedSymbols: new ISymbolDefinitionNode[] { this }); } - - public override int ClassCode => -87382891; } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs index 899b58ad23cc58..0af0429cd44f68 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs @@ -10,6 +10,7 @@ using System.Reflection.Metadata.Ecma335; using Internal.Text; +using Internal.TypeSystem; using Internal.TypeSystem.Ecma; using Debug = System.Diagnostics.Debug; @@ -140,13 +141,24 @@ public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilde sb.Append("ManifestMetadataTableNode"); } - public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) + internal IEnumerable<(int Index, Guid Mvid)> GetFragileDependencies(CompilerTypeSystemContext context) { - if (relocsOnly) + // Freeze the moduleId to assembly name map to catch possible ordering bugs. + CompleteEmission(); + + foreach (var assemblyNameAndIndex in _assemblyRefToModuleIdMap.OrderBy(x => x.Value)) { - return new ObjectData(Array.Empty(), null, 1, null); + var module = (EcmaModule)context.GetModuleForSimpleName(assemblyNameAndIndex.Key, throwIfNotFound: false); + if (module == null) + continue; + + Guid mvid = module.MetadataReader.GetGuid(module.MetadataReader.GetModuleDefinition().Mvid); + yield return (assemblyNameAndIndex.Value, mvid); } + } + private void CompleteEmission() + { if (!_emissionCompleted) { foreach (ISignatureEmitter emitter in _signatureEmitters) @@ -156,6 +168,16 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) _emissionCompleted = true; } + } + + public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) + { + if (relocsOnly) + { + return new ObjectData(Array.Empty(), null, 1, null); + } + + CompleteEmission(); MetadataBuilder metadataBuilder = new MetadataBuilder(); @@ -204,7 +226,7 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) name: metadataBuilder.GetOrAddString(assemblyName.Name), version: assemblyName.Version, culture: metadataBuilder.GetOrAddString(assemblyName.CultureName), - publicKeyOrToken: metadataBuilder.GetOrAddBlob(publicKeyOrToken), + publicKeyOrToken: publicKeyOrToken == null ? default : metadataBuilder.GetOrAddBlob(publicKeyOrToken), flags: assemblyFlags, hashValue: default(BlobHandle) /* TODO */); } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/NativeDependenciesNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/NativeDependenciesNode.cs new file mode 100644 index 00000000000000..11bc9f6a097af8 --- /dev/null +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/NativeDependenciesNode.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +using Internal.Text; +using Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis.ReadyToRun +{ + /// + /// Stores information about assemblies that this module has fragile dependencies on. + /// + public class NativeDependencieNode : HeaderTableNode + { + protected internal override int Phase => (int)ObjectNodePhase.Ordered; + + public override int ClassCode => (int)ObjectNodeOrder.NativeDependenciesNode; + + public NativeDependencieNode(TargetDetails target) + : base(target) + { + } + + public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) + { + sb.Append(nameMangler.CompilationUnitPrefix); + sb.Append("__ReadyToRunNativeDependenciesNode"); + } + + public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) + { + // This node does not trigger generation of other nodes. + if (relocsOnly) + return new ObjectData(Array.Empty(), Array.Empty(), 1, new ISymbolDefinitionNode[] { this }); + + ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly); + builder.RequireInitialPointerAlignment(); + builder.AddSymbol(this); + + foreach (var nativeDependency in factory.ManifestMetadataTable.GetFragileDependencies(factory.TypeSystemContext)) + { + builder.EmitInt(nativeDependency.Index); + builder.EmitBytes(nativeDependency.Mvid.ToByteArray()); + } + + return builder.ToObjectData(); + } + } +} diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs index e022ba5375c951..a5ef7395c848ae 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs @@ -26,6 +26,7 @@ public sealed class ReadyToRunCodegenCompilationBuilder : CompilationBuilder private bool _generateMapFile; private int _parallelism; private string _jitPath; + private bool _generateNativeDependencies; // These need to provide reasonable defaults so that the user can optionally skip // calling the Use/Configure methods and still get something reasonable back. @@ -108,6 +109,11 @@ public ReadyToRunCodegenCompilationBuilder UseParallelism(int parallelism) return this; } + public ReadyToRunCodegenCompilationBuilder WithNativeDependenciesTable(bool enable) + { + _generateNativeDependencies = enable; + return this; + } public override ICompilation ToCompilation() { @@ -150,6 +156,12 @@ public override ICompilation ToCompilation() var header = new HeaderNode(_context.Target, flags); + if (_generateNativeDependencies) + { + var nativeDependencies = new NativeDependencieNode(_context.Target); + header.Add(Internal.Runtime.ReadyToRunSectionType.NativeDependencies, nativeDependencies, nativeDependencies); + } + NodeFactory factory = new NodeFactory( _context, _compilationGroup, diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index 04eeaf52474f73..0a993f59a959e2 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -138,6 +138,7 @@ + diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/NativeDependenciesSection.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/NativeDependenciesSection.cs new file mode 100644 index 00000000000000..2ebd0be0f71736 --- /dev/null +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/NativeDependenciesSection.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Reflection.Metadata.Ecma335; +using System.Text; + +namespace ILCompiler.Reflection.ReadyToRun +{ + public class NativeDependenciesSection + { + private readonly ReadyToRunReader _r2r; + private readonly int _startOffset; + private readonly int _endOffset; + + public NativeDependenciesSection(ReadyToRunReader reader, int offset, int endOffset) + { + _r2r = reader; + _startOffset = offset; + _endOffset = endOffset; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + + byte[] guidBytes = new byte[16]; + + int iiOffset = _startOffset; + while (iiOffset < _endOffset) + { + int moduleId = NativeReader.ReadInt32(_r2r.Image, ref iiOffset); + string moduleName = _r2r.GetReferenceAssemblyName(moduleId); + Array.Copy(_r2r.Image, iiOffset, guidBytes, 0, guidBytes.Length); + iiOffset += guidBytes.Length; + Guid mvid = new Guid(guidBytes); + sb.AppendLine($"{moduleName}: {mvid}"); + } + + return sb.ToString(); + } + } +} diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunSection.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunSection.cs index 8f0b781aa0ebb3..b5d72f5ac88b28 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunSection.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunSection.cs @@ -30,6 +30,7 @@ public enum SectionType READYTORUN_SECTION_MANIFEST_METADATA = 112, // Added in v2.3 READYTORUN_SECTION_ATTRIBUTEPRESENCE = 113, // Added in V3.1 READYTORUN_SECTION_INLINING_INFO2 = 114, // Added in 4.1 + READYTORUN_SECTION_NATIVE_DEPENDENCIES = 115, } /// diff --git a/src/coreclr/src/tools/crossgen2/crossgen2/Program.cs b/src/coreclr/src/tools/crossgen2/crossgen2/Program.cs index 04f704c6845a59..5d610942a71561 100644 --- a/src/coreclr/src/tools/crossgen2/crossgen2/Program.cs +++ b/src/coreclr/src/tools/crossgen2/crossgen2/Program.cs @@ -319,6 +319,7 @@ private int Run() DependencyTrackingLevel.None : (_commandLineOptions.GenerateFullDgmlLog ? DependencyTrackingLevel.All : DependencyTrackingLevel.First); builder + .WithNativeDependenciesTable(_commandLineOptions.InputBubble) .UseIbcTuning(_commandLineOptions.Tuning) .UseResilience(_commandLineOptions.Resilient) .UseMapFile(_commandLineOptions.Map) diff --git a/src/coreclr/src/tools/r2rdump/TextDumper.cs b/src/coreclr/src/tools/r2rdump/TextDumper.cs index d9cde7c4183cde..85f38a3b940684 100644 --- a/src/coreclr/src/tools/r2rdump/TextDumper.cs +++ b/src/coreclr/src/tools/r2rdump/TextDumper.cs @@ -403,6 +403,12 @@ internal override void DumpSectionContents(ReadyToRunSection section) InliningInfoSection2 inliningInfoSection2 = new InliningInfoSection2(_r2r, ii2Offset, ii2EndOffset); _writer.WriteLine(inliningInfoSection2.ToString()); break; + case ReadyToRunSection.SectionType.READYTORUN_SECTION_NATIVE_DEPENDENCIES: + int ndOffset = _r2r.GetOffset(section.RelativeVirtualAddress); + int ndEndOffset = ndOffset + section.Size; + NativeDependenciesSection nativeDependenciesSection = new NativeDependenciesSection(_r2r, ndOffset, ndEndOffset); + _writer.WriteLine(nativeDependenciesSection.ToString()); + break; } } diff --git a/src/coreclr/src/utilcode/pedecoder.cpp b/src/coreclr/src/utilcode/pedecoder.cpp index c5267a751e0e24..146f3b4dea767e 100644 --- a/src/coreclr/src/utilcode/pedecoder.cpp +++ b/src/coreclr/src/utilcode/pedecoder.cpp @@ -2833,6 +2833,39 @@ CORCOMPILE_METHOD_PROFILE_LIST *PEDecoder::GetNativeProfileDataList(COUNT_T * pS #endif // FEATURE_PREJIT +PTR_IMAGE_DATA_DIRECTORY PEDecoder::GetReadyToRunSection(DWORD section) const +{ + CONTRACT(PTR_IMAGE_DATA_DIRECTORY) + { + INSTANCE_CHECK; + PRECONDITION(HasReadyToRunHeader()); + NOTHROW; + GC_NOTRIGGER; + } + CONTRACT_END; + + READYTORUN_HEADER* pHeader = GetReadyToRunHeader(); + + PTR_IMAGE_DATA_DIRECTORY pDir = NULL; + + PTR_READYTORUN_SECTION pSections = dac_cast(dac_cast(pHeader) + sizeof(READYTORUN_HEADER)); + for (DWORD i = 0; i < pHeader->NumberOfSections; i++) + { + // Verify that section types are sorted + _ASSERTE(i == 0 || (pSections[i - 1].Type < pSections[i].Type)); + + READYTORUN_SECTION* pSection = pSections + i; + if (pSection->Type == section) + { + // Set pDir to the address of the manifest metadata section + pDir = dac_cast(&pSection->Section); + break; + } + } + + RETURN pDir; +} + PTR_CVOID PEDecoder::GetNativeManifestMetadata(COUNT_T *pSize) const { CONTRACT(PTR_CVOID) @@ -2854,22 +2887,7 @@ PTR_CVOID PEDecoder::GetNativeManifestMetadata(COUNT_T *pSize) const else #endif { - READYTORUN_HEADER * pHeader = GetReadyToRunHeader(); - - PTR_READYTORUN_SECTION pSections = dac_cast(dac_cast(pHeader) + sizeof(READYTORUN_HEADER)); - for (DWORD i = 0; i < pHeader->NumberOfSections; i++) - { - // Verify that section types are sorted - _ASSERTE(i == 0 || (pSections[i - 1].Type < pSections[i].Type)); - - READYTORUN_SECTION * pSection = pSections + i; - if (pSection->Type == READYTORUN_SECTION_MANIFEST_METADATA) - { - // Set pDir to the address of the manifest metadata section - pDir = &pSection->Section; - break; - } - } + pDir = GetReadyToRunSection(READYTORUN_SECTION_MANIFEST_METADATA); // ReadyToRun file without large version bubble support doesn't have the READYTORUN_SECTION_MANIFEST_METADATA if (pDir == NULL) diff --git a/src/coreclr/src/vm/appdomain.cpp b/src/coreclr/src/vm/appdomain.cpp index 357115bf05188e..4ec31dae028231 100644 --- a/src/coreclr/src/vm/appdomain.cpp +++ b/src/coreclr/src/vm/appdomain.cpp @@ -4090,101 +4090,6 @@ CHECK AppDomain::CheckValidModule(Module * pModule) CHECK_OK; } -static void NormalizeAssemblySpecForNativeDependencies(AssemblySpec * pSpec) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (pSpec->IsStrongNamed() && pSpec->HasPublicKey()) - { - pSpec->ConvertPublicKeyToToken(); - } - - // - // CoreCLR binder unifies assembly versions. Ignore assembly version here to - // detect more types of potential mismatches. - // - AssemblyMetaDataInternal * pContext = pSpec->GetContext(); - pContext->usMajorVersion = (USHORT)-1; - pContext->usMinorVersion = (USHORT)-1; - pContext->usBuildNumber = (USHORT)-1; - pContext->usRevisionNumber = (USHORT)-1; - - // Ignore the WinRT type while considering if two assemblies have the same identity. - pSpec->SetWindowsRuntimeType(NULL, NULL); -} - -void AppDomain::CheckForMismatchedNativeImages(AssemblySpec * pSpec, const GUID * pGuid) -{ - STANDARD_VM_CONTRACT; - - // - // The native images are ever used only for trusted images in CoreCLR. - // We don't wish to open the IL file at runtime so we just forgo any - // eager consistency checking. But we still want to prevent mistmatched - // NGen images from being used. We record all mappings between assembly - // names and MVID, and fail once we detect mismatch. - // - NormalizeAssemblySpecForNativeDependencies(pSpec); - - CrstHolder ch(&m_DomainCrst); - - const NativeImageDependenciesEntry * pEntry = m_NativeImageDependencies.Lookup(pSpec); - - if (pEntry != NULL) - { - if (*pGuid != pEntry->m_guidMVID) - { - SString msg; - msg.Printf("ERROR: Native images generated against multiple versions of assembly %s. ", pSpec->GetName()); - WszOutputDebugString(msg.GetUnicode()); - COMPlusThrowNonLocalized(kFileLoadException, msg.GetUnicode()); - } - } - else - { - // - // No entry yet - create one - // - NativeImageDependenciesEntry * pNewEntry = new NativeImageDependenciesEntry(); - pNewEntry->m_AssemblySpec.CopyFrom(pSpec); - pNewEntry->m_AssemblySpec.CloneFields(AssemblySpec::ALL_OWNED); - pNewEntry->m_guidMVID = *pGuid; - m_NativeImageDependencies.Add(pNewEntry); - } -} - -BOOL AppDomain::RemoveNativeImageDependency(AssemblySpec * pSpec) -{ - CONTRACTL - { - GC_NOTRIGGER; - PRECONDITION(CheckPointer(pSpec)); - } - CONTRACTL_END; - - BOOL result = FALSE; - NormalizeAssemblySpecForNativeDependencies(pSpec); - - CrstHolder ch(&m_DomainCrst); - - const NativeImageDependenciesEntry * pEntry = m_NativeImageDependencies.Lookup(pSpec); - - if (pEntry != NULL) - { - m_NativeImageDependencies.Remove(pSpec); - delete pEntry; - result = TRUE; - } - - return result; -} - void AppDomain::SetupSharedStatics() { CONTRACTL diff --git a/src/coreclr/src/vm/appdomain.hpp b/src/coreclr/src/vm/appdomain.hpp index 7aa7e5b7a44ea0..24f80cee34b942 100644 --- a/src/coreclr/src/vm/appdomain.hpp +++ b/src/coreclr/src/vm/appdomain.hpp @@ -1894,36 +1894,6 @@ class AppDomain : public BaseDomain return AssemblyIterator::Create(this, assemblyIterationFlags); } -private: - struct NativeImageDependenciesEntry - { - BaseAssemblySpec m_AssemblySpec; - GUID m_guidMVID; - }; - - class NativeImageDependenciesTraits : public DeleteElementsOnDestructSHashTraits > - { - public: - typedef BaseAssemblySpec *key_t; - static key_t GetKey(NativeImageDependenciesEntry * e) { return &(e->m_AssemblySpec); } - - static count_t Hash(key_t k) - { - return k->Hash(); - } - - static BOOL Equals(key_t lhs, key_t rhs) - { - return lhs->CompareEx(rhs); - } - }; - - SHash m_NativeImageDependencies; - -public: - void CheckForMismatchedNativeImages(AssemblySpec * pSpec, const GUID * pGuid); - BOOL RemoveNativeImageDependency(AssemblySpec* pSpec); - public: class PathIterator { diff --git a/src/coreclr/src/vm/domainfile.cpp b/src/coreclr/src/vm/domainfile.cpp index 2adb813cf16ef0..4919bf7b8d5d94 100644 --- a/src/coreclr/src/vm/domainfile.cpp +++ b/src/coreclr/src/vm/domainfile.cpp @@ -512,6 +512,9 @@ BOOL DomainFile::DoIncrementalLoad(FileLoadLevel level) case FILE_LOAD_EAGER_FIXUPS: EagerFixups(); +#ifndef CROSSGEN_COMPILE + VerifyReadyToRunImageDependencies(); +#endif break; case FILE_LOAD_DELIVER_EVENTS: @@ -548,6 +551,59 @@ BOOL DomainFile::DoIncrementalLoad(FileLoadLevel level) return TRUE; } +void DomainAssembly::VerifyReadyToRunImageDependencies() +{ + // + // Verify that the IL image is consistent with the R2R images loaded into appdomain + // + + AssemblySpec spec; + spec.InitializeSpec(GetFile()); + + GUID mvid; + GetFile()->GetMVID(&mvid); + + GetLoaderAllocator()->CheckForMismatchedNativeImages(&spec, &mvid); + + if (GetFile()->IsILImageReadyToRun()) + { + PTR_PEImage pImage = GetFile()->GetILimage(); + + PTR_PEImageLayout pLayout = pImage->GetLayout(PEImageLayout::LAYOUT_ANY, 0); + PTR_IMAGE_DATA_DIRECTORY pDependencyDirectory = pLayout->GetReadyToRunSection(READYTORUN_SECTION_NATIVE_DEPENDENCIES); + if (pDependencyDirectory != NULL) + { + READYTORUN_DEPENDENCY* pDependencies = (READYTORUN_DEPENDENCY*)pLayout->GetDirectoryData(pDependencyDirectory); + COUNT_T cDependencies = pDependencyDirectory->Size / sizeof(READYTORUN_DEPENDENCY); + for (COUNT_T iDependency = 0; iDependency < cDependencies; iDependency++) + { + READYTORUN_DEPENDENCY* pDependency = &(pDependencies[iDependency]); + + mdToken token; + IMDInternalImport* mdImport; + if (pDependency->ModuleId < m_pModule->GetAssemblyRefMax()) + { + token = TokenFromRid(pDependency->ModuleId, mdtAssemblyRef); + mdImport = pImage->GetMDImport(); + } + else + { + token = TokenFromRid(pDependency->ModuleId - m_pModule->GetAssemblyRefMax(), mdtAssemblyRef); + mdImport = pImage->GetNativeMDImport(); + } + + AssemblySpec name; + name.InitializeSpec(token, + mdImport, + GetDomainAssembly()); + name.SetBindingContext(spec.GetBindingContext()); + + GetLoaderAllocator()->CheckForMismatchedNativeImages(&name, &pDependency->Mvid); + } + } + } +} + #ifdef FEATURE_PREJIT void DomainFile::VerifyNativeImageDependencies(bool verifyOnly) @@ -1452,7 +1508,7 @@ void DomainAssembly::FindNativeImage() GUID mvid; GetFile()->GetMVID(&mvid); - GetAppDomain()->CheckForMismatchedNativeImages(&spec, &mvid); + GetLoaderAllocator()->CheckForMismatchedNativeImages(&spec, &mvid); } CheckZapRequired(); @@ -1856,13 +1912,13 @@ BOOL DomainAssembly::CheckZapDependencyIdentities(PEImage *pNativeImage) CORCOMPILE_VERSION_INFO *pVersionInfo = pNativeImage->GetLoadedLayout()->GetNativeVersionInfo(); // Check our own assembly first - GetAppDomain()->CheckForMismatchedNativeImages(&spec, &pVersionInfo->sourceAssembly.mvid); + GetLoaderAllocator()->CheckForMismatchedNativeImages(&spec, &pVersionInfo->sourceAssembly.mvid); // Check MVID in metadata against MVID in CORCOMPILE_VERSION_INFO - important when metadata is loaded from IL instead of NI ReleaseHolder pImport(this->GetFile()->GetMDImportWithRef()); GUID mvid; IfFailThrow(pImport->GetScopeProps(NULL, &mvid)); - GetAppDomain()->CheckForMismatchedNativeImages(&spec, &mvid); + GetLoaderAllocator()->CheckForMismatchedNativeImages(&spec, &mvid); // Now Check dependencies COUNT_T cDependencies; @@ -1886,7 +1942,7 @@ BOOL DomainAssembly::CheckZapDependencyIdentities(PEImage *pNativeImage) name.SetBindingContext(pParentAssemblyBindingContext); } - GetAppDomain()->CheckForMismatchedNativeImages(&name, &pDependencies->signAssemblyDef.mvid); + GetLoaderAllocator()->CheckForMismatchedNativeImages(&name, &pDependencies->signAssemblyDef.mvid); } pDependencies++; diff --git a/src/coreclr/src/vm/domainfile.h b/src/coreclr/src/vm/domainfile.h index f01988721c0b35..778ba86520022e 100644 --- a/src/coreclr/src/vm/domainfile.h +++ b/src/coreclr/src/vm/domainfile.h @@ -327,6 +327,10 @@ class DomainFile #endif // FEATURE_PREJIT +#ifndef DACCESS_COMPILE + virtual void VerifyReadyToRunImageDependencies() = 0; +#endif + void SetProfilerNotified() { LIMITED_METHOD_CONTRACT; m_notifyflags|= PROFILER_NOTIFIED; } void SetDebuggerNotified() { LIMITED_METHOD_CONTRACT; m_notifyflags|=DEBUGGER_NOTIFIED; } void SetShouldNotifyDebugger() { LIMITED_METHOD_CONTRACT; m_notifyflags|=DEBUGGER_NEEDNOTIFICATION; } @@ -716,6 +720,10 @@ class DomainAssembly : public DomainFile #endif #endif // FEATURE_PREJIT +#ifndef DACCESS_COMPILE + void VerifyReadyToRunImageDependencies(); +#endif + BOOL IsInstrumented(); public: diff --git a/src/coreclr/src/vm/loaderallocator.cpp b/src/coreclr/src/vm/loaderallocator.cpp index 608c36bd8c7aa1..59bf386e840187 100644 --- a/src/coreclr/src/vm/loaderallocator.cpp +++ b/src/coreclr/src/vm/loaderallocator.cpp @@ -493,7 +493,7 @@ LoaderAllocator * LoaderAllocator::GCLoaderAllocators_RemoveAssemblies(AppDomain AssemblySpec spec; spec.InitializeSpec(domainAssemblyToRemove->GetFile()); VERIFY(pAppDomain->RemoveAssemblyFromCache(domainAssemblyToRemove)); - pAppDomain->RemoveNativeImageDependency(&spec); + pDomainLoaderAllocatorDestroyIterator->RemoveNativeImageDependency(&spec); } domainAssemblyIt++; @@ -1061,6 +1061,8 @@ void LoaderAllocator::Init(BaseDomain *pDomain, BYTE *pExecutableHeapMemory) m_ComCallWrapperCrst.Init(CrstCOMCallWrapper); #endif + m_NativeImageDependenciesCrst.Init(CrstNativeImageDependencies); + #ifndef CROSSGEN_COMPILE m_methodDescBackpatchInfoTracker.Initialize(this); #endif @@ -1324,6 +1326,8 @@ void LoaderAllocator::Terminate() #endif m_LoaderAllocatorReferences.RemoveAll(); + m_NativeImageDependenciesCrst.Destroy(); + // In collectible types we merge the low frequency and high frequency heaps // So don't destroy them twice. if ((m_pLowFrequencyHeap != NULL) && (m_pLowFrequencyHeap != m_pHighFrequencyHeap)) @@ -1974,4 +1978,99 @@ BOOL LoaderAllocator::InsertComInteropData(MethodTable* pMT, InteropMethodTableD #endif // FEATURE_COMINTEROP +static void NormalizeAssemblySpecForNativeDependencies(AssemblySpec* pSpec) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (pSpec->IsStrongNamed() && pSpec->HasPublicKey()) + { + pSpec->ConvertPublicKeyToToken(); + } + + // + // CoreCLR binder unifies assembly versions. Ignore assembly version here to + // detect more types of potential mismatches. + // + AssemblyMetaDataInternal* pContext = pSpec->GetContext(); + pContext->usMajorVersion = (USHORT)-1; + pContext->usMinorVersion = (USHORT)-1; + pContext->usBuildNumber = (USHORT)-1; + pContext->usRevisionNumber = (USHORT)-1; + + // Ignore the WinRT type while considering if two assemblies have the same identity. + pSpec->SetWindowsRuntimeType(NULL, NULL); +} + +void LoaderAllocator::CheckForMismatchedNativeImages(AssemblySpec* pSpec, const GUID* pGuid) +{ + STANDARD_VM_CONTRACT; + + // + // The native images are ever used only for trusted images in CoreCLR. + // We don't wish to open the IL file at runtime so we just forgo any + // eager consistency checking. But we still want to prevent mistmatched + // NGen images from being used. We record all mappings between assembly + // names and MVID, and fail once we detect mismatch. + // + NormalizeAssemblySpecForNativeDependencies(pSpec); + + CrstHolder ch(&m_NativeImageDependenciesCrst); + + const NativeImageDependenciesEntry* pEntry = m_NativeImageDependencies.Lookup(pSpec); + + if (pEntry != NULL) + { + if (*pGuid != pEntry->m_guidMVID) + { + SString msg; + msg.Printf("ERROR: Native images generated against multiple versions of assembly %s. ", pSpec->GetName()); + WszOutputDebugString(msg.GetUnicode()); + COMPlusThrowNonLocalized(kFileLoadException, msg.GetUnicode()); + } + } + else + { + // + // No entry yet - create one + // + NativeImageDependenciesEntry* pNewEntry = new NativeImageDependenciesEntry(); + pNewEntry->m_AssemblySpec.CopyFrom(pSpec); + pNewEntry->m_AssemblySpec.CloneFields(AssemblySpec::ALL_OWNED); + pNewEntry->m_guidMVID = *pGuid; + m_NativeImageDependencies.Add(pNewEntry); + } +} + +BOOL LoaderAllocator::RemoveNativeImageDependency(AssemblySpec* pSpec) +{ + CONTRACTL + { + GC_NOTRIGGER; + PRECONDITION(CheckPointer(pSpec)); + } + CONTRACTL_END; + + BOOL result = FALSE; + NormalizeAssemblySpecForNativeDependencies(pSpec); + + CrstHolder ch(&m_NativeImageDependenciesCrst); + + const NativeImageDependenciesEntry* pEntry = m_NativeImageDependencies.Lookup(pSpec); + + if (pEntry != NULL) + { + m_NativeImageDependencies.Remove(pSpec); + delete pEntry; + result = TRUE; + } + + return result; +} + #endif // !DACCESS_COMPILE diff --git a/src/coreclr/src/vm/loaderallocator.hpp b/src/coreclr/src/vm/loaderallocator.hpp index 178482bd813247..f5758981405193 100644 --- a/src/coreclr/src/vm/loaderallocator.hpp +++ b/src/coreclr/src/vm/loaderallocator.hpp @@ -282,8 +282,36 @@ class LoaderAllocator #endif #ifndef DACCESS_COMPILE + struct NativeImageDependenciesEntry + { + BaseAssemblySpec m_AssemblySpec; + GUID m_guidMVID; + }; + + class NativeImageDependenciesTraits : public DeleteElementsOnDestructSHashTraits > + { + public: + typedef BaseAssemblySpec* key_t; + static key_t GetKey(NativeImageDependenciesEntry* e) { return &(e->m_AssemblySpec); } + + static count_t Hash(key_t k) + { + return k->Hash(); + } + + static BOOL Equals(key_t lhs, key_t rhs) + { + return lhs->CompareEx(rhs); + } + }; + + CrstExplicitInit m_NativeImageDependenciesCrst; + SHash m_NativeImageDependencies; public: + void CheckForMismatchedNativeImages(AssemblySpec* pSpec, const GUID* pGuid); + BOOL RemoveNativeImageDependency(AssemblySpec* pSpec); + // CleanupFailedTypeInit is called from AppDomain // This method accesses loader allocator state in a thread unsafe manner. // It expects to be called only from Terminate.