runtime: RyuJIT incorrectly narrows value on ARM32/x86 in release

On ARM32 and x86 with .NET core 2.1, the following program prints 4294967295 in debug, but 255 in release:

// Generated by Fuzzlyn on 2018-07-03 07:50:20
// Seed: 10009979209080502034
// Reduced from 429.6 KiB to 0.4 KiB
// Debug: Outputs 4294967295
// Release: Outputs 255
public class Program
{
    public static void Main()
    {
        M1(0);
    }

    static void M1(byte arg2)
    {
        byte vr23 = arg2++;
        uint vr13 = uint.MaxValue * arg2;
        ulong vr40 = vr13;
        System.Console.WriteLine(vr40);
    }
}

It does not repro on AMD64 (Windows or Linux). Also, changing byte vr23 = arg2++; to arg2++; fixes it.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 17 (17 by maintainers)

Commits related to this issue

Most upvoted comments

I wonder if your example could be extended to violate memory safety by dereferencing an array beyond its end?

Probably not, redundant array range check elimination relies on conservative value numbers that account for updates done by other threads. It also relies on the existence of relops like i < a.Length, if an optimization removes those, range check elimination will be blocked. But I wouldn’t go as far to say that it’s impossible 😁. And this is certainly something to keep an eye on while doing work in this area of the JIT.

It looks to me that the current x86 build is also broken as it generates:

G_M55886_IG02:
       0FB6C9       movzx    ecx, cl
       41           inc      ecx
       0FB6C9       movzx    ecx, cl
       8BC1         mov      eax, ecx
       F7D8         neg      eax
       0FB6C0       movzx    eax, al ; huh ?!!
       6A00         push     0
       50           push     eax
       FF1588411E03 call     [Program:WriteLine(long)]

And the dump shows that morph produces a byte NEG node:

fgMorphTree BB01, stmt 3 (before)
               [000017] --C-G-------              *  CALL      void   Program.Write
               [000016] ---------U-- arg0         \--*  CAST      long <- ulong <- uint
               [000014] ------------                 |  /--*  LCL_VAR   ubyte  V00 arg0         
               [000015] ------------                 \--*  MUL       int   
               [000013] ------------                    \--*  CNS_INT   int    -1
Upping fgPtrArgCntMax from 0 to 2
fgArgTabEntry[arg 0 16.CAST, numSlots=2, slotNum=0, align=1]

fgMorphTree BB01, stmt 3 (after)
               [000017] --CXG+------              *  CALL      void   Program.Write
               [000016] -----+---U-- arg0         \--*  CAST      long <- ulong <- uint
               [000024] -----+------                 \--*  NEG       ubyte 
               [000014] -----+------                    \--*  LCL_VAR   ubyte  V00 arg0