public static void VerifyMetadataEqualModuloMvid(Stream peStream1, Stream peStream2)
        {
            peStream1.Position = 0;
            peStream2.Position = 0;

            var peReader1 = new PEReader(peStream1);
            var peReader2 = new PEReader(peStream2);

            var md1 = peReader1.GetMetadata().GetContent();
            var md2 = peReader2.GetMetadata().GetContent();

            var mdReader1 = peReader1.GetMetadataReader();
            var mdReader2 = peReader2.GetMetadataReader();

            var mvidIndex1 = mdReader1.GetModuleDefinition().Mvid;
            var mvidIndex2 = mdReader2.GetModuleDefinition().Mvid;

            var mvidOffset1 = mdReader1.GetHeapMetadataOffset(HeapIndex.Guid) + 16 * (MetadataTokens.GetHeapOffset(mvidIndex1) - 1);
            var mvidOffset2 = mdReader2.GetHeapMetadataOffset(HeapIndex.Guid) + 16 * (MetadataTokens.GetHeapOffset(mvidIndex2) - 1);

            if (!md1.RemoveRange(mvidOffset1, 16).SequenceEqual(md1.RemoveRange(mvidOffset2, 16)))
            {
                var mdw1 = new StringWriter();
                var mdw2 = new StringWriter();
                new MetadataVisualizer(mdReader1, mdw1).Visualize();
                new MetadataVisualizer(mdReader2, mdw2).Visualize();
                mdw1.Flush();
                mdw2.Flush();

                AssertEx.AssertResultsEqual(mdw1.ToString(), mdw2.ToString());
            }
        }
        public void CorLibWithAssemblyReferences_Pdb()
        {
            string sourceLib =
@"namespace Namespace
{
    public class Private { }
}";
            var compLib = CreateCompilationWithMscorlib(sourceLib, assemblyName: "System.Private.Library");
            compLib.VerifyDiagnostics();
            var refLib = compLib.EmitToImageReference(aliases: ImmutableArray.Create("A"));

            string sourceCorLib =
@"extern alias A;
#pragma warning disable 8019
using N = A::Namespace;
namespace System
{
    public class Object
    {
        public void F()
        {
        }
    }
#pragma warning disable 0436
    public class Void : Object { }
#pragma warning restore 0436
}";
            // Create a custom corlib with a reference to compilation
            // above and a reference to the actual mscorlib.
            var compCorLib = CreateCompilation(sourceCorLib, assemblyName: CorLibAssemblyName, references: new[] { MscorlibRef, refLib });
            compCorLib.VerifyDiagnostics();
            var objectType = compCorLib.SourceAssembly.GlobalNamespace.GetMember<NamedTypeSymbol>("System.Object");
            Assert.NotNull(objectType.BaseType);

            var pdbPath = Temp.CreateDirectory().Path;
            ImmutableArray<byte> peBytes;
            ImmutableArray<byte> pdbBytes;
            ExpressionCompilerTestHelpers.EmitCorLibWithAssemblyReferences(
                compCorLib,
                pdbPath,
                moduleBuilder => new PEAssemblyBuilderWithAdditionalReferences(moduleBuilder, objectType),
                out peBytes,
                out pdbBytes);
            var symReader = SymReaderFactory.CreateReader(pdbBytes);

            using (var reader = new PEReader(peBytes))
            {
                var metadata = reader.GetMetadata();
                var module = metadata.ToModuleMetadata(ignoreAssemblyRefs: true);
                var metadataReader = metadata.ToMetadataReader();
                var moduleInstance = ModuleInstance.Create(metadata, metadataReader.GetModuleVersionIdOrThrow(), symReader);

                // Verify the module declares System.Object.
                Assert.True(metadataReader.DeclaresTheObjectClass());
                // Verify the PEModule has no assembly references.
                Assert.Equal(0, module.Module.ReferencedAssemblies.Length);
                // Verify the underlying metadata has the expected assembly references.
                var actualReferences = metadataReader.AssemblyReferences.Select(r => metadataReader.GetString(metadataReader.GetAssemblyReference(r).Name)).ToImmutableArray();
                AssertEx.Equal(new[] { "mscorlib", "System.Private.Library" }, actualReferences);

                using (var runtime = RuntimeInstance.Create(new[] { moduleInstance }))
                {
                    string error;
                    var context = CreateMethodContext(runtime, "System.Object.F");
                    var testData = new CompilationTestData();
                    // Invalid import: "using N = A::Namespace;".
                    context.CompileExpression(
                        "new N.Private()",
                        out error,
                        testData);
                    Assert.Equal("error CS0246: The type or namespace name 'N' could not be found (are you missing a using directive or an assembly reference?)", error);
                }
            }
        }
        // Mimic what at least one version of at least one obfuscator has done to use the undocumented/non-standard extra-data flag.
        // If setFlag is false, do everything but setting the flag.
        private static unsafe byte[] ObfuscateWithExtraData(byte[] unobfuscated, bool setFlag = true)
        {
            int offsetToMetadata;
            int offsetToModuleTable;
            int offsetToMetadataSize;
            int tableStreamIndex = -1;
            StreamHeaderInfo[] streamHeaders;

            fixed (byte* ptr = unobfuscated)
            {
                using (var peReader = new PEReader(ptr, unobfuscated.Length))
                {
                    PEMemoryBlock metadata = peReader.GetMetadata();
                    offsetToMetadata = peReader.PEHeaders.MetadataStartOffset;
                    offsetToMetadataSize = peReader.PEHeaders.CorHeaderStartOffset + 12;
                    offsetToModuleTable = offsetToMetadata + peReader.GetMetadataReader().GetTableMetadataOffset(TableIndex.Module);

                    // skip root header
                    BlobReader blobReader = metadata.GetReader();
                    blobReader.ReadUInt32(); // signature
                    blobReader.ReadUInt16(); // major version
                    blobReader.ReadUInt16(); // minor version
                    blobReader.ReadUInt32(); // reserved
                    int versionStringSize = blobReader.ReadInt32();
                    blobReader.SkipBytes(versionStringSize);

                    // read stream headers to collect offsets and sizes to adjust later
                    blobReader.ReadUInt16(); // reserved
                    int streamCount = blobReader.ReadInt16();
                    streamHeaders = new StreamHeaderInfo[streamCount];

                    for (int i = 0; i < streamCount; i++)
                    {
                        streamHeaders[i].OffsetToOffset = offsetToMetadata + blobReader.Offset;
                        streamHeaders[i].Offset = blobReader.ReadInt32();
                        streamHeaders[i].OffsetToSize = offsetToMetadata + blobReader.Offset;
                        streamHeaders[i].Size = blobReader.ReadInt32();

                        string name = blobReader.ReadUtf8NullTerminated();
                        if (name == "#~")
                        {
                            tableStreamIndex = i;
                        }

                        blobReader.Align(4);
                    }
                }
            }

            const int sizeOfExtraData = 4;
            int offsetToTableStream = offsetToMetadata + streamHeaders[tableStreamIndex].Offset;
            int offsetToHeapSizeFlags = offsetToTableStream + 6;

            // copy unobfuscated to obfuscated, leaving room for 4 bytes of data right before the module table.
            byte[] obfuscated = new byte[unobfuscated.Length + sizeOfExtraData];
            Array.Copy(unobfuscated, 0, obfuscated, 0, offsetToModuleTable);
            Array.Copy(unobfuscated, offsetToModuleTable, obfuscated, offsetToModuleTable + sizeOfExtraData, unobfuscated.Length - offsetToModuleTable);

            fixed (byte* ptr = obfuscated)
            {
                // increase size of metadata
                *(int*)(ptr + offsetToMetadataSize) += sizeOfExtraData;

                // increase size of table stream
                *(int*)(ptr + streamHeaders[tableStreamIndex].OffsetToSize) += sizeOfExtraData;

                // adjust offset of any streams that follow it
                for (int i = 0; i < streamHeaders.Length; i++)
                    if (streamHeaders[i].Offset > streamHeaders[tableStreamIndex].Offset)
                        *(int*)(ptr + streamHeaders[i].OffsetToOffset) += sizeOfExtraData;
            }

            // write non-zero "extra data" to make sure so that our assertion of leading Module.Generation == 0
            // cannot succeed if extra data is interpreted as the start of the module table.
            for (int i = 0; i < sizeOfExtraData; i++)
            {
                obfuscated[offsetToModuleTable + i] = 0xCC;
            }

            if (setFlag)
            {
                // set the non-standard ExtraData flag indicating that these 4 bytes are present
                obfuscated[offsetToHeapSizeFlags] |= (byte)HeapSizes.ExtraData;
            }

            return obfuscated;
        }
        public void CorLibWithAssemblyReferences()
        {
            string sourceLib =
@"public class Private1
{
}
public class Private2
{
}";
            var compLib = CreateCompilationWithMscorlib(sourceLib, assemblyName: "System.Private.Library");
            compLib.VerifyDiagnostics();
            var refLib = compLib.EmitToImageReference();

            string sourceCorLib =
@"using System.Runtime.CompilerServices;
[assembly: TypeForwardedTo(typeof(Private2))]
namespace System
{
    public class Object
    {
        public Private1 F() => null;
    }
#pragma warning disable 0436
    public class Void : Object { }
#pragma warning restore 0436
}";
            // Create a custom corlib with a reference to compilation
            // above and a reference to the actual mscorlib.
            var compCorLib = CreateCompilation(sourceCorLib, assemblyName: CorLibAssemblyName, references: new[] { MscorlibRef, refLib });
            compCorLib.VerifyDiagnostics();
            var objectType = compCorLib.SourceAssembly.GlobalNamespace.GetMember<NamedTypeSymbol>("System.Object");
            Assert.NotNull(objectType.BaseType);

            ImmutableArray<byte> peBytes;
            ImmutableArray<byte> pdbBytes;
            ExpressionCompilerTestHelpers.EmitCorLibWithAssemblyReferences(
                compCorLib,
                null,
                moduleBuilder => new PEAssemblyBuilderWithAdditionalReferences(moduleBuilder, objectType),
                out peBytes,
                out pdbBytes);

            using (var reader = new PEReader(peBytes))
            {
                var metadata = reader.GetMetadata();
                var module = metadata.ToModuleMetadata(ignoreAssemblyRefs: true);
                var metadataReader = metadata.ToMetadataReader();
                var moduleInstance = ModuleInstance.Create(metadata, metadataReader.GetModuleVersionIdOrThrow());

                // Verify the module declares System.Object.
                Assert.True(metadataReader.DeclaresTheObjectClass());
                // Verify the PEModule has no assembly references.
                Assert.Equal(0, module.Module.ReferencedAssemblies.Length);
                // Verify the underlying metadata has the expected assembly references.
                var actualReferences = metadataReader.AssemblyReferences.Select(r => metadataReader.GetString(metadataReader.GetAssemblyReference(r).Name)).ToImmutableArray();
                AssertEx.Equal(new[] { "mscorlib", "System.Private.Library" }, actualReferences);

                var source =
@"class C
{
    static void M()
    {
    }
}";
                var comp = CreateCompilation(source, options: TestOptions.DebugDll, references: new[] { refLib, AssemblyMetadata.Create(module).GetReference() });
                comp.VerifyDiagnostics();

                using (var runtime = RuntimeInstance.Create(new[] { comp.ToModuleInstance(), moduleInstance }))
                {
                    string error;
                    var context = CreateMethodContext(runtime, "C.M");

                    // Valid expression.
                    var testData = new CompilationTestData();
                    context.CompileExpression(
                        "new object()",
                        out error,
                        testData);
                    Assert.Null(error);
                    testData.GetMethodData("<>x.<>m0").VerifyIL(
@"{
  // Code size        6 (0x6)
  .maxstack  1
  IL_0000:  newobj     ""object..ctor()""
  IL_0005:  ret
}");

                    // Invalid expression: System.Int32 is not defined in corlib above.
                    testData = new CompilationTestData();
                    context.CompileExpression(
                        "1",
                        out error,
                        testData);
                    Assert.Equal("error CS0518: Predefined type 'System.Int32' is not defined or imported", error);

                    // Invalid expression: type in method signature from missing referenced assembly.
                    testData = new CompilationTestData();
                    context.CompileExpression(
                        "(new object()).F()",
                        out error,
                        testData);
                    Assert.Equal("error CS0570: 'object.F()' is not supported by the language", error);

                    // Invalid expression: type forwarded to missing referenced assembly.
                    testData = new CompilationTestData();
                    context.CompileExpression(
                        "new Private2()",
                        out error,
                        testData);
                    Assert.Equal("error CS0246: The type or namespace name 'Private2' could not be found (are you missing a using directive or an assembly reference?)", error);
                }
            }
        }