Bug 59608 - Attribute MethodImplOptions.AggressiveInlining causes method to always return NULL
Summary: Attribute MethodImplOptions.AggressiveInlining causes method to always return...
Status: RESOLVED FIXED
Alias: None
Product: Runtime
Classification: Mono
Component: JIT (show other bugs)
Version: 5.2
Hardware: PC All
: --- normal
Target Milestone: ---
Assignee: Zoltan Varga
URL:
Depends on:
Blocks:
 
Reported: 2017-09-20 15:13 UTC by Mikhail Moussikhine
Modified: 2017-10-06 14:21 UTC (History)
4 users (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments

Description Mikhail Moussikhine 2017-09-20 15:13:57 UTC
Using aggressive method inlining in some case optimizes the method out of existence.

I do not know if this issue manifests itself only in this particular case or there are other circumstances in which the same behavior can be observed, but here is the specific use case from the Akka.NET project:

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Tcp.SocketCompleted ResolveMessage(SocketAsyncEventArgs e)
{
    switch (e.LastOperation)
    {
        case SocketAsyncOperation.Receive:
        case SocketAsyncOperation.ReceiveFrom:
        case SocketAsyncOperation.ReceiveMessageFrom:
            return Tcp.SocketReceived.Instance;
        case SocketAsyncOperation.Send:
        case SocketAsyncOperation.SendTo:
        case SocketAsyncOperation.SendPackets:
            return Tcp.SocketSent.Instance;
        case SocketAsyncOperation.Accept:
            return Tcp.SocketAccepted.Instance;
        case SocketAsyncOperation.Connect:
            return Tcp.SocketConnected.Instance;
        default:
            throw new NotSupportedException($"Socket operation {e.LastOperation} is not supported");
    }
}

Attribute [MethodImpl(MethodImplOptions.AggressiveInlining)] causes this method to ALWAYS return NULL under at least Mono 5.2.0.215. I have encountered the problem on Ubuntu 17.04, but others seem to be having the same issue on Windows too.

Akka.NET bug report is here:
https://github.com/akkadotnet/akka.net/issues/3092#issuecomment-328576938

Removing the attribute or disabling inline optimization (mono -O=all,-inline ...) alleviates the problem.
Comment 1 Zoltan Varga 2017-09-23 00:00:10 UTC
Could you attach a complete testcase ? I couldn't create one from that code fragment.
Comment 2 Mikhail Moussikhine 2017-09-23 05:13:11 UTC
The original Akka bug report has one:

https://github.com/akkadotnet/akka.net/issues/3092#issue-256574196

Would that suffice?
Comment 3 Zoltan Varga 2017-09-23 08:37:46 UTC
That code doesn't compile either, it has no using directives.
Comment 4 Mikhail Moussikhine 2017-09-23 16:50:08 UTC
https://github.com/mmoussikhine/Bug59608

Steps to reproduce:

"Success"

1. 'Debug' Server
2. 'Run' Client

Client will send "Ping"
Server will receive "Ping" and respond "Pong"
Client will receive "Pong"

3. Stop Server

"Failure"

1. 'Run' Server
2. 'Run' Client

Client will send "Ping"
Server will crash

The important part of the exception trace is "Akka.IO.TcpExt.OnComplete".

https://github.com/akkadotnet/akka.net/blob/dev/src/core/Akka/IO/Tcp.cs#L1103

Method OnComplete calls ResolveMessage, which in 'Run' mode always returns NULL.
Comment 5 Zoltan Varga 2017-09-23 21:46:50 UTC
I can reproduce, needed to compile the testcase with csc /optimize.

Testcase:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
using System;
using System.Runtime.CompilerServices;
using System.Net;
using System.Net.Sockets;

class Args {
	public SocketAsyncOperation LastOperation { get; set; }
}

public class Tests
{
	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	private static int ResolveMessage(Args e)
	{
    switch (e.LastOperation)
    {
        case SocketAsyncOperation.Receive:
            return 0;
        case SocketAsyncOperation.Send:
            return 1;
        case SocketAsyncOperation.Accept:
            return 2;
        case SocketAsyncOperation.Connect:
            return 3;
        default:
            throw new NotSupportedException($"Socket operation {e.LastOperation} is not supported");
    }
	}

public static void Main () {
	var e = new Args () { LastOperation = SocketAsyncOperation.Connect };
	Console.WriteLine (ResolveMessage(e));
}
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Comment 6 Zoltan Varga 2017-09-27 21:11:30 UTC
https://github.com/mono/mono/pull/5654
Comment 7 Marek Safar 2017-10-06 14:18:53 UTC
Closing the issue has been fixed

Note You need to log in before you can comment on or make changes to this bug.