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

Implement DynamicMethod.RTDynamicMethod.CreateDelegate. #79427

Merged
merged 3 commits into from
Dec 13, 2022

Conversation

madelson
Copy link
Contributor

@madelson madelson commented Dec 9, 2022

The implementation simply calls back to DynamicMethod.CreateDelegate.

fix #78365

The implementation simply calls back to DynamicMethod.CreateDelegate.

fix dotnet#78365
@ghost ghost added the community-contribution Indicates that the PR has been added by a community member label Dec 9, 2022
@ghost
Copy link

ghost commented Dec 9, 2022

Tagging subscribers to this area: @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

Issue Details

The implementation simply calls back to DynamicMethod.CreateDelegate.

fix #78365

Author: madelson
Assignees: -
Labels:

area-System.Reflection

Milestone: -


namespace System.Reflection.Emit.Tests;

public class DynamicMethodTests
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was surprised not to find an existing test file for this; is there one in another place that I just missed?

Copy link
Member

Choose a reason for hiding this comment

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

DynamicMethod / RTDynamicMethod split is a left-over from Code Access Security that was removed in .NET Core. We did not bring any Core Access Security tests over.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure why this didn't come up in my search, but thanks! Once there is some alignment about whether this approach is even ok, I'll relocate the test to that project.

Func<int> getTargetLength = getLength.Method.CreateDelegate<Func<int>>("ccc");
Assert.Equal(3, getTargetLength());

Assert.Equal(getLength, getTargetLength.Method.CreateDelegate<Func<string, int>>());
Copy link
Contributor Author

@madelson madelson Dec 9, 2022

Choose a reason for hiding this comment

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

Note: this change is not sufficient to get Delegate.CreateDelegate working because that method requires a RuntimeMethodInfo. I think that could be fixed by also checking for DynamicMethod / RTDynamicMethod explicitly (or perhaps better by just deferring to MethodInfo.CreateDelegate), but that felt out of scope. Let me know if that should be added in this PR or filed as a separate enhancement.

@@ -430,6 +430,9 @@ public override string ToString()

public override CallingConventions CallingConvention => _callingConvention;

public override Delegate CreateDelegate(Type delegateType) => _owner.CreateDelegate(delegateType);
Copy link
Member

Choose a reason for hiding this comment

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

This gives up on controlling the access to the DynamicMethod described in https://github.com/dotnet/runtime/pull/79427/files#diff-d9e708636c5ff1b043b18cbe86e7b7b32267e6a0be131c589d64c11061557fadR382-R383.

If we want to give up on controlling the access to the DynamicMethod, we should just delete RTDynamicMethod and fold with DynamicMethod.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jkotas I'm not sure I understand why implementing CreateDelegate changes the degree of access. If you have access to a Delegate instance that was created from a DynamicMethod, you can already invoke the generated code. You can also effectively "cast" between delegate types by creating a wrapper delegate that just invokes the original delegate.

If we get rid of RTDynamicMethod, then a delegate owner could cast to DynamicMethod and access the ILGenerator. I'm not sure that matters, since emitting more IL doesn't seem to change the method behavior once it has been compiled (or perhaps I just didn't structure my method correctly).

If we want to give up on controlling the access to the DynamicMethod, we should just delete RTDynamicMethod and fold with DynamicMethod.

Probably the more important question. Do we want to give up this control? I know CAS is gone, but I don't have context into what exactly this control was accomplishing.

Copy link
Member

Choose a reason for hiding this comment

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

what exactly this control was accomplishing.

It was preventing MethodInfo acquired from exception or stack trace to be used for invocation. CAS controlled permission for running code. It was not ok to leak permission to run fully trusted piece of code to partially trusted code. For example:

try
{
    ... call dynamic method that was created by fully trusted code ...
    ... assume that that the dynamic method threw an exception ...
}
catch (Exception e)
{
    // Let's assume that this is partially trusted code. It was important for CAS that the partially trusted code
    // cannot gain permission to run the dynamic method by inspecting the exception.
    MethodInfo mi = (MethodInfo)e.TargetSite;
    
    // `mi` cannot be used to call the method in any way here.
    // `mi.Invoke` fails
    // `mi.CreateDelegate` fails   
}

Do we want to give up this control?

I think it is fine to give up this control. We do not care about CAS.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Very interesting! Thanks for the explanation.

Makes sense that this can be done away with though.

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

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

LGTM. Thank you!

@jkotas jkotas merged commit c03de20 into dotnet:main Dec 13, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Jan 13, 2023
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
None yet
3 participants