Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion csharp/extractor/Semmle.Extraction.CIL.Driver/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ private static void ExtractAssembly(Layout layout, string assemblyPath, ILogger
{
var sw = new Stopwatch();
sw.Start();
Entities.Assembly.ExtractCIL(layout, assemblyPath, logger, nocache, extractPdbs, trapCompression, out _, out _);
Analyser.ExtractCIL(layout, assemblyPath, logger, nocache, extractPdbs, trapCompression, out _, out _);
sw.Stop();
logger.Log(Severity.Info, " {0} ({1})", assemblyPath, sw.Elapsed);
}
Expand Down
53 changes: 53 additions & 0 deletions csharp/extractor/Semmle.Extraction.CIL/Analyser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using Semmle.Util.Logging;
using System;
using Semmle.Util;
using Semmle.Extraction.CIL.Entities;

namespace Semmle.Extraction.CIL
{
public static class Analyser
{
private static void ExtractCIL(Extractor extractor, TrapWriter trapWriter, bool extractPdbs)
{
using var cilContext = new Context(extractor, trapWriter, extractor.OutputPath, extractPdbs);
cilContext.Populate(new Assembly(cilContext));
cilContext.PopulateAll();
}

/// <summary>
/// Main entry point to the CIL extractor.
/// Call this to extract a given assembly.
/// </summary>
/// <param name="layout">The trap layout.</param>
/// <param name="assemblyPath">The full path of the assembly to extract.</param>
/// <param name="logger">The logger.</param>
/// <param name="nocache">True to overwrite existing trap file.</param>
/// <param name="extractPdbs">Whether to extract PDBs.</param>
/// <param name="trapFile">The path of the trap file.</param>
/// <param name="extracted">Whether the file was extracted (false=cached).</param>
public static void ExtractCIL(Layout layout, string assemblyPath, ILogger logger, bool nocache, bool extractPdbs, TrapWriter.CompressionMode trapCompression, out string trapFile, out bool extracted)
{
trapFile = "";
extracted = false;
try
{
var canonicalPathCache = CanonicalPathCache.Create(logger, 1000);
var pathTransformer = new PathTransformer(canonicalPathCache);
var extractor = new Extractor(false, assemblyPath, logger, pathTransformer);
var transformedAssemblyPath = pathTransformer.Transform(assemblyPath);
var project = layout.LookupProjectOrDefault(transformedAssemblyPath);
using var trapWriter = project.CreateTrapWriter(logger, transformedAssemblyPath.WithSuffix(".cil"), trapCompression, discardDuplicates: true);
trapFile = trapWriter.TrapFile;
if (nocache || !System.IO.File.Exists(trapFile))
{
ExtractCIL(extractor, trapWriter, extractPdbs);
extracted = true;
}
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
logger.Log(Severity.Error, string.Format("Exception extracting {0}: {1}", assemblyPath, ex));
}
}
}
}
16 changes: 8 additions & 8 deletions csharp/extractor/Semmle.Extraction.CIL/Context.Factories.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ namespace Semmle.Extraction.CIL
/// <summary>
/// Provides methods for creating and caching various entities.
/// </summary>
public sealed partial class Context
internal sealed partial class Context
{
private readonly Dictionary<object, Label> ids = new Dictionary<object, Label>();

public T Populate<T>(T e) where T : IExtractedEntity
internal T Populate<T>(T e) where T : IExtractedEntity
{
if (e.Label.Valid)
{
Expand All @@ -27,10 +27,10 @@ public T Populate<T>(T e) where T : IExtractedEntity
}
else
{
e.Label = Cx.GetNewLabel();
Cx.DefineLabel(e, Cx.TrapWriter.Writer, Cx.Extractor);
e.Label = GetNewLabel();
DefineLabel(e);
ids.Add(e, e.Label);
Cx.PopulateLater(() =>
PopulateLater(() =>
{
foreach (var c in e.Contents)
c.Extract(this);
Expand All @@ -42,7 +42,7 @@ public T Populate<T>(T e) where T : IExtractedEntity

if (debugLabels.TryGetValue(id, out var previousEntity))
{
Cx.Extractor.Message(new Message("Duplicate trap ID", id, null, severity: Util.Logging.Severity.Warning));
Extractor.Message(new Message("Duplicate trap ID", id, null, severity: Util.Logging.Severity.Warning));
}
else
{
Expand Down Expand Up @@ -74,9 +74,9 @@ public PrimitiveType Create(PrimitiveTypeCode code)
{
e = new PrimitiveType(this, code)
{
Label = Cx.GetNewLabel()
Label = GetNewLabel()
};
Cx.DefineLabel(e, Cx.TrapWriter.Writer, Cx.Extractor);
DefineLabel(e);
primitiveTypes[(int)code] = e;
}

Expand Down
10 changes: 4 additions & 6 deletions csharp/extractor/Semmle.Extraction.CIL/Context.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@ namespace Semmle.Extraction.CIL
/// Adds additional context that is specific for CIL extraction.
/// One context = one DLL/EXE.
/// </summary>
public sealed partial class Context : IDisposable
internal sealed partial class Context : Extraction.Context, IDisposable
{
private readonly FileStream stream;
private Entities.Assembly? assemblyNull;

public Extraction.Context Cx { get; }
public MetadataReader MdReader { get; }
public PEReader PeReader { get; }
public string AssemblyPath { get; }
Expand All @@ -26,9 +24,9 @@ public Entities.Assembly Assembly
}
public PDB.IPdb? Pdb { get; }

public Context(Extraction.Context cx, string assemblyPath, bool extractPdbs)
public Context(Extractor extractor, TrapWriter trapWriter, string assemblyPath, bool extractPdbs)
: base(extractor, trapWriter)
{
this.Cx = cx;
this.AssemblyPath = assemblyPath;
stream = File.OpenRead(assemblyPath);
PeReader = new PEReader(stream, PEStreamOptions.PrefetchEntireImage);
Expand All @@ -51,7 +49,7 @@ public Context(Extraction.Context cx, string assemblyPath, bool extractPdbs)
Pdb = PDB.PdbReader.Create(assemblyPath, PeReader);
if (Pdb != null)
{
cx.Extractor.Logger.Log(Util.Logging.Severity.Info, string.Format("Found PDB information for {0}", assemblyPath));
Extractor.Logger.Log(Util.Logging.Severity.Info, string.Format("Found PDB information for {0}", assemblyPath));
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion csharp/extractor/Semmle.Extraction.CIL/EmptyContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Semmle.Extraction.CIL
/// <summary>
/// A generic context which does not contain any type parameters.
/// </summary>
public class EmptyContext : IGenericContext
internal class EmptyContext : IGenericContext
{
public EmptyContext(Context cx)
{
Expand Down
53 changes: 3 additions & 50 deletions csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
using System.Reflection;
using System.Globalization;
using System.Collections.Generic;
using Semmle.Util.Logging;
using System;
using Semmle.Extraction.Entities;
using System.IO;
using Semmle.Util;

namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// An assembly to extract.
/// </summary>
public class Assembly : LabelledEntity, ILocation
internal class Assembly : LabelledEntity, ILocation
{
private readonly File file;
private readonly AssemblyName assemblyName;
Expand Down Expand Up @@ -76,7 +73,7 @@ public override IEnumerable<IExtractionProduct> Contents
}
catch (InternalError e)
{
Cx.Cx.ExtractionError("Error processing type definition", e.Message, GeneratedLocation.Create(Cx.Cx), e.StackTrace);
Cx.ExtractionError("Error processing type definition", e.Message, GeneratedLocation.Create(Cx), e.StackTrace);
}

// Limitation of C#: Cannot yield return inside a try-catch.
Expand All @@ -93,57 +90,13 @@ public override IEnumerable<IExtractionProduct> Contents
}
catch (InternalError e)
{
Cx.Cx.ExtractionError("Error processing bytecode", e.Message, GeneratedLocation.Create(Cx.Cx), e.StackTrace);
Cx.ExtractionError("Error processing bytecode", e.Message, GeneratedLocation.Create(Cx), e.StackTrace);
}

if (product != null)
yield return product;
}
}
}

private static void ExtractCIL(Extraction.Context cx, string assemblyPath, bool extractPdbs)
{
using var cilContext = new Context(cx, assemblyPath, extractPdbs);
cilContext.Populate(new Assembly(cilContext));
cilContext.Cx.PopulateAll();
}

/// <summary>
/// Main entry point to the CIL extractor.
/// Call this to extract a given assembly.
/// </summary>
/// <param name="layout">The trap layout.</param>
/// <param name="assemblyPath">The full path of the assembly to extract.</param>
/// <param name="logger">The logger.</param>
/// <param name="nocache">True to overwrite existing trap file.</param>
/// <param name="extractPdbs">Whether to extract PDBs.</param>
/// <param name="trapFile">The path of the trap file.</param>
/// <param name="extracted">Whether the file was extracted (false=cached).</param>
public static void ExtractCIL(Layout layout, string assemblyPath, ILogger logger, bool nocache, bool extractPdbs, TrapWriter.CompressionMode trapCompression, out string trapFile, out bool extracted)
{
trapFile = "";
extracted = false;
try
{
var canonicalPathCache = CanonicalPathCache.Create(logger, 1000);
var pathTransformer = new PathTransformer(canonicalPathCache);
var extractor = new Extractor(false, assemblyPath, logger, pathTransformer);
var transformedAssemblyPath = pathTransformer.Transform(assemblyPath);
var project = layout.LookupProjectOrDefault(transformedAssemblyPath);
using var trapWriter = project.CreateTrapWriter(logger, transformedAssemblyPath.WithSuffix(".cil"), trapCompression, discardDuplicates: true);
trapFile = trapWriter.TrapFile;
if (nocache || !System.IO.File.Exists(trapFile))
{
var cx = new Extraction.Context(extractor, trapWriter);
ExtractCIL(cx, assemblyPath, extractPdbs);
extracted = true;
}
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
logger.Log(Severity.Error, string.Format("Exception extracting {0}: {1}", assemblyPath, ex));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public override IEnumerable<IExtractionProduct> Contents
}
catch
{
Cx.Cx.Extractor.Logger.Log(Util.Logging.Severity.Info,
Cx.Extractor.Logger.Log(Util.Logging.Severity.Info,
$"Attribute decoding is partial. Decoding attribute {constructor.DeclaringType.GetQualifiedName()} failed on {@object}.");
yield break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Semmle.Extraction.CIL
/// <summary>
/// A CIL entity which has been extracted.
/// </summary>
public interface IExtractedEntity : IExtractionProduct, IEntity
internal interface IExtractedEntity : IExtractionProduct, IEntity
{
/// <summary>
/// The contents of the entity.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CIL
/// - Enumerate Contents to produce more extraction products
/// - Extract these until there is nothing left to extract
/// </remarks>
public interface IExtractionProduct
internal interface IExtractionProduct
{
/// <summary>
/// Perform further extraction/population of this item as necessary.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Semmle.Extraction.CIL
/// When we decode a type/method signature, we need access to
/// generic parameters.
/// </summary>
public interface IGenericContext
internal interface IGenericContext
{
Context Cx { get; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ namespace Semmle.Extraction.CIL
/// An entity that needs to be populated during extraction.
/// This assigns a key and optionally extracts its contents.
/// </summary>
public abstract class LabelledEntity : Extraction.LabelledEntity, IExtractedEntity
internal abstract class LabelledEntity : Extraction.LabelledEntity, IExtractedEntity
{
// todo: with .NET 5 this can override the base context, and change the return type.
public Context Cx { get; }
public Context Cx => (Context)base.Context;

protected LabelledEntity(Context cx) : base(cx.Cx)
protected LabelledEntity(Context cx) : base(cx)
{
this.Cx = cx;
}

public override Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public Tuple(string name, params object[] args)

public void Extract(Context cx)
{
cx.Cx.Emit(tuple);
cx.TrapWriter.Emit(tuple);
}

public override string ToString() => tuple.ToString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@ namespace Semmle.Extraction.CIL
/// An entity that has contents to extract. There is no need to populate
/// a key as it's done in the contructor.
/// </summary>
public abstract class UnlabelledEntity : Extraction.UnlabelledEntity, IExtractedEntity
internal abstract class UnlabelledEntity : Extraction.UnlabelledEntity, IExtractedEntity
{
// todo: with .NET 5 this can override the base context, and change the return type.
public Context Cx { get; }
public Context Cx => (Context)base.Context;

protected UnlabelledEntity(Context cx) : base(cx.Cx)
protected UnlabelledEntity(Context cx) : base(cx)
{
Cx = cx;
}

public override Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Semmle.Extraction.CIL.Entities
/// <summary>
/// A constructed type.
/// </summary>
public sealed class ConstructedType : Type
internal sealed class ConstructedType : Type
{
private readonly Type unboundGenericType;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ public PrimitiveTypeCode GetUnderlyingEnumType(Type type)

if (wellKnownEnums.TryGetValue(name, out var code))
{
cx.Cx.Extractor.Logger.Log(Util.Logging.Severity.Debug, $"Using hard coded underlying enum type for {name}");
cx.Extractor.Logger.Log(Util.Logging.Severity.Debug, $"Using hard coded underlying enum type for {name}");
return code;
}

cx.Cx.Extractor.Logger.Log(Util.Logging.Severity.Info, $"Couldn't get underlying enum type for {name}");
cx.Extractor.Logger.Log(Util.Logging.Severity.Info, $"Couldn't get underlying enum type for {name}");

// We can't fall back to Int32, because the type returned here defines how many bytes are read from the
// stream and how those bytes are interpreted.
Expand Down
4 changes: 2 additions & 2 deletions csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@

namespace Semmle.Extraction.CIL.Entities
{
public class File : LabelledEntity, IFileOrFolder
internal class File : LabelledEntity, IFileOrFolder
{
protected string OriginalPath { get; }
protected PathTransformer.ITransformedPath TransformedPath { get; }

public File(Context cx, string path) : base(cx)
{
this.OriginalPath = path;
TransformedPath = cx.Cx.Extractor.PathTransformer.Transform(OriginalPath);
TransformedPath = Cx.Extractor.PathTransformer.Transform(OriginalPath);
}

public override void WriteId(TextWriter trapFile)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Semmle.Extraction.CIL.Entities
{
public sealed class Folder : LabelledEntity, IFileOrFolder
internal sealed class Folder : LabelledEntity, IFileOrFolder
{
private readonly PathTransformer.ITransformedPath transformedPath;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ public IEnumerable<IExtractionProduct> JumpContents(Dictionary<int, Instruction>
// TODO: Find a solution to this.

// For now, just log the error
Cx.Cx.ExtractionError("A CIL instruction jumps outside the current method", null, Extraction.Entities.GeneratedLocation.Create(Cx.Cx), "", Util.Logging.Severity.Warning);
Cx.ExtractionError("A CIL instruction jumps outside the current method", null, Extraction.Entities.GeneratedLocation.Create(Cx), "", Util.Logging.Severity.Warning);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Semmle.Extraction.CIL.Entities
/// <summary>
/// A namespace.
/// </summary>
public sealed class Namespace : TypeContainer
internal sealed class Namespace : TypeContainer
{
public Namespace? ParentNamespace { get; }
public string Name { get; }
Expand Down
Loading