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

Finally block belonging to unexecuted try runs anyway #10955

Closed
jakobbotsch opened this issue Aug 23, 2018 · 5 comments
Closed

Finally block belonging to unexecuted try runs anyway #10955

jakobbotsch opened this issue Aug 23, 2018 · 5 comments

Comments

@jakobbotsch
Copy link
Member

The following program prints something in release even though it shouldn't:

// Debug: Prints 0 lines
// Release: Prints 1 line
using System;

public class Program
{
    public static void Main()
    {
        try
        {
            bool b = false;
            if (b)
            {
                try
                {
                    return;
                }
                finally
                {
                    Console.WriteLine("Prints");
                }
            }
            else
            {
                return;
            }
        }
        finally
        {
            GC.KeepAlive(null);
        }
    }
}

Disassembly is:

; Assembly listing for method Program:Main()
; Emitting BLENDED_CODE for X64 CPU with AVX
; optimized code
; rbp based frame
; fully interruptible
; Final local variable assignments
;
;  V00 OutArgs      [V00    ] (  1,  1   )  lclBlk (32) [rsp+0x00]
;  V01 PSPSym       [V01    ] (  1,  1   )    long  ->  [rbp-0x10]   do-not-enreg[X] addr-exposed
;
; Lcl frame size = 48

G_M5092_IG01:
       55                   push     rbp
       4883EC30             sub      rsp, 48
       488D6C2430           lea      rbp, [rsp+30H]
       488965F0             mov      qword ptr [rbp-10H], rsp

G_M5092_IG02:
       48B968302ED59B010000 mov      rcx, 0x19BD52E3068
       488B09               mov      rcx, gword ptr [rcx]
       E850FCFFFF           call     System.Console:WriteLine(ref)
       90                   nop

G_M5092_IG03:
       33C9                 xor      rcx, rcx
       E8B85B1E5E           call     System.GC:KeepAlive(ref)
       90                   nop

G_M5092_IG04:
       488D6500             lea      rsp, [rbp]
       5D                   pop      rbp
       C3                   ret

G_M5092_IG05:
       55                   push     rbp
       4883EC30             sub      rsp, 48
       488B6920             mov      rbp, qword ptr [rcx+32]
       48896C2420           mov      qword ptr [rsp+20H], rbp
       488D6D30             lea      rbp, [rbp+30H]

G_M5092_IG06:
       33C9                 xor      rcx, rcx
       E8985B1E5E           call     System.GC:KeepAlive(ref)
       90                   nop

G_M5092_IG07:
       4883C430             add      rsp, 48
       5D                   pop      rbp
       C3                   ret

; Total bytes of code 79, prolog size 14 for method Program:Main()
; ============================================================
@AndyAyersMS
Copy link
Member

This looks like it might be a bug in the C# compiler's optimizer. The IL for Main (from 2.10.0.63119 (03b68dcf)) (with /o+) is:

.method public hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       23 (0x17)
  .maxstack  1
  .try
  {
    IL_0000:  ldc.i4.0
    IL_0001:  pop
    .try
    {
      IL_0002:  leave.s    IL_0016
    }  // end .try
    finally
    {
      IL_0004:  ldstr      "Prints"
      IL_0009:  call       void [System.Console]System.Console::WriteLine(string)
      IL_000e:  endfinally
    }  // end handler
  }  // end .try
  finally
  {
    IL_000f:  ldnull
    IL_0010:  call       void [System.Private.CoreLib]System.GC::KeepAlive(object)
    IL_0015:  endfinally
  }  // end handler
  IL_0016:  ret
} // end of method Program::Main

cc @jaredpar @VSadov

@jakobbotsch
Copy link
Member Author

I see, I should've checked. Should I move this over to https://github.com/dotnet/roslyn?

@VSadov
Copy link
Member

VSadov commented Aug 23, 2018

Looks like Roslyn bug.
Something is wrong with dead code elimination. A known to be false condition is eliminated but the consequence block is still emitted - as a fallthrough. So it runs when it should not.

@jakobbotsch
Copy link
Member Author

I don't think this is related to dead code elimination. This was the original example:

// Debug: Outputs True
// Release: Outputs False
public class Program
{
    static bool s_1 = true;
    static bool[] s_2 = new bool[]{false};
    static long s_6;
    public static void Main()
    {
        M0();
        System.Console.WriteLine(s_1);
    }

    static void M0()
    {
        try
        {
            if (s_2[0])
            {
                try
                {
                    return;
                }
                finally
                {
                    s_1 = s_2[0];
                }
            }
            else
            {
                return;
            }
        }
        finally
        {
            s_6 = s_6;
        }
    }
}

@jakobbotsch jakobbotsch changed the title RyuJIT: Finally block belonging to unexecuted try runs anyway Finally block belonging to unexecuted try runs anyway Aug 23, 2018
@jkotas
Copy link
Member

jkotas commented Aug 23, 2018

This issue was moved to dotnet/roslyn#29481

@jkotas jkotas closed this as completed Aug 23, 2018
@msftgits msftgits transferred this issue from dotnet/coreclr Jan 31, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 15, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants