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

Function pointer bug fixes #45473

Merged
6 commits merged into from
Jun 27, 2020
Merged

Function pointer bug fixes #45473

6 commits merged into from
Jun 27, 2020

Conversation

333fred
Copy link
Member

@333fred 333fred commented Jun 26, 2020

Fixes a couple of function pointer bugs:

@dotnet/roslyn-compiler @AlekseyTs for review.

@333fred 333fred requested review from AlekseyTs and a team June 26, 2020 02:52
ref arguments,
ref argRefKinds);

Debug.Assert(arguments.IsDefault && argRefKinds.IsDefault && receiver.Kind == BoundKind.TypeExpression);
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 26, 2020

Choose a reason for hiding this comment

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

receiver.Kind == BoundKind.TypeExpression [](start = 77, length = 41)

What is this type? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

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

Made the var explicit and added some more verification of the remapped method.


In reply to: 445955503 [](ancestors = 445955503)

@@ -1303,6 +1303,30 @@ public override BoundNode VisitDelegateCreationExpression(BoundDelegateCreationE
return base.VisitDelegateCreationExpression(node);
}

public override BoundNode VisitFunctionPointerLoad(BoundFunctionPointerLoad node)
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 26, 2020

Choose a reason for hiding this comment

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

VisitFunctionPointerLoad [](start = 34, length = 24)

Did you check other places where we override VisitDelegateCreationExpression to confirm that we don't need to add VisitFunctionPointerLoad? We probably have several visitors that introduce virtual methods with names like that. #Closed

Copy link
Member Author

Choose a reason for hiding this comment

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

I've taken a look. I'll add an override in MethodToClassRewriter, but I can't find a case that it will actually change, as other than this it's only used for iterator and async method rewriting. Since we don't allow you to refer to the compiler-generated underlying methods of these from source, there's nothing that we can test. If we add a new thing that gets remapped in the future, though, it will function as expected.


In reply to: 445956108 [](ancestors = 445956108)

Comment on lines +7112 to +7115
delegate*<void> a = &local;
a();

static void local() => System.Console.Write(""local"");
Copy link
Member

@jaredpar jaredpar Jun 26, 2020

Choose a reason for hiding this comment

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

Consider adding a test where the contents of this method body exist within a lambda expression. Verifying the rewriting works in a nested environment. #Resolved

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jun 26, 2020

Done with review pass (iteration 3) #Closed

333fred added 2 commits June 26, 2020 14:30
* Additional tests for nested function contexts.
* Override VisitFunctionPointerLoad in MethodToClassRewriter.
* Adjust debug asserts.
@333fred
Copy link
Member Author

333fred commented Jun 26, 2020

@AlekseyTs addressed feedback.

This PR now addresses an additional issue I found when testing locally, where an ldftn would be left on the stack when the result was unused. @jaredpar, I'd like another review with that additional fix.


In reply to: 649949098 [](ancestors = 649949098)

@333fred 333fred requested a review from jaredpar June 26, 2020 21:33
if (used)
{
_builder.EmitOpCode(ILOpCode.Ldftn);
EmitSymbolToken(load.TargetMethod, load.Syntax, optArgList: null);
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 26, 2020

Choose a reason for hiding this comment

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

EmitSymbolToken(load.TargetMethod, load.Syntax, optArgList: null); [](start = 16, length = 66)

Can this have a side effect, for example an exception? Is this conditional handling consistent with what we do for delegate creation? I.e. if a delegate instance is not used, are we not loading the address of a target method? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

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

If I hadn't fixed the remapped local function bug, it would have an effect, but the only effect from this I could see now is if a tree-trimming algorithm decides the referenced method isn't used (which it isn't) and decides to remove it. However, when I implemented this I checked our handling for delegates:

static void M()
{
    System.Action a = M;
}

produces this IL in release mode:

    .method private hidebysig static 
        void M () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 1 (0x1)
        .maxstack 8

        IL_0000: ret
    } // end of method C::M

In reply to: 446421466 [](ancestors = 446421466)

Copy link
Member

Choose a reason for hiding this comment

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

My intuition was that the tree trimming aspect was fine, and likely desired. The fact that it lines up with delegate behavior makes me feel good about this outcome.

if (used)
{
_builder.EmitOpCode(ILOpCode.Ldftn);
EmitSymbolToken(load.TargetMethod, load.Syntax, optArgList: null);
Copy link
Member

Choose a reason for hiding this comment

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

My intuition was that the tree trimming aspect was fine, and likely desired. The fact that it lines up with delegate behavior makes me feel good about this outcome.

@@ -506,6 +506,11 @@ public override BoundNode VisitDelegateCreationExpression(BoundDelegateCreationE
return node.Update(rewrittenArgument, method, node.IsExtensionMethod, type);
}

public override BoundNode VisitFunctionPointerLoad(BoundFunctionPointerLoad node)
{
return node.Update(VisitMethodSymbol(node.TargetMethod), node.Type);
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 26, 2020

Choose a reason for hiding this comment

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

node.Type [](start = 69, length = 9)

It looks like we should also visit type. #Closed

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jun 26, 2020

Done with review pass (iteration 5) #Closed

@333fred
Copy link
Member Author

333fred commented Jun 26, 2020

@AlekseyTs addressed feedback.


In reply to: 650448547 [](ancestors = 650448547)

Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

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

LGTM (iteration 6), assuming CI is passing

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

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

Auto-approval

@ghost ghost merged commit fa69a8c into dotnet:master Jun 27, 2020
@333fred 333fred deleted the func-ptr-bugs branch June 27, 2020 02:08
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants