Skip to content

JIT: Assertion failed 'm_dfsTree != nullptr' #115168

Closed
@BruceForstall

Description

@BruceForstall
// Generated by Fuzzlyn v2.9 on 2025-04-29 21:12:44
// Run on X64 Windows
// Seed: 1988339208440149902-vectort,vector128,vector256,x86aes,x86avx,x86avx2,x86avx512bw,x86avx512bwvl,x86avx512cd,x86avx512cdvl,x86avx512dq,x86avx512dqvl,x86avx512f,x86avx512fvl,x86avx512fx64,x86bmi1,x86bmi1x64,x86bmi2,x86bmi2x64,x86fma,x86lzcnt,x86lzcntx64,x86pclmulqdq,x86popcnt,x86popcntx64,x86sse,x86ssex64,x86sse2,x86sse2x64,x86sse3,x86sse41,x86sse41x64,x86sse42,x86sse42x64,x86ssse3,x86x86base
// Reduced from 63.5 KiB to 1.0 KiB in 00:01:26
// Hits JIT assert in Release:
// Assertion failed 'm_dfsTree != nullptr' in 'Program:M1(C0)' during 'Do value numbering' (IL size 72; hash 0xc7c374c5; FullOpts)
// 
//     File: D:\a\_work\1\s\src\coreclr\jit\valuenum.cpp Line: 10867
// 
using System;
using System.Numerics;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;

public class C0
{
    public byte F0;
    public ushort F4;
}

public class Program
{
    public static void Main()
    {
        var vr1 = new C0();
        M1(vr1);
    }

    public static void M1(C0 argThis)
    {
        switch ((Bmi1.AndNot(4294967295U, argThis.F4) & argThis.F0))
        {
            case 0:
            {
                Vector<long> var0 = Vector.Create<long>(0);
                System.Console.WriteLine(var0);
            }

                break;
            case 1:
            {
            }

                break;
            case 2:
            {
            }

                break;
            case 3:
            {
            }

                break;
            case 4:
            {
            }

                break;
            default:
            {
            }

                break;
        }
    }
}

Activity

ghost added
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
on Apr 29, 2025
added and removed
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
untriagedNew issue has not been triaged by the area owner
on Apr 29, 2025
dotnet-policy-service

dotnet-policy-service commented on Apr 29, 2025

@dotnet-policy-service
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

changed the title [-]JIT:[/-] [+]JIT: Assertion failed 'm_dfsTree != nullptr'[/+] on Apr 29, 2025
added
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
on Apr 29, 2025
BruceForstall

BruceForstall commented on Apr 29, 2025

@BruceForstall
ContributorAuthor

@dotnet/jit-contrib

amanasifkhalid

amanasifkhalid commented on Apr 30, 2025

@amanasifkhalid
Member

If early value propagation decides to fold a null check away, any existing flowgraph annotations need to be invalidated due to the change in flowgraph shape. Value numbering tolerates the loop data structures being null, but oddly expects the DFS tree to always be available -- I'm guessing this assert has been overzealous for a long time, and the null check fold in early prop just doesn't kick in often.

amanasifkhalid

amanasifkhalid commented on Apr 30, 2025

@amanasifkhalid
Member

With the assert replaced with a DFS tree re-computation, I'm now hitting an assert in the VM:

Assert failure(PID 23352 [0x00005b38], Thread: 6068 [0x17b4]): ohThrowable

CORECLR! PreStubWorker$catch$17 + 0xE3 (0x00007ffe`d4f89423)
CORECLR! CallSettingFrame_LookupContinuationIndex + 0x20 (0x00007ffe`d4ed1850)
CORECLR! _FrameHandler4::CxxCallCatchBlock + 0x1DE (0x00007ffe`d4ecf61e)
NTDLL! RtlCaptureContext2 + 0x4A6 (0x00007fff`60c1e416)
CORECLR! PreStubWorker + 0x539 (0x00007ffe`d47edd39)
CORECLR! ThePreStub + 0x55 (0x00007ffe`d4cb9e75)
<no module>! <no symbol> + 0x0 (0x00007ffe`754b3c4c)
<no module>! <no symbol> + 0x0 (0x00000223`9e8bca60)
<no module>! <no symbol> + 0x0 (0x00000000`00000200)
<no module>! <no symbol> + 0x0 (0x0000007f`597ae108)
    File: C:\wk\runtime\src\coreclr\vm\prestub.cpp:1973
    Image: C:\wk\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\corerun.exe

I'm guessing there's something illegal about this transformation.

amanasifkhalid

amanasifkhalid commented on Apr 30, 2025

@amanasifkhalid
Member

Turns out this assert was obscuring an AV in the JIT from the dominance tree being null in a later phase. Not sure if it's interesting, but here's the transformation we're doing:

The AndNot call is folded away because ~4294967295 (or ~0xFFFFFFFF) is 0, so all the Ands will reduce to 0 regardless of argThis's values, but we keep the null check around in a GT_COMMA node. So before early prop, we have this tree:

N010 ( 19, 14) [000013] ---XG+-----                         *  SWITCH    void  
N009 (  9,  9) [000010] ---XG+-----                         \--*  AND       int   
N004 (  3,  3) [000006] ---X-+-----                            +--*  COMMA     int   
N002 (  2,  2) [000030] ---X-+-----                            |  +--*  NULLCHECK byte  
N001 (  1,  1) [000029] -----+-----                            |  |  \--*  LCL_VAR   ref    V00 arg0         u:1
N003 (  1,  1) [000004] -----+-----                            |  \--*  CNS_INT   int    0
N008 (  5,  5) [000009] ---XG+-----                            \--*  IND       ubyte 
N007 (  2,  2) [000036] -----+-N---                               \--*  ADD       byref 
N005 (  1,  1) [000007] -----+-----                                  +--*  LCL_VAR   ref    V00 arg0         u:1 (last use)
N006 (  1,  1) [000035] -----+-----                                  \--*  CNS_INT   long   10 Fseq[F0]

Null check folding finds the GT_IND node below the GT_COMMA, and gets rid of the null check and folds the GT_AND away, so we end up with the following:

N010 ( 19, 14) [000013] ---XGO-----                         *  SWITCH    void  
N006 (  6,  6) [000037] ---XG------                         \--*  COMMA     int   
N004 (  5,  5) [000009] ---XG------                            +--*  IND       ubyte 
N003 (  2,  2) [000036] -------N---                            |  \--*  ADD       byref 
N001 (  1,  1) [000007] -----------                            |     +--*  LCL_VAR   ref    V00 arg0         u:1 (last use)
N002 (  1,  1) [000035] -----------                            |     \--*  CNS_INT   long   10 Fseq[F0]
N005 (  1,  1) [000004] -----------                            \--*  CNS_INT   int    0

This looks valid to me; the second read to argThis is preserved so we can throw a NRE if needed. Now that we've folded the switch expression into a constant, we can fold it into a BBJ_ALWAYS, hence the flowgraph change.

added this to the 10.0.0 milestone on Apr 30, 2025
added a commit that references this issue on Apr 30, 2025
6ee6d40
locked and limited conversation to collaborators on May 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIblocking-clean-ci-optionalBlocking optional rolling runs

Type

No type

Projects

No projects

Relationships

None yet

    Development

    Participants

    @BruceForstall@amanasifkhalid

    Issue actions

      JIT: Assertion failed 'm_dfsTree != nullptr' · Issue #115168 · dotnet/runtime