diff --git a/VisualFSharp.sln b/VisualFSharp.sln index 0e584f0c9fa..5f0ba007e8f 100644 --- a/VisualFSharp.sln +++ b/VisualFSharp.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27102.0 +VisualStudioVersion = 15.0.27116.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Compiler.Private", "src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj", "{2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}" EndProject @@ -138,6 +138,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResourceFile", "vsintegrati EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Build.UnitTests", "src\fsharp\FSharp.Build.UnitTests\FSharp.Build.UnitTests.fsproj", "{400FAB03-786E-40CC-85A8-04B0C2869B14}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PEVerify", "tests\fsharpqa\testenv\src\PEVerify\PEVerify.csproj", "{B0689A4E-07D8-494D-A0C8-791CB1D74E54}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -760,6 +762,18 @@ Global {400FAB03-786E-40CC-85A8-04B0C2869B14}.Release|Any CPU.Build.0 = Release|Any CPU {400FAB03-786E-40CC-85A8-04B0C2869B14}.Release|x86.ActiveCfg = Release|Any CPU {400FAB03-786E-40CC-85A8-04B0C2869B14}.Release|x86.Build.0 = Release|Any CPU + {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Debug|x86.ActiveCfg = Debug|Any CPU + {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Debug|x86.Build.0 = Debug|Any CPU + {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Proto|Any CPU.ActiveCfg = Debug|Any CPU + {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Proto|Any CPU.Build.0 = Debug|Any CPU + {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Proto|x86.ActiveCfg = Debug|Any CPU + {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Proto|x86.Build.0 = Debug|Any CPU + {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Release|Any CPU.Build.0 = Release|Any CPU + {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Release|x86.ActiveCfg = Release|Any CPU + {B0689A4E-07D8-494D-A0C8-791CB1D74E54}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -823,6 +837,7 @@ Global {FF76BD3C-5E0A-4752-B6C3-044F6E15719B} = {35636A82-401A-4C3A-B2AB-EB7DC5E9C268} {0385564F-07B4-4264-AB8A-17C393E9140C} = {F6DAEE9A-8BE1-4C4A-BC83-09215517C7DA} {400FAB03-786E-40CC-85A8-04B0C2869B14} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449} + {B0689A4E-07D8-494D-A0C8-791CB1D74E54} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {48EDBBBE-C8EE-4E3C-8B19-97184A487B37} diff --git a/build-everything.proj b/build-everything.proj index b171c83ae04..07e2fcbc687 100644 --- a/build-everything.proj +++ b/build-everything.proj @@ -73,11 +73,17 @@ + + + + + + @@ -112,4 +118,9 @@ + + + + + diff --git a/build.cmd b/build.cmd index 88c6be98fa1..1cf2de6040e 100644 --- a/build.cmd +++ b/build.cmd @@ -664,8 +664,11 @@ if "%BUILD_PROTO%" == "1" ( echo ---------------- Done with proto, starting build ------------------------ if "%BUILD_PHASE%" == "1" ( - echo %_msbuildexe% %msbuildflags% build-everything.proj /p:Configuration=%BUILD_CONFIG% %BUILD_DIAG% /p:BUILD_PUBLICSIGN=%BUILD_PUBLICSIGN% - %_msbuildexe% %msbuildflags% build-everything.proj /p:Configuration=%BUILD_CONFIG% %BUILD_DIAG% /p:BUILD_PUBLICSIGN=%BUILD_PUBLICSIGN% + echo %_msbuildexe% %msbuildflags% build-everything.proj /t:Restore + %_msbuildexe% %msbuildflags% build-everything.proj /t:Restore + + echo %_msbuildexe% %msbuildflags% build-everything.proj /p:Configuration=%BUILD_CONFIG% %BUILD_DIAG% /p:BUILD_PUBLICSIGN=%BUILD_PUBLICSIGN% + %_msbuildexe% %msbuildflags% build-everything.proj /p:Configuration=%BUILD_CONFIG% %BUILD_DIAG% /p:BUILD_PUBLICSIGN=%BUILD_PUBLICSIGN% @if ERRORLEVEL 1 echo Error build failed && goto :failure ) diff --git a/tests/fsharp/test-framework.fs b/tests/fsharp/test-framework.fs index 5753bc1bbcb..5bb3776e8d3 100644 --- a/tests/fsharp/test-framework.fs +++ b/tests/fsharp/test-framework.fs @@ -106,7 +106,6 @@ module Commands = type TestConfig = { EnvironmentVariables : Map CORDIR : string - CORSDK : string CSC : string csc_flags : string BUILD_CONFIG : string @@ -132,7 +131,7 @@ module WindowsPlatform = [| "PROCESSOR_ARCHITECTURE" |] |> Seq.tryPick (fun s -> find s) |> function None -> "" | Some x -> x value = "AMD64" - let clrPaths envVars = + let clrPath envVars = let windir = match envVars |> Map.tryFind "windir" with @@ -149,15 +148,7 @@ module WindowsPlatform = if Is64BitOperatingSystem envVars then CORDIR <- CORDIR.Replace("Framework", "Framework64") - let CORSDK = - let find s = envVars |> Map.tryFind s - [| "WINSDKNETFXTOOLS"; "WindowsSDK_ExecutablePath_x64"; "WindowsSDK_ExecutablePath_x86" |] - |> Seq.tryPick find - |> function - | None -> @"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\x64\" - | Some x -> x - - CORDIR, CORSDK + CORDIR type FSLibPaths = { FSCOREDLLPATH : string } @@ -173,13 +164,13 @@ let config configurationName envVars = let csc_flags = "/nologo" let fsc_flags = "-r:System.Core.dll --nowarn:20 --define:COMPILED" let fsi_flags = "-r:System.Core.dll --nowarn:20 --define:INTERACTIVE --maxerrors:1 --abortonerror" - let CORDIR, CORSDK = WindowsPlatform.clrPaths envVars + let CORDIR = WindowsPlatform.clrPath envVars let Is64BitOperatingSystem = WindowsPlatform.Is64BitOperatingSystem envVars let architectureMoniker = if Is64BitOperatingSystem then "x64" else "x86" let CSC = requireFile (CORDIR ++ "csc.exe") let ILDASM = requireFile (packagesDir ++ ("runtime.win-" + architectureMoniker + ".Microsoft.NETCore.ILDAsm.2.0.3") ++ "runtimes" ++ ("win-" + architectureMoniker) ++ "native" ++ "ildasm.exe") let coreclrdll = requireFile (packagesDir ++ ("runtime.win-" + architectureMoniker + ".Microsoft.NETCore.Runtime.CoreCLR.2.0.3") ++ "runtimes" ++ ("win-" + architectureMoniker) ++ "native" ++ "coreclr.dll") - let PEVERIFY = requireFile (CORSDK ++ "peverify.exe") + let PEVERIFY = requireFile (SCRIPT_ROOT ++ ".." ++ "fsharpqa" ++ "testenv" ++ "src" ++ "PEVerify" ++ "bin" ++ configurationName ++ "net46" ++ "PEVerify.exe") let FSI_FOR_SCRIPTS = match envVars |> Map.tryFind "_fsiexe" with | Some fsiexe when (not (String.IsNullOrWhiteSpace fsiexe)) -> requireFile (SCRIPT_ROOT ++ ".." ++ ".." ++ (fsiexe.Trim([| '\"' |]))) @@ -214,7 +205,6 @@ let config configurationName envVars = { EnvironmentVariables = envVars CORDIR = CORDIR |> Commands.pathAddBackslash - CORSDK = CORSDK |> Commands.pathAddBackslash FSCBinPath = FSCBinPath |> Commands.pathAddBackslash FSCOREDLLPATH = FSCOREDLLPATH ILDASM = ILDASM @@ -236,7 +226,6 @@ let logConfig (cfg: TestConfig) = log "Executables" log "" log "CORDIR =%s" cfg.CORDIR - log "CORSDK =%s" cfg.CORSDK log "CSC =%s" cfg.CSC log "BUILD_CONFIG =%s" cfg.BUILD_CONFIG log "csc_flags =%s" cfg.csc_flags diff --git a/tests/fsharpqa/Source/run.pl b/tests/fsharpqa/Source/run.pl index f168f6415ab..c999def6387 100644 --- a/tests/fsharpqa/Source/run.pl +++ b/tests/fsharpqa/Source/run.pl @@ -264,11 +264,14 @@ # check/set PEVerify my $PEVERIFY = $ENV{PEVERIFY}; unless(defined($PEVERIFY)) { - # Only use peverify if it is in the path - foreach $_ (split /;/, $ENV{PATH}) { - $PEVERIFY = "peverify.exe" if(-e "$_\\peverify.exe"); + my $scriptPath = dirname(__FILE__); + $PEVERIFY = "$scriptPath\\..\\testenv\\src\\PEVerify\\bin\\Release\\net46\\PEVerify.exe"; + if (-e $PEVERIFY) { + $ENV{PEVERIFY} = $PEVERIFY; + } + else { + $ENV{PEVERIFY} = "$scriptPath\\..\\testenv\\src\\PEVerify\\bin\\Debug\\net46\\PEVerify.exe"; } - $ENV{PEVERIFY} = $PEVERIFY; } # Use $ENV{PEVER} if it is defined diff --git a/tests/fsharpqa/testenv/src/PEVerify/CLRHelpers.cs b/tests/fsharpqa/testenv/src/PEVerify/CLRHelpers.cs new file mode 100644 index 00000000000..be1d8346efb --- /dev/null +++ b/tests/fsharpqa/testenv/src/PEVerify/CLRHelpers.cs @@ -0,0 +1,344 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +// ported from https://github.com/dotnet/roslyn/blob/aaee215045c03c4f4b38a66b56d35261ee7f0ddc/src/Test/Utilities/Portable/Platform/Desktop/CLRHelpers.cs + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using PEVerify; +using Roslyn.Test.Utilities.Desktop.ComTypes; + +namespace Roslyn.Test.Utilities.Desktop +{ + public static class CLRHelpers + { + private static readonly Guid s_clsIdClrRuntimeHost = new Guid("90F1A06E-7712-4762-86B5-7A5EBA6BDB02"); + private static readonly Guid s_clsIdCorMetaDataDispenser = new Guid("E5CB7A31-7512-11d2-89CE-0080C792E5D8"); + + public static event ResolveEventHandler ReflectionOnlyAssemblyResolve; + + static CLRHelpers() + { + // Work around CLR bug: + // PE Verifier adds a handler to ReflectionOnlyAssemblyResolve event in AppDomain.EnableResolveAssembliesForIntrospection + // (called from ValidateWorker in Validator.cpp) in which it directly calls Assembly.ReflectionOnlyLoad. + // If that happens before we get a chance to resolve the assembly the resolution fails. + // + // The handlers are invoked in the order they were added until one of them returns non-null assembly. + // Therefore once we call Validate we can't add any more handlers -- they would all follow the CLR one, which fails. + // + // As A workaround we add a single forwarding handler before any calls to Validate and then subscribe all of our true handlers + // to this event. + AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += ReflectionOnlyAssemblyResolveHandler; + } + + private static Assembly ReflectionOnlyAssemblyResolveHandler(object sender, ResolveEventArgs args) + { + var handler = ReflectionOnlyAssemblyResolve; + if (handler != null) + { + return handler(sender, args); + } + + return null; + } + + public static object GetRuntimeInterfaceAsObject(Guid clsid, Guid riid) + { + // This API isn't available on Mono hence we must use reflection to access it. + Debug.Assert(!MonoHelpers.IsRunningOnMono()); + + var getRuntimeInterfaceAsObject = typeof(RuntimeEnvironment).GetMethod("GetRuntimeInterfaceAsObject", BindingFlags.Public | BindingFlags.Static); + return getRuntimeInterfaceAsObject.Invoke(null, new object[] { clsid, riid }); + } + + /// + /// Verifies the specified image. Subscribe to to provide a loader for dependent assemblies. + /// + public static string[] PeVerify(byte[] peImage, bool metadataOnly) + { + // fileName must be null, otherwise AssemblyResolve events won't fire + return PeVerify(peImage, AppDomain.CurrentDomain.Id, assemblyPath: null, metadataOnly: metadataOnly); + } + + /// + /// Verifies the specified file. All dependencies must be on disk next to the file. + /// + public static string[] PeVerify(string filePath, bool metadataOnly) + { + return PeVerify(File.ReadAllBytes(filePath), AppDomain.CurrentDomain.Id, filePath, metadataOnly: metadataOnly); + } + + private static readonly object s_guard = new object(); + + private static string[] PeVerify(byte[] peImage, int domainId, string assemblyPath, bool metadataOnly) + { + if (MonoHelpers.IsRunningOnMono()) + { + // PEverify is currently unsupported on Mono hence return an empty + // set of messages + return new string[0]; + } + + lock (s_guard) + { + GCHandle pinned = GCHandle.Alloc(peImage, GCHandleType.Pinned); + try + { + IntPtr buffer = pinned.AddrOfPinnedObject(); + + ICLRValidator validator = (ICLRValidator)GetRuntimeInterfaceAsObject(s_clsIdClrRuntimeHost, typeof(ICLRRuntimeHost).GUID); + ValidationErrorHandler errorHandler = new ValidationErrorHandler(validator); + + IMetaDataDispenser dispenser = (IMetaDataDispenser)GetRuntimeInterfaceAsObject(s_clsIdCorMetaDataDispenser, typeof(IMetaDataDispenser).GUID); + + // the buffer needs to be pinned during validation + Guid riid = typeof(IMetaDataImport).GUID; + object metaDataImport = null; + if (assemblyPath != null) + { + dispenser.OpenScope(assemblyPath, CorOpenFlags.ofRead, ref riid, out metaDataImport); + } + else + { + dispenser.OpenScopeOnMemory(buffer, (uint)peImage.Length, CorOpenFlags.ofRead, ref riid, out metaDataImport); + } + + IMetaDataValidate metaDataValidate = (IMetaDataValidate)metaDataImport; + metaDataValidate.ValidatorInit(CorValidatorModuleType.ValidatorModuleTypePE, errorHandler); + metaDataValidate.ValidateMetaData(); + + if (!metadataOnly) + { + validator.Validate(errorHandler, (uint)domainId, ValidatorFlags.VALIDATOR_EXTRA_VERBOSE, + ulMaxError: 10, token: 0, fileName: assemblyPath, pe: buffer, ulSize: (uint)peImage.Length); + } + + return errorHandler.GetOutput(); + } + finally + { + pinned.Free(); + } + } + } + + private class ValidationErrorHandler : IVEHandler + { + private readonly ICLRValidator _validator; + private readonly List _output; + private const int MessageLength = 256; + + public ValidationErrorHandler(ICLRValidator validator) + { + _validator = validator; + _output = new List(); + } + + public void SetReporterFtn(long lFnPtr) + { + throw new NotImplementedException(); + } + + public void VEHandler(int VECode, tag_VerError Context, Array psa) + { + StringBuilder sb = new StringBuilder(MessageLength); + string message = null; + + if (Context.Flags == (uint)ValidatorFlags.VALIDATOR_CHECK_PEFORMAT_ONLY) + { + GetErrorResourceString(VECode, sb); + string formatString = ReplaceFormatItems(sb.ToString(), "%08x", ":x8"); + formatString = ReplaceFormatItems(formatString, "%d", ""); + if (psa == null) + { + psa = new object[0]; + } + + message = string.Format(formatString, (object[])psa); + } + else + { + _validator.FormatEventInfo(VECode, Context, sb, (uint)MessageLength - 1, psa); + message = sb.ToString(); + } + + // retail version of peverify.exe filters out CLS warnings... + if (!message.Contains("[CLS]")) + { + _output.Add(message); + } + } + + public string[] GetOutput() + { + return _output.ToArray(); + } + + private static readonly string s_resourceFilePath = Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(), "mscorrc.dll"); + private const uint LOAD_LIBRARY_AS_DATAFILE = 0x00000002; + private static readonly IntPtr s_hMod = LoadLibraryEx(s_resourceFilePath, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE); + + private static void GetErrorResourceString(int code, StringBuilder message) + { + LoadString(s_hMod, (uint)(code & 0x0000FFFF), message, MessageLength - 1); + } + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern int LoadString(IntPtr hInstance, uint uID, StringBuilder lpBuffer, int nBufferMax); + + private static string ReplaceFormatItems(string input, string oldFormat, string newFormat) + { + // not foolproof/efficient, but easy to write/understand... + var parts = input.Replace(oldFormat, "|").Split('|'); + + var formatString = new StringBuilder(); + for (int i = 0; i < parts.Length; i++) + { + formatString.Append(parts[i]); + if (i < (parts.Length - 1)) + { + formatString.Append('{'); + formatString.Append(i); + formatString.Append(newFormat); + formatString.Append('}'); + } + } + + return formatString.ToString(); + } + } + } + + namespace ComTypes + { + [ComImport, CoClass(typeof(object)), Guid("90F1A06C-7712-4762-86B5-7A5EBA6BDB02"), TypeIdentifier] + public interface CLRRuntimeHost : ICLRRuntimeHost + { + } + + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("90F1A06C-7712-4762-86B5-7A5EBA6BDB02"), TypeIdentifier] + public interface ICLRRuntimeHost + { + } + + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("63DF8730-DC81-4062-84A2-1FF943F59FDD"), TypeIdentifier] + public interface ICLRValidator + { + void Validate( + [In, MarshalAs(UnmanagedType.Interface)] IVEHandler veh, + [In] uint ulAppDomainId, + [In] ValidatorFlags ulFlags, + [In] uint ulMaxError, + [In] uint token, + [In, MarshalAs(UnmanagedType.LPWStr)] string fileName, + [In] IntPtr pe, + [In] uint ulSize); + + void FormatEventInfo( + [In, MarshalAs(UnmanagedType.Error)] int hVECode, + [In] tag_VerError Context, + [In, Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder msg, + [In] uint ulMaxLength, + [In, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] Array psa); + } + + [ComImport, Guid("856CA1B2-7DAB-11D3-ACEC-00C04F86C309"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), TypeIdentifier] + public interface IVEHandler + { + void VEHandler([In, MarshalAs(UnmanagedType.Error)] int VECode, [In] tag_VerError Context, [In, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] Array psa); + void SetReporterFtn([In] long lFnPtr); + } + + [ComImport, Guid("809C652E-7396-11D2-9771-00A0C9B4D50C"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), TypeIdentifier] + public interface IMetaDataDispenser + { + void DefineScope( + [In] ref Guid rclsid, + [In] uint dwCreateFlags, + [In] ref Guid riid, + [Out, MarshalAs(UnmanagedType.IUnknown)] out object ppIUnk); + + void OpenScope( + [In, MarshalAs(UnmanagedType.LPWStr)] string szScope, + [In] CorOpenFlags dwOpenFlags, + [In] ref Guid riid, + [Out, MarshalAs(UnmanagedType.IUnknown)] out object ppIUnk); + + void OpenScopeOnMemory( + [In] IntPtr pData, + [In] uint cbData, + [In] CorOpenFlags dwOpenFlags, + [In] ref Guid riid, + [Out, MarshalAs(UnmanagedType.IUnknown)] out object ppIUnk); + } + + [ComImport, Guid("7DAC8207-D3AE-4c75-9B67-92801A497D44"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), TypeIdentifier] + public interface IMetaDataImport + { + } + + [ComImport, Guid("4709C9C6-81FF-11D3-9FC7-00C04F79A0A3"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), TypeIdentifier] + public interface IMetaDataValidate + { + void ValidatorInit([In] CorValidatorModuleType dwModuleType, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnk); + void ValidateMetaData(); + } + + [StructLayout(LayoutKind.Sequential, Pack = 4), TypeIdentifier("5477469e-83b1-11d2-8b49-00a0c9b7c9c4", "mscoree.tag_VerError")] + public struct tag_VerError + { + public uint Flags; + public uint opcode; + public uint uOffset; + public uint Token; + public uint item1_flags; + public IntPtr item1_data; + public uint item2_flags; + public IntPtr item2_data; + } + + public enum ValidatorFlags : uint + { + VALIDATOR_EXTRA_VERBOSE = 0x00000001, + VALIDATOR_SHOW_SOURCE_LINES = 0x00000002, + VALIDATOR_CHECK_ILONLY = 0x00000004, + VALIDATOR_CHECK_PEFORMAT_ONLY = 0x00000008, + VALIDATOR_NOCHECK_PEFORMAT = 0x00000010 + }; + + public enum CorValidatorModuleType : uint + { + ValidatorModuleTypeInvalid = 0x00000000, + ValidatorModuleTypeMin = 0x00000001, + ValidatorModuleTypePE = 0x00000001, + ValidatorModuleTypeObj = 0x00000002, + ValidatorModuleTypeEnc = 0x00000003, + ValidatorModuleTypeIncr = 0x00000004, + ValidatorModuleTypeMax = 0x00000004 + }; + + public enum CorOpenFlags : uint + { + ofRead = 0x00000000, + ofWrite = 0x00000001, + ofReadWriteMask = 0x00000001, + ofCopyMemory = 0x00000002, + ofCacheImage = 0x00000004, + ofManifestMetadata = 0x00000008, + ofReadOnly = 0x00000010, + ofTakeOwnership = 0x00000020, + ofNoTypeLib = 0x00000080, + ofReserved1 = 0x00000100, + ofReserved2 = 0x00000200, + ofReserved = 0xffffff40, + }; + } +} diff --git a/tests/fsharpqa/testenv/src/PEVerify/MonoHelpers.cs b/tests/fsharpqa/testenv/src/PEVerify/MonoHelpers.cs new file mode 100644 index 00000000000..385dcacc5bb --- /dev/null +++ b/tests/fsharpqa/testenv/src/PEVerify/MonoHelpers.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +using System; + +namespace PEVerify +{ + public class MonoHelpers + { + public static bool IsRunningOnMono() + { + return Type.GetType("Mono.Runtime") != null; + } + } +} diff --git a/tests/fsharpqa/testenv/src/PEVerify/PEVerify.csproj b/tests/fsharpqa/testenv/src/PEVerify/PEVerify.csproj new file mode 100644 index 00000000000..3af2b4d23db --- /dev/null +++ b/tests/fsharpqa/testenv/src/PEVerify/PEVerify.csproj @@ -0,0 +1,8 @@ + + + + Exe + net46 + + + diff --git a/tests/fsharpqa/testenv/src/PEVerify/Program.cs b/tests/fsharpqa/testenv/src/PEVerify/Program.cs new file mode 100644 index 00000000000..ecc24afee3e --- /dev/null +++ b/tests/fsharpqa/testenv/src/PEVerify/Program.cs @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +using System; +using System.IO; +using Roslyn.Test.Utilities.Desktop; + +namespace PEVerify +{ + class Program + { + static int Main(string[] args) + { + string assemblyPath = null; + bool metadataOnly = false; + foreach (var arg in args) + { + switch (arg.ToUpperInvariant()) + { + case "/IL": + case "/NOLOGO": + case "/UNIQUE": + // ignore these options + break; + case "/MD": + metadataOnly = true; + break; + default: + if (assemblyPath != null) + { + Console.WriteLine("Assembly already specified or unknown option."); + return -1; + } + + assemblyPath = arg; + break; + } + } + + if (!Path.IsPathRooted(assemblyPath)) + { + var workingDir = Directory.GetCurrentDirectory(); + assemblyPath = Path.Combine(workingDir, assemblyPath); + } + + var errors = CLRHelpers.PeVerify(assemblyPath, metadataOnly); + foreach (var error in errors) + { + Console.WriteLine(error); + } + + return errors.Length; + } + } +} diff --git a/tests/service/FscTests.fs b/tests/service/FscTests.fs index ca3d3999e0a..61c3a29003f 100644 --- a/tests/service/FscTests.fs +++ b/tests/service/FscTests.fs @@ -47,32 +47,12 @@ type PEVerifier () = if runsOnMono then Some ("pedump", "--verify all") else - let rec tryFindFile (fileName : string) (dir : DirectoryInfo) = - let file = Path.Combine(dir.FullName, fileName) - if File.Exists file then Some file - else - dir.GetDirectories() - |> Array.sortBy(fun d -> d.Name) - |> Array.filter(fun d -> - match d.Name with - // skip old SDK directories - | "v6.0" | "v6.0A" | "v7.0" | "v7.0A" | "v7.1" | "v7.1A" -> false - | _ -> true) - |> Array.rev // order by descending -- get latest version - |> Array.tryPick (tryFindFile fileName) - - let tryGetSdkDir (progFiles : Environment.SpecialFolder) = - let progFilesFolder = Environment.GetFolderPath(progFiles) - let dI = DirectoryInfo(Path.Combine(progFilesFolder, "Microsoft SDKs", "Windows")) - if dI.Exists then Some dI - else None - - match Array.tryPick tryGetSdkDir [| Environment.SpecialFolder.ProgramFilesX86; Environment.SpecialFolder.ProgramFiles |] with - | None -> None - | Some sdkDir -> - match tryFindFile "peverify.exe" sdkDir with - | None -> None - | Some pe -> Some (pe, "/UNIQUE /IL /NOLOGO") + let peverifyPath configuration = + Path.Combine(__SOURCE_DIRECTORY__, "..", "fsharpqa", "testenv", "src", "PEVerify", "bin", configuration, "net46", "PEVerify.exe") + let peverify = + if File.Exists(peverifyPath "Debug") then peverifyPath "Debug" + else peverifyPath "Release" + Some (peverify, "/UNIQUE /IL /NOLOGO") #endif static let execute (fileName : string, arguments : string) =