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

JITted code throws NullRefException in release #56980

Closed
jakobbotsch opened this issue Aug 6, 2021 · 4 comments · Fixed by #57282
Closed

JITted code throws NullRefException in release #56980

jakobbotsch opened this issue Aug 6, 2021 · 4 comments · Fixed by #57282
Assignees
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Milestone

Comments

@jakobbotsch
Copy link
Member

Run on x64 Windows:

// Generated by Fuzzlyn v1.2 on 2021-07-06 09:46:44
// Seed: 16635934940619066544
// Reduced from 447.5 KiB to 0.6 KiB in 00:02:24
// Debug: Runs successfully
// Release: Throws 'System.NullReferenceException'
struct S0
{
    public uint F1;
    public byte F3;
    public long F4;
    public uint F5;
    public S0(long f4): this()
    {
        F4 = f4;
    }
}

class C0
{
    public S0 F4;
}

struct S1
{
    public C0 F2;
    public S0 F8;
    public S1(C0 f2, S0 f8): this()
    {
        F2 = f2;
        F8 = f8;
    }
}

struct S2
{
    public S1 F0;
    public S2(S1 f0): this()
    {
        F0 = f0;
    }
}

public class Program
{
    public static void Main()
    {
        S2 vr0 = new S2(new S1(new C0(), new S0(0)));
        M17(ref vr0.F0.F2.F4.F1);
    }

    static void M17(ref uint arg2)
    {
    }
}

Disassembly looks quite strange:

; Assembly listing for method Program:Main()
; Emitting BLENDED_CODE for X64 CPU with AVX - Windows
; optimized code
; rsp based frame
; partially interruptible
; No PGO data
; 0 inlinees with PGO data; 5 single block inlinees; 0 inlinees without PGO data
; Final local variable assignments
;
;  V00 OutArgs      [V00    ] (  1,  1   )  lclBlk (32) [rsp+00H]   "OutgoingArgSpace"
;  V01 tmp1         [V01,T02] (  2,  4   )     ref  ->  rcx         class-hnd exact single-def "NewObj constructor temp"
;* V02 tmp2         [V02    ] (  0,  0   )  struct (24) zero-ref    "NewObj constructor temp"
;* V03 tmp3         [V03,T01] (  0,  0   )  struct (32) zero-ref    do-not-enreg[SFB] single-def "NewObj constructor temp"
;* V04 tmp4         [V04,T03] (  0,  0   )  struct (32) zero-ref    do-not-enreg[SFB] "NewObj constructor temp"
;* V05 tmp5         [V05,T00] (  0,  0   )  struct (24) zero-ref    do-not-enreg[SFB] "Inlining Arg"
;* V06 tmp6         [V06    ] (  0,  0   )  struct (32) zero-ref    do-not-enreg[S] single-def "Inlining Arg"
;* V07 tmp7         [V07,T08] (  0,  0   )     int  ->  zero-ref    V02.F1(offs=0x00) P-INDEP "field V02.F1 (fldOffset=0x0)"
;* V08 tmp8         [V08,T05] (  0,  0   )   ubyte  ->  zero-ref    V02.F3(offs=0x04) P-INDEP "field V02.F3 (fldOffset=0x4)"
;* V09 tmp9         [V09,T06] (  0,  0   )    long  ->  zero-ref    V02.F4(offs=0x08) P-INDEP "field V02.F4 (fldOffset=0x8)"
;* V10 tmp10        [V10,T04] (  0,  0   )     int  ->  zero-ref    V02.F5(offs=0x10) P-INDEP "field V02.F5 (fldOffset=0x10)"
;* V11 tmp11        [V11,T07] (  0,  0   )     ref  ->  zero-ref    single-def "Big Offset Morphing"
;
; Lcl frame size = 40

G_M27646_IG01:              ;; offset=0000H
       4883EC28             sub      rsp, 40
                                                ;; bbWeight=1    PerfScore 0.25
G_M27646_IG02:              ;; offset=0004H
       48B9D0C3EE8CFB7F0000 mov      rcx, 0x7FFB8CEEC3D0
       E89D95E35E           call     CORINFO_HELP_NEWSFAST
       488BC8               mov      rcx, rax
       E8BD15FEFF           call     System.Object:.ctor():this
       8B042500000000       mov      eax, dword ptr [0000H]
                                                ;; bbWeight=1    PerfScore 4.50
G_M27646_IG03:              ;; offset=0022H
       4883C428             add      rsp, 40
       C3                   ret
                                                ;; bbWeight=1    PerfScore 1.25

; Total bytes of code 39, prolog size 4, PerfScore 9.90, instruction count 8, allocated bytes for code 39 (MethodHash=cb019401) for method Program:Main()
; ============================================================

cc @dotnet/jit-contrib

@dotnet-issue-labeler dotnet-issue-labeler bot added area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI untriaged New issue has not been triaged by the area owner labels Aug 6, 2021
@JulieLeeMSFT JulieLeeMSFT added needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration and removed untriaged New issue has not been triaged by the area owner labels Aug 6, 2021
@JulieLeeMSFT JulieLeeMSFT added this to the 6.0.0 milestone Aug 6, 2021
@AndyAyersMS
Copy link
Member

Took a quick look; proximate cause is that VN thinks the base of an indir is null, and that feeds a nullcheck, so the codegen above is the nullcheck of a null.

  VNApplySelectors:
    VNForHandle(F0) is $147, fieldType is struct, size = 32
      AX2: $147 != $146 ==> select([$4c1]store($440, $146, $205), $147) ==> select($440, $147) remaining budget is 99.
      AX2: $147 != $145 ==> select([$440]store($1, $145, $180), $147) ==> select($1, $147) remaining budget is 98.
    VNForMapSelect($4c1, $147):struct returns $VN.ZeroMap
  VNApplySelectors:
    VNForHandle(F2) is $145, fieldType is ref
    VNForMapSelect($1, $145):ref returns $VN.Null
  VNApplySelectors:
    VNForHandle(F0) is $147, fieldType is struct, size = 32
      AX2: $147 != $146 ==> select([$4c0]store($440, $146, $204), $147) ==> select($440, $147) remaining budget is 99.
      AX2: $147 != $145 ==> select([$440]store($1, $145, $180), $147) ==> select($1, $147) remaining budget is 98.
    VNForMapSelect($4c0, $147):struct returns $VN.ZeroMap
  VNApplySelectors:
    VNForHandle(F2) is $145, fieldType is ref
    VNForMapSelect($1, $145):ref returns $VN.Null
N001 [000031]   LCL_FLD   V04 tmp4         u:1[+0] Fseq[F0, F2] (last use) => $VN.Null

***** BB01, STMT00018(after)
N008 ( 11, 10) [000086] -A-XG-------              *  COMMA     void   $500
N006 ( 11, 10) [000148] -A-X--------              +--*  COMMA     void   $183
N003 (  7,  7) [000137] -A------R---              |  +--*  ASG       ref    $VN.Null
N002 (  3,  2) [000136] D------N----              |  |  +--*  LCL_VAR   ref    V11 tmp11        d:1 $VN.Null
N001 (  3,  4) [000031] ------------              |  |  \--*  LCL_FLD   ref    V04 tmp4         u:1[+0] Fseq[F0, F2] (last use) $VN.Null
N005 (  4,  3) [000139] ---X---N----              |  \--*  NULLCHECK byte   $183
N004 (  3,  2) [000138] ------------              |     \--*  LCL_VAR   ref    V11 tmp11        u:1 (last use) $VN.Null
N007 (  0,  0) [000085] ------------              \--*  NOP       void   $1c5

Now WHY VN thinks that is not immediately clear.... likely we are missing something when modelling the memory updates done earlier in the method, and so think that bit of the struct was not explicitly initialized.

@briansull briansull self-assigned this Aug 9, 2021
@JulieLeeMSFT JulieLeeMSFT removed the needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration label Aug 9, 2021
@AndyAyersMS
Copy link
Member

Think the issue may originate here:

LocalAddressVisitor visiting statement:
STMT00016 (IL 0x011...  ???)
               [000080] -A----------              *  ASG       struct (copy)
               [000079] ------------              +--*  OBJ       struct<S1, 32>
               [000078] ------------              |  \--*  ADDR      byref 
               [000077] -------N----              |     \--*  FIELD     struct F0
               [000074] ------------              |        \--*  ADDR      byref 
               [000075] -------N----              |           \--*  LCL_VAR   struct<S2, 32> V04 tmp4         
               [000076] ------------              \--*  LCL_VAR   struct<S1, 32> V06 tmp6         
LocalAddressVisitor modified statement:
STMT00016 (IL 0x011...  ???)
               [000080] -A----------              *  ASG       struct (copy)
               [000079] D------N----              +--*  LCL_VAR   struct<S2, 32> V04 tmp4         
               [000076] ------------              \--*  LCL_VAR   struct<S1, 32> V06 tmp6         

We seem to lose the fact that we're storing to the S1 field of an S2, not to the S2 itself. Logically it's the same set of bits, but I think we need to preserve the bit of field seq here we've lost...?

@AndyAyersMS
Copy link
Member

@sandreenko if this is similar to issues you're already working on, do you want to take this over?

@sandreenko sandreenko self-assigned this Aug 9, 2021
@sandreenko
Copy link
Contributor

@sandreenko if this is similar to issues you're already working on, do you want to take this over?

sure.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
5 participants