From 132d7f57308d787e8ec68171b44f34dc6ea6986b Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Thu, 9 Nov 2017 15:22:50 -0800 Subject: [PATCH] Add public API for ILVerify --- .../TypeSystem/Common/TypeSystemContext.cs | 7 + src/Common/src/TypeSystem/Ecma/EcmaModule.cs | 11 + src/ILVerify/src/AssemblyInfo.cs | 2 +- src/ILVerify/src/ILVerify.csproj | 8 +- src/ILVerify/src/Program.cs | 194 ++++----------- src/ILVerify/src/SimpleTypeSystemContext.cs | 122 ++++----- src/ILVerify/src/Verifier.cs | 231 ++++++++++++++++++ src/ILVerify/src/VerifierError.cs | 6 - src/ILVerify/tests/ILMethodTester.cs | 38 +-- src/ILVerify/tests/ILVerify.Tests.csproj | 3 + src/ILVerify/tests/TestDataLoader.cs | 53 ++-- 11 files changed, 403 insertions(+), 272 deletions(-) create mode 100644 src/ILVerify/src/Verifier.cs diff --git a/src/Common/src/TypeSystem/Common/TypeSystemContext.cs b/src/Common/src/TypeSystem/Common/TypeSystemContext.cs index 4f9dbb141dd..ec54d1e4662 100644 --- a/src/Common/src/TypeSystem/Common/TypeSystemContext.cs +++ b/src/Common/src/TypeSystem/Common/TypeSystemContext.cs @@ -66,6 +66,13 @@ public virtual ModuleDesc ResolveAssembly(AssemblyName name, bool throwIfNotFoun return null; } + public virtual ModuleDesc ResolveModule(AssemblyName name, bool throwIfNotFound = true) + { + if (throwIfNotFound) + throw new NotSupportedException(); + return null; + } + // // Array types // diff --git a/src/Common/src/TypeSystem/Ecma/EcmaModule.cs b/src/Common/src/TypeSystem/Ecma/EcmaModule.cs index 14b3d51b495..6144b8f41fe 100644 --- a/src/Common/src/TypeSystem/Ecma/EcmaModule.cs +++ b/src/Common/src/TypeSystem/Ecma/EcmaModule.cs @@ -147,6 +147,10 @@ protected override IEntityHandleObject CreateValueFromKey(EntityHandle handle) item = _module; break; + case HandleKind.ModuleReference: + item = _module.ResolveModuleReference((ModuleReferenceHandle)handle); + break; + default: throw new BadImageFormatException("Unknown metadata token type: " + handle.Kind); } @@ -479,6 +483,13 @@ private Object ResolveAssemblyReference(AssemblyReferenceHandle handle) return Context.ResolveAssembly(an); } + private Object ResolveModuleReference(ModuleReferenceHandle handle) + { + ModuleReference moduleReference = _metadataReader.GetModuleReference(handle); + string name = _metadataReader.GetString(moduleReference.Name); + return Context.ResolveModule(new AssemblyName(name)); + } + private Object ResolveExportedType(ExportedTypeHandle handle) { ExportedType exportedType = _metadataReader.GetExportedType(handle); diff --git a/src/ILVerify/src/AssemblyInfo.cs b/src/ILVerify/src/AssemblyInfo.cs index 8e392ff7bc6..7b687074742 100644 --- a/src/ILVerify/src/AssemblyInfo.cs +++ b/src/ILVerify/src/AssemblyInfo.cs @@ -1,3 +1,3 @@ using System.Runtime.CompilerServices; -[assembly: InternalsVisibleTo("ILVerify.Tests")] +[assembly: InternalsVisibleTo("ILVerify.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010055e0217eb635f69281051f9a823e0c7edd90f28063eb6c7a742a19b4f6139778ee0af438f47aed3b6e9f99838aa8dba689c7a71ddb860c96d923830b57bbd5cd6119406ddb9b002cf1c723bf272d6acbb7129e9d6dd5a5309c94e0ff4b2c884d45a55f475cd7dba59198086f61f5a8c8b5e601c0edbf269733f6f578fc8579c2")] diff --git a/src/ILVerify/src/ILVerify.csproj b/src/ILVerify/src/ILVerify.csproj index 27ce4fc9e98..7219869c06a 100644 --- a/src/ILVerify/src/ILVerify.csproj +++ b/src/ILVerify/src/ILVerify.csproj @@ -1,12 +1,15 @@ - Exe + Library netcoreapp2.0;net46 AnyCPU false true false + + true + D:\repos\roslyn4\build\Targets\..\Strong Name Keys\RoslynInternalKey.Private.snk @@ -16,6 +19,7 @@ + @@ -299,4 +303,4 @@ - \ No newline at end of file + diff --git a/src/ILVerify/src/Program.cs b/src/ILVerify/src/Program.cs index aec3b5c18a3..f271c1ccf60 100644 --- a/src/ILVerify/src/Program.cs +++ b/src/ILVerify/src/Program.cs @@ -3,42 +3,28 @@ // See the LICENSE file in the project root for more information. using System; -using System.IO; using System.Collections.Generic; using System.CommandLine; -using System.Reflection; +using System.IO; using System.Linq; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; +using System.Reflection; using System.Reflection.PortableExecutable; -using System.Text; - -using Internal.TypeSystem; -using Internal.TypeSystem.Ecma; -using Internal.IL; - -using Internal.CommandLine; using System.Text.RegularExpressions; -using System.Globalization; -using System.Resources; +using Internal.CommandLine; namespace ILVerify { - class Program + class Program : IResolver { - private const string DefaultSystemModuleName = "mscorlib"; private bool _help; - private string _systemModule = DefaultSystemModuleName; - private Dictionary _inputFilePaths = new Dictionary(StringComparer.OrdinalIgnoreCase); - private Dictionary _referenceFilePaths = new Dictionary(StringComparer.OrdinalIgnoreCase); + private AssemblyName _systemModule; + private Dictionary _inputFilePaths = new Dictionary(StringComparer.OrdinalIgnoreCase); // map of simple name to file path + private Dictionary _referenceFilePaths = new Dictionary(StringComparer.OrdinalIgnoreCase); // map of simple name to file path private IReadOnlyList _includePatterns = Array.Empty(); private IReadOnlyList _excludePatterns = Array.Empty(); - private SimpleTypeSystemContext _typeSystemContext; - private ResourceManager _stringResourceManager; - - private int _numErrors; + private Verifier _verifier; private Program() { @@ -78,7 +64,7 @@ private ArgumentSyntax ParseCommandLine(string[] args) syntax.HandleErrors = true; syntax.DefineOption("h|help", ref _help, "Display this usage message"); - syntax.DefineOption("s|system-module", ref _systemModule, "System module name (default: mscorlib)"); + syntax.DefineOption("s|system-module", ref _systemModule, s => new AssemblyName(s), "System module name (default: mscorlib)"); syntax.DefineOptionList("r|reference", ref referenceFiles, "Reference metadata from the specified assembly"); syntax.DefineOptionList("i|include", ref includePatterns, "Use only methods/types/namespaces, which match the given regular expression(s)"); syntax.DefineOption("include-file", ref includeFile, "Same as --include, but the regular expression(s) are declared line by line in the specified file."); @@ -113,153 +99,61 @@ private ArgumentSyntax ParseCommandLine(string[] args) return argSyntax; } - private void VerifyMethod(MethodDesc method, MethodIL methodIL) + private int Run(string[] args) { - // Console.WriteLine("Verifying: " + method.ToString()); - - try + ArgumentSyntax syntax = ParseCommandLine(args); + if (_help) { - var importer = new ILImporter(method, methodIL); - - importer.ReportVerificationError = (args) => - { - var message = new StringBuilder(); - - message.Append("[IL]: Error: "); - - message.Append("["); - message.Append(_typeSystemContext.GetModulePath(((EcmaMethod)method).Module)); - message.Append(" : "); - message.Append(((EcmaType)method.OwningType).Name); - message.Append("::"); - message.Append(method.Name); - message.Append("("); - if (method.Signature._parameters != null && method.Signature._parameters.Length > 0) - { - foreach (TypeDesc parameter in method.Signature._parameters) - { - message.Append(parameter.ToString()); - message.Append(", "); - } - message.Remove(message.Length - 2, 2); - } - message.Append(")"); - message.Append("]"); - - message.Append("[offset 0x"); - message.Append(args.Offset.ToString("X8")); - message.Append("]"); - - if (args.Found != null) - { - message.Append("[found "); - message.Append(args.Found); - message.Append("]"); - } - - if (args.Expected != null) - { - message.Append("[expected "); - message.Append(args.Expected); - message.Append("]"); - } - - if (args.Token != 0) - { - message.Append("[token 0x"); - message.Append(args.Token.ToString("X8")); - message.Append("]"); - } - - message.Append(" "); - - if (_stringResourceManager == null) - { - _stringResourceManager = new ResourceManager("ILVerify.Resources.Strings", Assembly.GetExecutingAssembly()); - } - - var str = _stringResourceManager.GetString(args.Code.ToString(), CultureInfo.InvariantCulture); - message.Append(string.IsNullOrEmpty(str) ? args.Code.ToString() : str); + Help(syntax.GetHelpText()); + return 1; + } - Console.WriteLine(message); + if (_inputFilePaths.Count == 0) + throw new CommandLineException("No input files specified"); - _numErrors++; - }; + _verifier = new Verifier(this); + _verifier.SetSystemModuleName(_systemModule); + _verifier.ShouldVerifyMethod = this.ShouldVerifyMethod; - importer.Verify(); - } - catch (NotImplementedException e) - { - Console.Error.WriteLine($"Error in {method}: {e.Message}"); - } - catch (InvalidProgramException e) - { - Console.Error.WriteLine($"Error in {method}: {e.Message}"); - } - catch (VerificationException) - { - } - catch (BadImageFormatException) - { - Console.WriteLine("Unable to resolve token"); - } - catch (PlatformNotSupportedException e) + foreach (var kvp in _inputFilePaths) { - Console.WriteLine(e.Message); + var result = _verifier.Verify(new AssemblyName(kvp.Key)); + + if (result.NumErrors > 0) + Console.WriteLine(result.NumErrors + " Error(s) Verifying " + kvp.Value); + else + Console.WriteLine("All Classes and Methods in " + kvp.Value + " Verified."); } + + return 0; } - private void VerifyModule(EcmaModule module) + private bool ShouldVerifyMethod(string methodName) { - foreach (var methodHandle in module.MetadataReader.MethodDefinitions) + if (_includePatterns.Count > 0 && !_includePatterns.Any(p => p.IsMatch(methodName))) { - var method = (EcmaMethod)module.GetMethod(methodHandle); - - var methodIL = EcmaMethodIL.Create(method); - if (methodIL == null) - continue; - - var methodName = method.ToString(); - if (_includePatterns.Count > 0 && !_includePatterns.Any(p => p.IsMatch(methodName))) - continue; - if (_excludePatterns.Any(p => p.IsMatch(methodName))) - continue; - - VerifyMethod(method, methodIL); + return false; } - } - private int Run(string[] args) - { - ArgumentSyntax syntax = ParseCommandLine(args); - if (_help) + if (_excludePatterns.Any(p => p.IsMatch(methodName))) { - Help(syntax.GetHelpText()); - return 1; + return false; } - if (_inputFilePaths.Count == 0) - throw new CommandLineException("No input files specified"); - - _typeSystemContext = new SimpleTypeSystemContext(); - _typeSystemContext.InputFilePaths = _inputFilePaths; - _typeSystemContext.ReferenceFilePaths = _referenceFilePaths; - - _typeSystemContext.SetSystemModule(_typeSystemContext.GetModuleForSimpleName(_systemModule)); + return true; + } - foreach (var inputPath in _inputFilePaths.Values) + PEReader IResolver.Resolve(AssemblyName name) + { + // Note: we use simple names instead of full names to resolve, because we can't get a full name from an assembly without reading it + string simpleName = name.Name; + string path = null; + if (_inputFilePaths.TryGetValue(simpleName, out path) || _referenceFilePaths.TryGetValue(simpleName, out path)) { - _numErrors = 0; - - VerifyModule(_typeSystemContext.GetModuleFromPath(inputPath)); - - if (_numErrors > 0) - Console.WriteLine(_numErrors + " Error(s) Verifying " + inputPath); - else - Console.WriteLine("All Classes and Methods in " + inputPath + " Verified."); + return new PEReader(File.OpenRead(path)); } - return 0; + return null; } private static int Main(string[] args) diff --git a/src/ILVerify/src/SimpleTypeSystemContext.cs b/src/ILVerify/src/SimpleTypeSystemContext.cs index 123e2e0d27e..113e62e327d 100644 --- a/src/ILVerify/src/SimpleTypeSystemContext.cs +++ b/src/ILVerify/src/SimpleTypeSystemContext.cs @@ -3,132 +3,114 @@ // See the LICENSE file in the project root for more information. using System; -using System.IO; using System.Collections.Generic; +using System.Diagnostics; using System.Reflection; using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; - using Internal.TypeSystem; using Internal.TypeSystem.Ecma; -using Internal.CommandLine; - namespace ILVerify { class SimpleTypeSystemContext : MetadataTypeSystemContext { + private readonly IResolver _resolver; + private RuntimeInterfacesAlgorithm _arrayOfTRuntimeInterfacesAlgorithm; private MetadataRuntimeInterfacesAlgorithm _metadataRuntimeInterfacesAlgorithm = new MetadataRuntimeInterfacesAlgorithm(); - Dictionary _modules = new Dictionary(StringComparer.OrdinalIgnoreCase); + // cache from simple name to EcmaModule + private readonly Dictionary _modules = new Dictionary(StringComparer.OrdinalIgnoreCase); - class ModuleData + internal EcmaModule _inferredSystemModule; + + public SimpleTypeSystemContext(IResolver resolver) { - public string Path; + _resolver = resolver; } - Dictionary _moduleData = new Dictionary(); - public SimpleTypeSystemContext() + public override ModuleDesc ResolveAssembly(AssemblyName name, bool throwIfNotFound = true) { + return GetModule(name, throwIfNotFound); } - public IDictionary InputFilePaths + public override ModuleDesc ResolveModule(AssemblyName name, bool throwIfNotFound = true) { - get; - set; + return GetModule(name, throwIfNotFound); } - public IDictionary ReferenceFilePaths + protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForNonPointerArrayType(ArrayType type) { - get; - set; + if (_arrayOfTRuntimeInterfacesAlgorithm == null) + { + _arrayOfTRuntimeInterfacesAlgorithm = new SimpleArrayOfTRuntimeInterfacesAlgorithm(SystemModule); + } + return _arrayOfTRuntimeInterfacesAlgorithm; } - public override ModuleDesc ResolveAssembly(AssemblyName name, bool throwIfNotFound = true) + protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForDefType(DefType type) { - return GetModuleForSimpleName(name.Name); + return _metadataRuntimeInterfacesAlgorithm; } - public EcmaModule GetModuleForSimpleName(string simpleName) + internal EcmaModule GetModule(AssemblyName name, bool throwIfNotFound = true) { - EcmaModule existingModule; - if (_modules.TryGetValue(simpleName, out existingModule)) + if (_modules.TryGetValue(name.Name, out EcmaModule existingModule)) + { return existingModule; + } - return CreateModuleForSimpleName(simpleName); + EcmaModule module = CreateModule(name); + if (module is null && throwIfNotFound) + { + throw new VerifierException("Assembly or module not found: " + name.Name); + } + + return module; } - private EcmaModule CreateModuleForSimpleName(string simpleName) + private EcmaModule CreateModule(AssemblyName name) { - string filePath; - if (!InputFilePaths.TryGetValue(simpleName, out filePath)) + PEReader peReader = _resolver.Resolve(name); + if (peReader is null) { - if (!ReferenceFilePaths.TryGetValue(simpleName, out filePath)) - throw new CommandLineException("Assembly not found: " + simpleName); + return null; } - PEReader peReader = new PEReader(File.OpenRead(filePath)); EcmaModule module = EcmaModule.Create(this, peReader); MetadataReader metadataReader = module.MetadataReader; - string actualSimpleName = metadataReader.GetString(metadataReader.GetAssemblyDefinition().Name); - if (!actualSimpleName.Equals(simpleName, StringComparison.OrdinalIgnoreCase)) - throw new CommandLineException("Assembly name does not match filename " + filePath); - _modules.Add(simpleName, module); - - ModuleData moduleData = new ModuleData() { Path = filePath }; - _moduleData.Add(module, moduleData); - - return module; - } - - public EcmaModule GetModuleFromPath(string filePath) - { - // This is called once for every assembly that should be verified, so linear search is acceptable. - foreach (KeyValuePair entry in _moduleData) + if (this.SystemModule == null && IsSystemModule(metadataReader)) { - EcmaModule curModule = entry.Key; - ModuleData curData = entry.Value; - if (curData.Path == filePath) - return curModule; + Debug.Assert(_inferredSystemModule is null); + _inferredSystemModule = module; } - - PEReader peReader = new PEReader(File.OpenRead(filePath)); - EcmaModule module = EcmaModule.Create(this, peReader); - MetadataReader metadataReader = module.MetadataReader; - string simpleName = metadataReader.GetString(metadataReader.GetAssemblyDefinition().Name); - if (_modules.ContainsKey(simpleName)) - throw new CommandLineException("Module with same simple name already exists " + filePath); + StringHandle nameHandle = metadataReader.IsAssembly + ? metadataReader.GetAssemblyDefinition().Name + : metadataReader.GetModuleDefinition().Name; - _modules.Add(simpleName, module); + string actualSimpleName = metadataReader.GetString(nameHandle); + if (!actualSimpleName.Equals(name.Name, StringComparison.OrdinalIgnoreCase)) + throw new VerifierException($"Assembly name '{actualSimpleName}' does not match filename '{name}'"); - ModuleData moduleData = new ModuleData() { Path = filePath }; - _moduleData.Add(module, moduleData); + _modules.Add(name.Name, module); return module; } - public string GetModulePath(EcmaModule module) - { - return _moduleData[module].Path; - } - - protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForNonPointerArrayType(ArrayType type) + private bool IsSystemModule(MetadataReader metadataReader) { - if (_arrayOfTRuntimeInterfacesAlgorithm == null) + if (metadataReader.AssemblyReferences.Count > 0) { - _arrayOfTRuntimeInterfacesAlgorithm = new SimpleArrayOfTRuntimeInterfacesAlgorithm(SystemModule); + return false; } - return _arrayOfTRuntimeInterfacesAlgorithm; - } - protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForDefType(DefType type) - { - return _metadataRuntimeInterfacesAlgorithm; + // TODO check for System.Object too + + return true; } } } diff --git a/src/ILVerify/src/Verifier.cs b/src/ILVerify/src/Verifier.cs new file mode 100644 index 00000000000..a006981549a --- /dev/null +++ b/src/ILVerify/src/Verifier.cs @@ -0,0 +1,231 @@ +// 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.Collections.Generic; +using System.Globalization; +using System.Reflection; +using System.Reflection.PortableExecutable; +using System.Resources; +using System.Text; +using Internal.IL; +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +namespace ILVerify +{ + public delegate bool ShouldVerifyMethod(string name); + + public interface IResolver + { + PEReader Resolve(AssemblyName name); + } + + public class Verifier + { + private Lazy _stringResourceManager = + new Lazy(() => new ResourceManager("ILVerify.Resources.Strings", Assembly.GetExecutingAssembly())); + + private SimpleTypeSystemContext _typeSystemContext; + + public ShouldVerifyMethod ShouldVerifyMethod { private get; set; } + + public Verifier(IResolver resolver) + { + _typeSystemContext = new SimpleTypeSystemContext(resolver); + } + + internal Verifier(SimpleTypeSystemContext context) + { + _typeSystemContext = context; + } + + public void SetSystemModuleName(AssemblyName name) + { + _typeSystemContext.SetSystemModule(_typeSystemContext.GetModule(name)); + } + + public VerificationResult Verify(AssemblyName moduleToVerify) + { + if (moduleToVerify == null) + { + throw new ArgumentNullException(nameof(moduleToVerify)); + } + + try + { + if (_typeSystemContext.SystemModule is null) + { + if (_typeSystemContext._inferredSystemModule != null) + { + _typeSystemContext.SetSystemModule(_typeSystemContext._inferredSystemModule); + } + else + { + throw new VerifierException("No system module specified"); + } + } + + EcmaModule module = _typeSystemContext.GetModule(moduleToVerify); + return VerifyModule(module, moduleToVerify.Name); + } + catch (VerifierException e) + { + return new VerificationResult() { NumErrors = 1, Message = e.Message }; + } + } + + private VerificationResult VerifyModule(EcmaModule module, string path) + { + foreach (var methodHandle in module.MetadataReader.MethodDefinitions) + { + var method = (EcmaMethod)module.GetMethod(methodHandle); + + var methodIL = EcmaMethodIL.Create(method); + if (methodIL == null) + { + continue; + } + + var methodName = method.ToString(); + if (ShouldVerifyMethod != null && !ShouldVerifyMethod(methodName)) + { + continue; + } + + var result = VerifyMethod(method, methodIL, path); + if (result.NumErrors > 0) + { + return result; + } + } + + return new VerificationResult(); + } + + internal VerificationResult VerifyMethod(MethodDesc method, MethodIL methodIL, string moduleName) + { + StringBuilder output = new StringBuilder(); + int numErrors = 0; + var errors = new List(); + + try + { + var importer = new ILImporter(method, methodIL); + + importer.ReportVerificationError = (args) => + { + AppendError(method, moduleName, args, output); + errors.Add(args.Code); + numErrors++; + }; + + importer.Verify(); + } + catch (NotImplementedException e) + { + output.AppendLine($"Error in {method}: {e.Message}"); + numErrors++; + } + catch (InvalidProgramException e) + { + output.AppendLine($"Error in {method}: {e.Message}"); + numErrors++; + } + catch (VerificationException) + { + numErrors++; + } + catch (BadImageFormatException) + { + output.AppendLine("Unable to resolve token"); + numErrors++; + } + catch (PlatformNotSupportedException e) + { + output.AppendLine(e.Message); + numErrors++; + } + catch (VerifierException e) + { + output.AppendLine(e.Message); + numErrors++; + } + catch (TypeSystemException e) + { + output.AppendLine(e.Message); + numErrors++; + } + + return new VerificationResult() { NumErrors = numErrors, Message = output.ToString(), _errors = errors }; + } + + internal void AppendError(MethodDesc method, string moduleName, VerificationErrorArgs args, StringBuilder output) + { + output.Append("[IL]: Error: "); + + output.Append("["); + output.Append(moduleName); + output.Append(" : "); + output.Append(((EcmaType)method.OwningType).Name); + output.Append("::"); + output.Append(method.Name); + output.Append("("); + if (method.Signature._parameters != null && method.Signature._parameters.Length > 0) + { + foreach (TypeDesc parameter in method.Signature._parameters) + { + output.Append(parameter.ToString()); + output.Append(", "); + } + output.Remove(output.Length - 2, 2); + } + output.Append(")"); + output.Append("]"); + + output.Append("[offset 0x"); + output.Append(args.Offset.ToString("X8")); + output.Append("]"); + + if (args.Found != null) + { + output.Append("[found "); + output.Append(args.Found); + output.Append("]"); + } + + if (args.Expected != null) + { + output.Append("[expected "); + output.Append(args.Expected); + output.Append("]"); + } + + if (args.Token != 0) + { + output.Append("[token 0x"); + output.Append(args.Token.ToString("X8")); + output.Append("]"); + } + + output.Append(" "); + var str = _stringResourceManager.Value.GetString(args.Code.ToString(), CultureInfo.InvariantCulture); + output.AppendLine(string.IsNullOrEmpty(str) ? args.Code.ToString() : str); + } + } + + public class VerificationResult + { + public int NumErrors = 0; + public string Message = string.Empty; + internal IEnumerable _errors; // Note: there may be fewer errors recorded here than counted in NumErrors, which also counts exceptions + } + + public class VerifierException : Exception + { + public VerifierException(string message) : base(message) + { + } + } +} diff --git a/src/ILVerify/src/VerifierError.cs b/src/ILVerify/src/VerifierError.cs index ef92c2e380f..dfaab755071 100644 --- a/src/ILVerify/src/VerifierError.cs +++ b/src/ILVerify/src/VerifierError.cs @@ -2,12 +2,6 @@ // 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.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - namespace ILVerify { enum VerifierError diff --git a/src/ILVerify/tests/ILMethodTester.cs b/src/ILVerify/tests/ILMethodTester.cs index 671bd3f915c..7fe8cb225da 100644 --- a/src/ILVerify/tests/ILMethodTester.cs +++ b/src/ILVerify/tests/ILMethodTester.cs @@ -2,8 +2,6 @@ // 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.Collections.Generic; using System.Linq; using System.Reflection.Metadata.Ecma335; using Internal.IL; @@ -19,16 +17,8 @@ public class ILMethodTester [Trait("", "Valid IL Tests")] void TestMethodsWithValidIL(ValidILTestCase validIL) { - ILImporter importer = ConstructILImporter(validIL); - - var verifierErrors = new List(); - importer.ReportVerificationError = new Action((err) => - { - verifierErrors.Add(err.Code); - }); - - importer.Verify(); - Assert.Equal(0, verifierErrors.Count); + VerificationResult result = Verify(validIL); + Assert.Equal(0, result.NumErrors); } [Theory(DisplayName = "")] @@ -36,17 +26,11 @@ void TestMethodsWithValidIL(ValidILTestCase validIL) [Trait("", "Invalid IL Tests")] void TestMethodsWithInvalidIL(InvalidILTestCase invalidIL) { - ILImporter importer = ConstructILImporter(invalidIL); - - var verifierErrors = new List(); - importer.ReportVerificationError = new Action((err) => - { - verifierErrors.Add(err.Code); - }); + VerificationResult result = null; try { - importer.Verify(); + result = Verify(invalidIL); } catch { @@ -57,23 +41,25 @@ void TestMethodsWithInvalidIL(InvalidILTestCase invalidIL) } finally { - Assert.Equal(invalidIL.ExpectedVerifierErrors.Count, verifierErrors.Count); + Assert.NotNull(result); + Assert.Equal(invalidIL.ExpectedVerifierErrors.Count, result.NumErrors); foreach (var item in invalidIL.ExpectedVerifierErrors) { - var actual = verifierErrors.Select(e => e.ToString()); - Assert.True(verifierErrors.Contains(item), $"Actual errors where: {string.Join(',', actual)}"); + var actual = result._errors.Select(e => e.ToString()); + Assert.True(result._errors.Contains(item), $"Actual errors where: {string.Join(',', actual)}"); } } } - private ILImporter ConstructILImporter(TestCase testCase) + private static VerificationResult Verify(TestCase testCase) { - var module = TestDataLoader.GetModuleForTestAssembly(testCase.ModuleName); + EcmaModule module = TestDataLoader.GetModuleForTestAssembly(testCase.ModuleName); var method = (EcmaMethod)module.GetMethod(MetadataTokens.EntityHandle(testCase.MetadataToken)); var methodIL = EcmaMethodIL.Create(method); - return new ILImporter(method, methodIL); + var verifier = new Verifier((SimpleTypeSystemContext)method.Context); + return verifier.VerifyMethod(method, methodIL, testCase.ToString()); } } } diff --git a/src/ILVerify/tests/ILVerify.Tests.csproj b/src/ILVerify/tests/ILVerify.Tests.csproj index 94c21cd1599..82b723779eb 100644 --- a/src/ILVerify/tests/ILVerify.Tests.csproj +++ b/src/ILVerify/tests/ILVerify.Tests.csproj @@ -4,6 +4,9 @@ netcoreapp2.0 false + + true + D:\repos\roslyn4\build\Targets\..\Strong Name Keys\RoslynInternalKey.Private.snk diff --git a/src/ILVerify/tests/TestDataLoader.cs b/src/ILVerify/tests/TestDataLoader.cs index 15dc8efde2e..0d7ef83223d 100644 --- a/src/ILVerify/tests/TestDataLoader.cs +++ b/src/ILVerify/tests/TestDataLoader.cs @@ -8,9 +8,8 @@ using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; using System.Text; -using Internal.IL; -using Internal.TypeSystem; using Internal.TypeSystem.Ecma; using Newtonsoft.Json; using Xunit; @@ -96,7 +95,7 @@ public static TheoryData GetMethodsWithInvalidIL() private static TheoryData GetTestMethodsFromDll(Func methodSelector) { - var retVal = new Xunit.TheoryData(); + var retVal = new TheoryData(); foreach (var testDllName in GetAllTestDlls()) { @@ -152,33 +151,53 @@ private static MethodDefinitionHandle HandleSpecialTests(string[] methodParams, private static IEnumerable GetAllTestDlls() { - foreach (var item in System.IO.Directory.GetFiles(TESTASSEMBLYPATH)) + foreach (var item in Directory.GetFiles(TESTASSEMBLYPATH)) { if (item.ToLower().EndsWith(".dll")) { - yield return System.IO.Path.GetFileName(item); + yield return Path.GetFileName(item); } } } public static EcmaModule GetModuleForTestAssembly(string assemblyName) { - var typeSystemContext = new SimpleTypeSystemContext(); - var coreAssembly = typeof(Object).Assembly; - var systemRuntime = Assembly.Load("System.Runtime"); + var simpleNameToPathMap = new Dictionary(); - typeSystemContext.InputFilePaths = new Dictionary + foreach (var fileName in GetAllTestDlls()) { - { coreAssembly.GetName().Name, coreAssembly.Location }, - { systemRuntime.GetName().Name, systemRuntime.Location } - }; + simpleNameToPathMap.Add(Path.GetFileNameWithoutExtension(fileName), TESTASSEMBLYPATH + fileName); + } - typeSystemContext.ReferenceFilePaths = new Dictionary(); - foreach (var fileName in GetAllTestDlls()) - typeSystemContext.ReferenceFilePaths.Add(Path.GetFileNameWithoutExtension(fileName), TESTASSEMBLYPATH + fileName); + Assembly coreAssembly = typeof(object).Assembly; + simpleNameToPathMap.Add(coreAssembly.GetName().Name, coreAssembly.Location); + + Assembly systemRuntime = Assembly.Load("System.Runtime"); + simpleNameToPathMap.Add(systemRuntime.GetName().Name, systemRuntime.Location); + + var typeSystemContext = new SimpleTypeSystemContext(new TestResolver(simpleNameToPathMap)); + typeSystemContext.SetSystemModule(typeSystemContext.GetModule(coreAssembly.GetName())); - typeSystemContext.SetSystemModule(typeSystemContext.GetModuleForSimpleName(coreAssembly.GetName().Name)); - return typeSystemContext.GetModuleFromPath(TESTASSEMBLYPATH + assemblyName); + return typeSystemContext.GetModule(new AssemblyName(Path.GetFileNameWithoutExtension(assemblyName))); + } + + private class TestResolver : IResolver + { + Dictionary _simpleNameToPathMap; + public TestResolver(Dictionary simpleNameToPathMap) + { + _simpleNameToPathMap = simpleNameToPathMap; + } + + public PEReader Resolve(AssemblyName name) + { + if (_simpleNameToPathMap.TryGetValue(name.Name, out string path)) + { + return new PEReader(File.OpenRead(path)); + } + + return null; + } } }