Skip to content

Commit 85f2425

Browse files
EgorBoCopilot
andcommitted
JIT: Fix KnownBits bounds-check width and drop dead include
The bounds-check consumer hardcoded width=32 in EvalRelop, which is unsound on 64-bit targets where fgMorphIndexAddr (morph.cpp:2995-3015) widens the bounds check to TYP_I_IMPL when the index is native int. With a TYP_LONG index whose low 32 bits are provably small but whose high 32 bits are unknown, the fold could prove (uint)idx < (uint)len using only the low half and incorrectly drop a required bounds check (memory corruption). Derive the width from the operand type, matching the other two consumers. Caught by Opus 4.7 (xhigh), Opus 4.8, and GPT-5.5 in parallel review. Also drop the now-dead #include "knownbits.h" from rangecheck.cpp left over from the previous cleanup commit. libraries.pmi: -13,920 bytes (was -14,515; ~600 byte loss is the correctness recovery -- those wins were unsound TYP_LONG bounds-check drops). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 7c5bf61 commit 85f2425

2 files changed

Lines changed: 7 additions & 3 deletions

File tree

src/coreclr/jit/assertionprop.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5572,10 +5572,15 @@ GenTree* Compiler::optAssertionProp_BndsChk(ASSERT_VALARG_TP assertions, GenTree
55725572
};
55735573

55745574
// Known-bits elimination: redundant if (uint)index is provably < (uint)length. Catches masked
5575-
// indices and bit patterns the range-based paths cannot express.
5575+
// indices and bit patterns the range-based paths cannot express. On 64-bit targets the index
5576+
// and length can both be TYP_I_IMPL (see fgMorphIndexAddr), so derive the width from the actual
5577+
// operand type instead of hardcoding 32 -- otherwise we'd discard the high 32 bits of a native-int
5578+
// index and could prove a (uint)idx < (uint)len fact that doesn't hold for the full value.
5579+
assert(genActualType(arrBndsChk->GetIndex()) == genActualType(arrBndsChk->GetArrayLength()));
5580+
const unsigned width = genTypeSize(genActualType(arrBndsChk->GetIndex())) * BITS_PER_BYTE;
55765581
const KnownBits kbIdx = KnownBits::Compute(this, vnCurIdx, assertions);
55775582
const KnownBits kbLen = KnownBits::Compute(this, vnCurLen, assertions);
5578-
if (KnownBitsOps::EvalRelop(GT_LT, /* isUnsigned */ true, kbIdx, kbLen, 32) == 1)
5583+
if (KnownBitsOps::EvalRelop(GT_LT, /* isUnsigned */ true, kbIdx, kbLen, width) == 1)
55795584
{
55805585
return dropBoundsCheck(INDEBUG("known bits prove (uint)index < (uint)length"));
55815586
}

src/coreclr/jit/rangecheck.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
#include "jitpch.h"
77
#include "rangecheck.h"
8-
#include "knownbits.h"
98

109
//------------------------------------------------------------------------
1110
// rangeCheckPhase: optimize bounds checks via range analysis

0 commit comments

Comments
 (0)