Skip to content

JIT: Make GenTree::Compare more conservative around several node types - #135363

Merged
EgorBo merged 2 commits into
dotnet:mainfrom
EgorBo:jit-compare-cns-fieldseq
Oct 8, 2026
Merged

EgorBo merged 2 commits into
dotnet:mainfrom
EgorBo:jit-compare-cns-fieldseq

Conversation

@EgorBo

@EgorBo EgorBo commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Fixes #135350

GenTree::Compare ignored the field sequence on GT_CNS_INT, so post-morph head/tail merge could merge statements that differ only in which field an offset constant refers to. In the Roslyn case, the two arms of a GDV over ContainingType ended with:

// SynthesizedReadOnlyListEnumeratorTypeSymbol arm
V25 = ISINSTANCEOFCLASS(NamedTypeSymbol, IND(ADD(obj, 0x38 Fseq[_containingType])))
// fallback arm
V25 = ISINSTANCEOFCLASS(NamedTypeSymbol, IND(ADD(obj, 0x38 Fseq[_containingSymbol])))

Both fields happen to live at offset 0x38, so the statements compared equal and the guarded arm's copy was kept for all paths. _containingType is typed as a sealed NamedTypeSymbol subclass, so the isinst was later folded away, and ContainingType != null became _containingSymbol != null for every object.

The fix makes GT_CNS_INT comparison require matching field sequences, mirroring the existing gtFldHnd check for GT_FIELD_ADDR. No SPMI diffs.

While here, GenTree::Compare also now compares a few other correctness-relevant fields it used to ignore:

  • GT_CNS_INT: handle kind and compile-time handle.
  • Relops: GTF_RELOP_NAN_UN (ordered vs unordered).
  • All indir-like nodes (ARR_LENGTH, MDARR_*, NULLCHECK, atomics, CMPXCHG, not just IND/BLK/stores): GTF_IND_FLAGS, which includes the path-dependent GTF_IND_NONFAULTING.
  • GT_ARR_ADDR: the path-dependent GTF_ARR_ADDR_NONNULL.
  • GT_BOX: the upstream def/copy statements.
  • Unexpected ExOps are treated as unequal in release builds.

Almost no diffs

Post-morph head/tail merge could merge statements that differ only in the
field sequence of an offset constant, e.g. IND(ADD(obj, 0x38 Fseq[A])) and
IND(ADD(obj, 0x38 Fseq[B])) coming from different GDV arms. The surviving
tree's field (and hence its type) then applied to all paths, which allowed
an isinst to be folded away incorrectly.

Fixes dotnet#135350

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 6d240d47-05da-4cbb-8dfd-f64b265cd3e1
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Oct 7, 2026
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

* CNS_INT: also compare the handle kind and the compile-time handle.
* Relops: compare GTF_RELOP_NAN_UN (ordered vs unordered).
* All indir-like nodes (ARR_LENGTH, MDARR_*, NULLCHECK, atomics, CMPXCHG): compare
  GTF_IND_FLAGS, which includes the path-dependent GTF_IND_NONFAULTING.
* ARR_ADDR: compare the path-dependent GTF_ARR_ADDR_NONNULL.
* BOX: compare the upstream def/copy statements.
* Treat unexpected ExOps as unequal in release builds.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 6d240d47-05da-4cbb-8dfd-f64b265cd3e1

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The reported miscompile lacks a focused regression test.

1 open finding
What changed in this PR

Fixes unsafe JIT tree equality that could cause head/tail merging to discard path-specific semantics.

Changes:

  • Compares constant metadata, field sequences, and handles.
  • Compares semantic relop, indirection, array-address, and box state.
  • Conservatively rejects unexpected extended operators.
File Description
src/​coreclr/​jit/​gentree.cpp Strengthens GenTree::Compare correctness.

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

Comment thread src/coreclr/jit/gentree.cpp
@EgorBo
EgorBo requested a review from adamperlin October 8, 2026 11:26
@EgorBo

EgorBo commented Oct 8, 2026

Copy link
Copy Markdown
Member Author

PTAL @adamperlin @dotnet/jit-contrib

This just makes GenTree::Compare more conservative when comparing trees. The actual bug is for GT_CNS_INT, but I fixed a few more issues along the road.

Comment thread src/coreclr/jit/gentree.cpp
@EgorBo EgorBo changed the title JIT: Compare field sequences of GT_CNS_INT in GenTree::Compare JIT: Make GenTree::Compare more conservative around several node types Oct 8, 2026
@EgorBo

EgorBo commented Oct 8, 2026

Copy link
Copy Markdown
Member Author

/ba-g unrelated smpt failures

@EgorBo
EgorBo merged commit 176db4e into dotnet:main Oct 8, 2026
141 of 143 checks passed
@EgorBo
EgorBo deleted the jit-compare-cns-fieldseq branch October 8, 2026 23:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JIT: Tier1 with Dynamic PGO drops isinst in inlined guarded devirtualization (Roslyn MetadataWriter NRE, .NET 10.0.12 x64)

3 participants