Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono-addins.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirill Osenkov <github@osenkov.com>2017-05-05 01:23:47 +0300
committerKirill Osenkov <github@osenkov.com>2017-05-05 01:23:47 +0300
commit47a9b873b6b99a5678bba4c2ad07bdb836493881 (patch)
tree14412e383f26d1892c1c8e99a7ff2755b5e62ccf /Mono.Addins/Mono.Addins.Database
parent925f835acdcec8e830a722367b563506370bc499 (diff)
Add an IsManagedAssembly() implementation that doesn't throw on native assemblies.
The downside of the previous method is that it was throwing a first-chance exception on native binaries. This makes it harder to debug. Also the new implementation is 4 times faster for success cases and 5-6 times faster for failure cases (native binary).
Diffstat (limited to 'Mono.Addins/Mono.Addins.Database')
-rw-r--r--Mono.Addins/Mono.Addins.Database/Util.cs71
1 files changed, 66 insertions, 5 deletions
diff --git a/Mono.Addins/Mono.Addins.Database/Util.cs b/Mono.Addins/Mono.Addins.Database/Util.cs
index 72e48c1..5a80a35 100644
--- a/Mono.Addins/Mono.Addins.Database/Util.cs
+++ b/Mono.Addins/Mono.Addins.Database/Util.cs
@@ -248,12 +248,73 @@ namespace Mono.Addins.Database
yield return gacDir + "_MSIL";
}
- internal static bool IsManagedAssembly (string file)
+ internal static bool IsManagedAssembly (string filePath)
{
- try {
- AssemblyName.GetAssemblyName (file);
- return true;
- } catch (BadImageFormatException) {
+ try
+ {
+ using (Stream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
+ using (BinaryReader binaryReader = new BinaryReader(fileStream))
+ {
+ if (fileStream.Length < 64)
+ {
+ return false;
+ }
+
+ // PE Header starts @ 0x3C (60). Its a 4 byte header.
+ fileStream.Position = 0x3C;
+ uint peHeaderPointer = binaryReader.ReadUInt32();
+ if (peHeaderPointer == 0)
+ {
+ peHeaderPointer = 0x80;
+ }
+
+ // Ensure there is at least enough room for the following structures:
+ // 24 byte PE Signature & Header
+ // 28 byte Standard Fields (24 bytes for PE32+)
+ // 68 byte NT Fields (88 bytes for PE32+)
+ // >= 128 byte Data Dictionary Table
+ if (peHeaderPointer > fileStream.Length - 256)
+ {
+ return false;
+ }
+
+ // Check the PE signature. Should equal 'PE\0\0'.
+ fileStream.Position = peHeaderPointer;
+ uint peHeaderSignature = binaryReader.ReadUInt32();
+ if (peHeaderSignature != 0x00004550)
+ {
+ return false;
+ }
+
+ // skip over the PEHeader fields
+ fileStream.Position += 20;
+
+ const ushort PE32 = 0x10b;
+ const ushort PE32Plus = 0x20b;
+
+ // Read PE magic number from Standard Fields to determine format.
+ var peFormat = binaryReader.ReadUInt16();
+ if (peFormat != PE32 && peFormat != PE32Plus)
+ {
+ return false;
+ }
+
+ // Read the 15th Data Dictionary RVA field which contains the CLI header RVA.
+ // When this is non-zero then the file contains CLI data otherwise not.
+ ushort dataDictionaryStart = (ushort)(peHeaderPointer + (peFormat == PE32 ? 232 : 248));
+ fileStream.Position = dataDictionaryStart;
+
+ uint cliHeaderRva = binaryReader.ReadUInt32();
+ if (cliHeaderRva == 0)
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+ catch (Exception)
+ {
return false;
}
}