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

Return empty string in InternalAssemblyBuilder.Location #57396

Merged
merged 7 commits into from
Aug 20, 2021

Conversation

pedrobsaila
Copy link
Contributor

Return empty string in AssemblyBuilder.Location

Issue #51924

@jkotas
Copy link
Member

jkotas commented Aug 14, 2021

Could you please also add a simple test? src\libraries\System.Reflection.Emit\tests\AssemblyBuilderTests.cs can be a good place to add it.

@pedrobsaila
Copy link
Contributor Author

pedrobsaila commented Aug 15, 2021

Hi @jkotas , I tried to add a test inside AssemblyBuilderTests, but I have not succeeded yet in getting Location = string.Empty. I found that the test uses assembly System.Private.CoreLib.dll inside .dotnet folder which is downloaded with dotnet-install.ps, instead of the one inside artifacts directory (containing my new code). Do you know how to force using the new version of System.Private.CoreLib.dll ?

@jkotas
Copy link
Member

jkotas commented Aug 15, 2021

the test uses assembly System.Private.CoreLib.dll inside .dotnet folder

That is not expected. How are you running the tests ? https://github.com/dotnet/runtime/blob/main/docs/workflow/testing/libraries/testing.md has the instructions for running the tests.

@pedrobsaila
Copy link
Contributor Author

pedrobsaila commented Aug 15, 2021

I use this link dotnet/sdk#7419 (comment) to debug tests inside VS

@pedrobsaila pedrobsaila changed the title Return empty string in AssemblyBuilder.Location Return empty string in InternalAssemblyBuilder.Location Aug 15, 2021
Comment on lines 430 to 434
object internalAssemblyBuilder = assembly.GetType()
.GetProperty("InternalAssembly", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(assembly);
object locationObj = internalAssemblyBuilder.GetType().GetProperty("Location", BindingFlags.Public | BindingFlags.Instance)
.GetValue(internalAssemblyBuilder);
string location = Assert.IsType<string>(locationObj);
Copy link
Member

Choose a reason for hiding this comment

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

Would it be possible to rewrite the test to not use private reflection?
The test is valid regardless of how the builder is implemented, but now it would fail if we changed the implementation (to rename/remove the internal property).
I think it should be possible to call something like AssemblyLoadContext.Default.Assemblies and find the one just defined and validate it there.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks for the clue

[Fact]
public void DefineDynamicAssembly_InternalAssemblyLocationIsEmpty()
{
AssemblyBuilder assembly = Helpers.DynamicAssembly();
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
AssemblyBuilder assembly = Helpers.DynamicAssembly();
AssemblyBuilder assembly = Helpers.DynamicAssembly(nameof(DefineDynamicAssembly_InternalAssemblyLocationIsEmpty));

Otherwise the assembly will get a default name TestAssembly and the test might succeed by accident if some other test uses the same assembly name. (Unlikely as the test would still likely do the right validation, but still)

{
AssemblyBuilder assembly = Helpers.DynamicAssembly(nameof(DefineDynamicAssembly_InternalAssemblyLocationIsEmpty));
Assembly internalAssemblyBuilder = AssemblyLoadContext.Default.Assemblies
.FirstOrDefault(_ => _.FullName == assembly.FullName);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
.FirstOrDefault(_ => _.FullName == assembly.FullName);
.FirstOrDefault(a => a.FullName == assembly.FullName);

Don't use _ for a variable name if you are actually going to use the variable. _ is used when you want to ignore the variable/return value.

@vitek-karas
Copy link
Member

@lambdageek Could you please advice about the behavior expected in Mono? It seems that defining a dynamic assembly doesn't add that assembly to the AssemblyLoadContext.Assemblies collection.

On top of that I expect the Mono's version to throw from the Location property - but that should be easily fixable as part of this change.

@lambdageek
Copy link
Member

@lambdageek Could you please advice about the behavior expected in Mono?

It seems that defining a dynamic assembly doesn't add that assembly to the AssemblyLoadContext.Assemblies collection.

Seems like a bug in Mono's AssemblyLoadContext.GetLoadContext - a mono AssemblyBuilder doesn't derive from RuntimeAssembly.

RuntimeAssembly? rtAsm = assembly as RuntimeAssembly;
// We only support looking up load context for runtime assemblies.
if (rtAsm != null)
{
RuntimeAssembly runtimeAssembly = rtAsm;
IntPtr ptrAssemblyLoadContext = GetLoadContextForAssembly(runtimeAssembly);
loadContextForAssembly = GetAssemblyLoadContext(ptrAssemblyLoadContext);
}
return loadContextForAssembly;

On top of that I expect the Mono's version to throw from the Location property - but that should be easily fixable as part of this change.

I think it probably throws from here:

public virtual string Location => throw NotImplemented.ByDesign;

So we'd need a new override in

public sealed partial class AssemblyBuilder : Assembly

@pedrobsaila
Copy link
Contributor Author

pedrobsaila commented Aug 17, 2021

I use now AppDomain.CurrentDomain.GetAssemblies instead of AssemblyLoadContext.Assemblies in my test , it seemed to return the test assembly on my machine for coreclr and mono.

Location should be updated to return string.Empty in src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs because it's the partial class of
/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.Mono.cs

I'm not so sure of what I did, if there's something to adjust or drop, I would be happy to update my PR.

Copy link
Member

@vitek-karas vitek-karas left a comment

Choose a reason for hiding this comment

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

Thanks a lot for the fix! LGTM

@vitek-karas vitek-karas merged commit 56d881f into dotnet:main Aug 20, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Sep 19, 2021
@pedrobsaila pedrobsaila deleted the 51924/returnEmptyString branch October 28, 2021 07:02
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Reflection community-contribution Indicates that the PR has been added by a community member
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

5 participants