Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix alignment padding and add test for saving managed resources #110915

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
128 changes: 64 additions & 64 deletions src/libraries/System.Reflection.Emit/tests/AssemblyBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -411,100 +411,100 @@ private static void VerifyAssemblyBuilder(AssemblyBuilder assembly, AssemblyName
Assert.Empty(assembly.GetTypes());
}

private static void SamplePrivateMethod ()
{
}
private static void SamplePrivateMethod()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whitespace-only changes to this file

{
}

internal static void SampleInternalMethod ()
{
}
internal static void SampleInternalMethod()
{
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))]
void Invoke_Private_CrossAssembly_ThrowsMethodAccessException()
{
TypeBuilder tb = Helpers.DynamicType(TypeAttributes.Public);
var mb = tb.DefineMethod ("MyMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new Type[] { });
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))]
void Invoke_Private_CrossAssembly_ThrowsMethodAccessException()
{
TypeBuilder tb = Helpers.DynamicType(TypeAttributes.Public);
var mb = tb.DefineMethod("MyMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new Type[] { });

var ilg = mb.GetILGenerator ();
var ilg = mb.GetILGenerator();

var callee = typeof (AssemblyTests).GetMethod ("SamplePrivateMethod", BindingFlags.Static | BindingFlags.NonPublic);
var callee = typeof(AssemblyTests).GetMethod("SamplePrivateMethod", BindingFlags.Static | BindingFlags.NonPublic);

ilg.Emit (OpCodes.Call, callee);
ilg.Emit (OpCodes.Ret);
ilg.Emit(OpCodes.Call, callee);
ilg.Emit(OpCodes.Ret);

var ty = tb.CreateType ();
var ty = tb.CreateType();

var mi = ty.GetMethod ("MyMethod", BindingFlags.Static | BindingFlags.Public);
var mi = ty.GetMethod("MyMethod", BindingFlags.Static | BindingFlags.Public);

var d = (Action) mi.CreateDelegate (typeof(Action));
var d = (Action)mi.CreateDelegate(typeof(Action));

Assert.Throws<MethodAccessException>(() => d ());
}
Assert.Throws<MethodAccessException>(() => d());
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))]
void Invoke_Internal_CrossAssembly_ThrowsMethodAccessException()
{
TypeBuilder tb = Helpers.DynamicType(TypeAttributes.Public);
var mb = tb.DefineMethod ("MyMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new Type[] { });
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))]
void Invoke_Internal_CrossAssembly_ThrowsMethodAccessException()
{
TypeBuilder tb = Helpers.DynamicType(TypeAttributes.Public);
var mb = tb.DefineMethod("MyMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new Type[] { });

var ilg = mb.GetILGenerator ();
var ilg = mb.GetILGenerator();

var callee = typeof (AssemblyTests).GetMethod ("SampleInternalMethod", BindingFlags.Static | BindingFlags.NonPublic);
var callee = typeof(AssemblyTests).GetMethod("SampleInternalMethod", BindingFlags.Static | BindingFlags.NonPublic);

ilg.Emit (OpCodes.Call, callee);
ilg.Emit (OpCodes.Ret);
ilg.Emit(OpCodes.Call, callee);
ilg.Emit(OpCodes.Ret);

var ty = tb.CreateType ();
var ty = tb.CreateType();

var mi = ty.GetMethod ("MyMethod", BindingFlags.Static | BindingFlags.Public);
var mi = ty.GetMethod("MyMethod", BindingFlags.Static | BindingFlags.Public);

var d = (Action) mi.CreateDelegate (typeof(Action));
var d = (Action)mi.CreateDelegate(typeof(Action));

Assert.Throws<MethodAccessException>(() => d ());
}
Assert.Throws<MethodAccessException>(() => d());
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))]
void Invoke_Private_SameAssembly_ThrowsMethodAccessException()
{
ModuleBuilder modb = Helpers.DynamicModule();
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))]
void Invoke_Private_SameAssembly_ThrowsMethodAccessException()
{
ModuleBuilder modb = Helpers.DynamicModule();

string calleeName = "PrivateMethod";
string calleeName = "PrivateMethod";

TypeBuilder tbCalled = modb.DefineType ("CalledClass", TypeAttributes.Public);
var mbCalled = tbCalled.DefineMethod (calleeName, MethodAttributes.Private | MethodAttributes.Static);
mbCalled.GetILGenerator().Emit (OpCodes.Ret);
TypeBuilder tbCalled = modb.DefineType("CalledClass", TypeAttributes.Public);
var mbCalled = tbCalled.DefineMethod(calleeName, MethodAttributes.Private | MethodAttributes.Static);
mbCalled.GetILGenerator().Emit(OpCodes.Ret);

var tyCalled = tbCalled.CreateType();
var callee = tyCalled.GetMethod (calleeName, BindingFlags.NonPublic | BindingFlags.Static);
var tyCalled = tbCalled.CreateType();
var callee = tyCalled.GetMethod(calleeName, BindingFlags.NonPublic | BindingFlags.Static);

TypeBuilder tb = modb.DefineType("CallerClass", TypeAttributes.Public);
var mb = tb.DefineMethod ("MyMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new Type[] { });
TypeBuilder tb = modb.DefineType("CallerClass", TypeAttributes.Public);
var mb = tb.DefineMethod("MyMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new Type[] { });

var ilg = mb.GetILGenerator ();
var ilg = mb.GetILGenerator();

ilg.Emit (OpCodes.Call, callee);
ilg.Emit (OpCodes.Ret);
ilg.Emit(OpCodes.Call, callee);
ilg.Emit(OpCodes.Ret);

var ty = tb.CreateType ();
var ty = tb.CreateType();

var mi = ty.GetMethod ("MyMethod", BindingFlags.Static | BindingFlags.Public);
var mi = ty.GetMethod("MyMethod", BindingFlags.Static | BindingFlags.Public);

var d = (Action) mi.CreateDelegate (typeof(Action));
var d = (Action)mi.CreateDelegate(typeof(Action));

Assert.Throws<MethodAccessException>(() => d ());
}
Assert.Throws<MethodAccessException>(() => d());
}

[Fact]
public void DefineDynamicAssembly_AssemblyBuilderLocationIsEmpty_InternalAssemblyBuilderLocationIsEmpty()
{
AssemblyBuilder assembly = Helpers.DynamicAssembly(nameof(DefineDynamicAssembly_AssemblyBuilderLocationIsEmpty_InternalAssemblyBuilderLocationIsEmpty));
Assembly internalAssemblyBuilder = AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(a => a.FullName == assembly.FullName);
[Fact]
public void DefineDynamicAssembly_AssemblyBuilderLocationIsEmpty_InternalAssemblyBuilderLocationIsEmpty()
{
AssemblyBuilder assembly = Helpers.DynamicAssembly(nameof(DefineDynamicAssembly_AssemblyBuilderLocationIsEmpty_InternalAssemblyBuilderLocationIsEmpty));
Assembly internalAssemblyBuilder = AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(a => a.FullName == assembly.FullName);

Assert.Empty(assembly.Location);
Assert.NotNull(internalAssemblyBuilder);
Assert.Empty(internalAssemblyBuilder.Location);
}
Assert.Empty(assembly.Location);
Assert.NotNull(internalAssemblyBuilder);
Assert.Empty(internalAssemblyBuilder.Location);
}

[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public static void ThrowsWhenDynamicCodeNotSupported()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections;
using System.Globalization;
using System.IO;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
using System.Resources;
using Microsoft.DotNet.RemoteExecutor;
using Xunit;

namespace System.Reflection.Emit.Tests
{
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
public class AssemblySaveResourceTests
{
[ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
[InlineData(new byte[] { 1 }, "01")]
[InlineData(new byte[] { 1, 2 }, "01-02")] // Verify blob padding by adding a byte.
public void ManagedResources(byte[] byteValue, string byteValueExpected)
{
PersistedAssemblyBuilder ab = new PersistedAssemblyBuilder(new AssemblyName("MyAssemblyWithResource"), typeof(object).Assembly);
ab.DefineDynamicModule("MyModule");
MetadataBuilder metadata = ab.GenerateMetadata(out BlobBuilder ilStream, out _);

using MemoryStream memoryStream = new MemoryStream();
ResourceWriter myResourceWriter = new ResourceWriter(memoryStream);
myResourceWriter.AddResource("StringResource", "Value");
myResourceWriter.AddResource("ByteResource", byteValue);
myResourceWriter.Close();

byte[] data = memoryStream.ToArray();
BlobBuilder resourceBlob = new BlobBuilder();
resourceBlob.WriteInt32(data.Length);
resourceBlob.WriteBytes(data);

metadata.AddManifestResource(
ManifestResourceAttributes.Public,
metadata.GetOrAddString("MyResource.resources"),
implementation: default,
offset: 0);

ManagedPEBuilder peBuilder = new ManagedPEBuilder(
header: PEHeaderBuilder.CreateLibraryHeader(),
metadataRootBuilder: new MetadataRootBuilder(metadata),
ilStream: ilStream,
managedResources: resourceBlob);

BlobBuilder blob = new BlobBuilder();
peBuilder.Serialize(blob);

// Create a temporary assembly.
string tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".dll");
steveharter marked this conversation as resolved.
Show resolved Hide resolved
using (FileStream fileStream = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write))
{
blob.WriteContentTo(fileStream);
}

// In order to verify the resources work with ResourceManager, we need to load the assembly.
using (RemoteInvokeHandle remoteHandle = RemoteExecutor.Invoke(static (tempFilePath, byteValue, byteValueExpected) =>
{
Assembly readAssembly = Assembly.LoadFile(tempFilePath);

// Use ResourceReader to read the resources.
using Stream readStream = readAssembly.GetManifestResourceStream("MyResource.resources")!;
using ResourceReader reader = new(readStream);
Verify(reader.GetEnumerator());

// Use ResourceManager to read the resources.
ResourceManager rm = new ResourceManager("MyResource", readAssembly);
ResourceSet resourceSet = rm.GetResourceSet(CultureInfo.InvariantCulture, createIfNotExists: true, tryParents: false);
Verify(resourceSet.GetEnumerator());

void Verify(IDictionaryEnumerator resources)
{
Assert.True(resources.MoveNext());
DictionaryEntry resource = (DictionaryEntry)resources.Current;
Assert.Equal("ByteResource", resource.Key);
Assert.Equal(byteValueExpected, byteValue);

Assert.True(resources.MoveNext());
resource = (DictionaryEntry)resources.Current;
Assert.Equal("StringResource", resource.Key);
Assert.Equal("Value", resource.Value);

Assert.False(resources.MoveNext());
}
}, tempFilePath, BitConverter.ToString(byteValue), byteValueExpected)) { }

File.Delete(tempFilePath);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
<Compile Include="PersistedAssemblyBuilder\AssemblySaveTypeBuilderAPIsTests.cs" />
<Compile Include="PersistedAssemblyBuilder\AssemblySaveModuleBuilderTests.cs" />
<Compile Include="PersistedAssemblyBuilder\AssemblySavePropertyBuilderTests.cs" />
<Compile Include="PersistedAssemblyBuilder\AssemblySaveResourceTests.cs" />
<Compile Include="PersistedAssemblyBuilder\AssemblySaveTools.cs" />
<Compile Include="PersistedAssemblyBuilder\AssemblySaveTypeBuilderTests.cs" />
<Compile Include="PortablePdb\ILGeneratorScopesAndSequencePointsTests.cs" />
Expand Down
Loading