Skip to content

Commit b72ec6c

Browse files
Fix asserts and GC holes with Unsafe.Subtract/ByteOffset (#99019)
1 parent 8dcca1c commit b72ec6c

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed

src/coreclr/jit/morph.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -9220,11 +9220,11 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA
92209220

92219221
// TODO #4104: there are a lot of other places where
92229222
// this condition is not checked before transformations.
9223-
if (fgGlobalMorph)
9223+
noway_assert(op2);
9224+
if (fgGlobalMorph && !op2->TypeIs(TYP_BYREF))
92249225
{
92259226
/* Check for "op1 - cns2" , we change it to "op1 + (-cns2)" */
92269227

9227-
noway_assert(op2);
92289228
if (op2->IsCnsIntOrI() && !op2->IsIconHandle())
92299229
{
92309230
// Negate the constant and change the node to be "+",
@@ -9242,7 +9242,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA
92429242
noway_assert(op1);
92439243
if (op1->IsCnsIntOrI())
92449244
{
9245-
noway_assert(varTypeIsIntOrI(tree));
9245+
noway_assert(varTypeIsIntegralOrI(tree));
92469246

92479247
// The type of the new GT_NEG node cannot just be op2->TypeGet().
92489248
// Otherwise we may sign-extend incorrectly in cases where the GT_NEG

src/libraries/System.Runtime/tests/System.Runtime.CompilerServices.Unsafe.Tests/UnsafeTests.cs

+26-1
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,26 @@ public static void ByteOffsetStackByte4()
462462
Assert.Equal(new IntPtr(-3), Unsafe.ByteOffset(ref byte4.B3, ref byte4.B0));
463463
}
464464

465+
private static unsafe class StaticReadonlyHolder
466+
{
467+
public static readonly void* Pointer = (void*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(StaticReadonlyHolder), 1);
468+
}
469+
470+
[Fact]
471+
public static unsafe void ByteOffsetConstantRef()
472+
{
473+
// https://github.com/dotnet/runtime/pull/99019
474+
[MethodImpl(MethodImplOptions.NoInlining)]
475+
static nint NullTest(ref byte origin) => Unsafe.ByteOffset(ref origin, ref Unsafe.NullRef<byte>());
476+
Assert.Equal(0, NullTest(ref Unsafe.NullRef<byte>()));
477+
478+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
479+
static ref byte GetStatic(ref byte x) => ref x;
480+
[MethodImpl(MethodImplOptions.NoInlining)]
481+
static nint StaticReadonlyTest(ref byte x) => Unsafe.ByteOffset(ref GetStatic(ref Unsafe.AsRef<byte>(StaticReadonlyHolder.Pointer)), ref x);
482+
Assert.Equal(0, StaticReadonlyTest(ref Unsafe.AsRef<byte>(StaticReadonlyHolder.Pointer)));
483+
}
484+
465485
[Fact]
466486
public static unsafe void AsRef()
467487
{
@@ -597,7 +617,7 @@ public static void RefAddNuintByteOffset()
597617
}
598618

599619
[Fact]
600-
public static void RefSubtract()
620+
public static unsafe void RefSubtract()
601621
{
602622
string[] a = new string[] { "abc", "def", "ghi", "jkl" };
603623

@@ -609,6 +629,11 @@ public static void RefSubtract()
609629

610630
ref string r3 = ref Unsafe.Subtract(ref r2, 3);
611631
Assert.Equal("abc", r3);
632+
633+
// https://github.com/dotnet/runtime/pull/99019
634+
[MethodImpl(MethodImplOptions.NoInlining)]
635+
static ref byte NullTest(nuint offset) => ref Unsafe.Subtract(ref Unsafe.NullRef<byte>(), offset);
636+
Assert.True(Unsafe.IsNullRef(ref NullTest(0)));
612637
}
613638

614639
[Fact]

0 commit comments

Comments
 (0)