Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

Commit

Permalink
Add public API for ILVerify
Browse files Browse the repository at this point in the history
  • Loading branch information
jcouv committed Jan 3, 2018
1 parent 7384d4a commit 132d7f5
Show file tree
Hide file tree
Showing 11 changed files with 403 additions and 272 deletions.
7 changes: 7 additions & 0 deletions src/Common/src/TypeSystem/Common/TypeSystemContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
//
Expand Down
11 changes: 11 additions & 0 deletions src/Common/src/TypeSystem/Ecma/EcmaModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/ILVerify/src/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("ILVerify.Tests")]
[assembly: InternalsVisibleTo("ILVerify.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010055e0217eb635f69281051f9a823e0c7edd90f28063eb6c7a742a19b4f6139778ee0af438f47aed3b6e9f99838aa8dba689c7a71ddb860c96d923830b57bbd5cd6119406ddb9b002cf1c723bf272d6acbb7129e9d6dd5a5309c94e0ff4b2c884d45a55f475cd7dba59198086f61f5a8c8b5e601c0edbf269733f6f578fc8579c2")]
8 changes: 6 additions & 2 deletions src/ILVerify/src/ILVerify.csproj
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<OutputType>Library</OutputType>
<TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
<PlatformTarget>AnyCPU</PlatformTarget>
<CLSCompliant>false</CLSCompliant>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>

<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>D:\repos\roslyn4\build\Targets\..\Strong Name Keys\RoslynInternalKey.Private.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>

<ItemGroup>
Expand All @@ -16,6 +19,7 @@
<Compile Include="ILImporter.StackValue.cs" />
<Compile Include="SimpleArrayOfTRuntimeInterfacesAlgorithm.cs" />
<Compile Include="SimpleTypeSystemContext.cs" />
<Compile Include="Verifier.cs" />
<Compile Include="VerifierError.cs" />
<Compile Include="TypeSystemHelpers.cs" />
<Compile Include="InstantiatedGenericParameter.cs" />
Expand Down Expand Up @@ -299,4 +303,4 @@
<PackageReference Include="System.Reflection.Metadata" Version="1.4.1" />
<PackageReference Include="System.CommandLine" Version="0.1.0-e160909-1" />
</ItemGroup>
</Project>
</Project>
194 changes: 44 additions & 150 deletions src/ILVerify/src/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, string> _inputFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
private Dictionary<string, string> _referenceFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
private AssemblyName _systemModule;
private Dictionary<string, string> _inputFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); // map of simple name to file path
private Dictionary<string, string> _referenceFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); // map of simple name to file path
private IReadOnlyList<Regex> _includePatterns = Array.Empty<Regex>();
private IReadOnlyList<Regex> _excludePatterns = Array.Empty<Regex>();

private SimpleTypeSystemContext _typeSystemContext;
private ResourceManager _stringResourceManager;

private int _numErrors;
private Verifier _verifier;

private Program()
{
Expand Down Expand Up @@ -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.");
Expand Down Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 132d7f5

Please sign in to comment.