diff --git a/src/coreclr/vm/amd64/JitHelpers_InlineGetThread.asm b/src/coreclr/vm/amd64/JitHelpers_InlineGetThread.asm
index 5e93265cf54873db7cc2fb3d3a12c01d2ba8e705..bf79668e567e29bdcdeacd5052c2582d82ce6cd7 100644
--- a/src/coreclr/vm/amd64/JitHelpers_InlineGetThread.asm
+++ b/src/coreclr/vm/amd64/JitHelpers_InlineGetThread.asm
@@ -60,15 +60,9 @@ LEAF_END JIT_TrialAllocSFastMP_InlineGetThread, _TEXT
; HCIMPL2(Object*, JIT_Box, CORINFO_CLASS_HANDLE type, void* unboxedData)
NESTED_ENTRY JIT_BoxFastMP_InlineGetThread, _TEXT
- mov rax, [rcx + OFFSETOF__MethodTable__m_pWriteableData]
-
- ; Check whether the class has not been initialized
- test dword ptr [rax + OFFSETOF__MethodTableWriteableData__m_dwFlags], MethodTableWriteableData__enum_flag_Unrestored
- jnz ClassNotInited
-
- mov r8d, [rcx + OFFSET__MethodTable__m_BaseSize]
; m_BaseSize is guaranteed to be a multiple of 8.
+ mov r8d, [rcx + OFFSET__MethodTable__m_BaseSize]
INLINE_GETTHREAD r11
mov r10, [r11 + OFFSET__Thread__m_alloc_context__alloc_limit]
@@ -79,6 +73,9 @@ NESTED_ENTRY JIT_BoxFastMP_InlineGetThread, _TEXT
cmp r8, r10
ja AllocFailed
+ test rdx, rdx
+ je NullRef
+
mov [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr], r8
mov [rax], rcx
@@ -113,8 +110,8 @@ align 16
pop rax
ret
- ClassNotInited:
AllocFailed:
+ NullRef:
jmp JIT_Box
NESTED_END JIT_BoxFastMP_InlineGetThread, _TEXT
diff --git a/src/coreclr/vm/amd64/JitHelpers_Slow.asm b/src/coreclr/vm/amd64/JitHelpers_Slow.asm
index 2efd0b122488cd53ff9fdcc8c373ffd7f36ff741..50fe4c64b66f9f1435185b3de912dc18099ce618 100644
--- a/src/coreclr/vm/amd64/JitHelpers_Slow.asm
+++ b/src/coreclr/vm/amd64/JitHelpers_Slow.asm
@@ -205,15 +205,8 @@ LEAF_END JIT_TrialAllocSFastSP, _TEXT
; HCIMPL2(Object*, JIT_Box, CORINFO_CLASS_HANDLE type, void* unboxedData)
NESTED_ENTRY JIT_BoxFastUP, _TEXT
- mov rax, [rcx + OFFSETOF__MethodTable__m_pWriteableData]
-
- ; Check whether the class has not been initialized
- test dword ptr [rax + OFFSETOF__MethodTableWriteableData__m_dwFlags], MethodTableWriteableData__enum_flag_Unrestored
- jnz JIT_Box
-
- mov r8d, [rcx + OFFSET__MethodTable__m_BaseSize]
-
; m_BaseSize is guaranteed to be a multiple of 8.
+ mov r8d, [rcx + OFFSET__MethodTable__m_BaseSize]
inc [g_global_alloc_lock]
jnz JIT_Box
@@ -226,6 +219,8 @@ NESTED_ENTRY JIT_BoxFastUP, _TEXT
cmp r8, r10
ja NoAlloc
+ test rdx, rdx
+ je NullRef
mov qword ptr [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr], r8 ; update the alloc ptr
mov [rax], rcx
@@ -265,6 +260,7 @@ NESTED_ENTRY JIT_BoxFastUP, _TEXT
ret
NoAlloc:
+ NullRef:
mov [g_global_alloc_lock], -1
jmp JIT_Box
NESTED_END JIT_BoxFastUP, _TEXT
diff --git a/src/coreclr/vm/amd64/asmconstants.h b/src/coreclr/vm/amd64/asmconstants.h
index 2afddae98a4d3f0b809d9cea46ba5b287ebda9bd..e578f21ee7a02affdf3c1d451cef72874f2c5a03 100644
--- a/src/coreclr/vm/amd64/asmconstants.h
+++ b/src/coreclr/vm/amd64/asmconstants.h
@@ -163,10 +163,6 @@ ASMCONSTANTS_C_ASSERT(OFFSETOF__MethodTable__m_wNumInterfaces
ASMCONSTANTS_C_ASSERT(OFFSETOF__MethodTable__m_pParentMethodTable
== offsetof(MethodTable, m_pParentMethodTable));
-#define OFFSETOF__MethodTable__m_pWriteableData DBG_FRE(0x28, 0x20)
-ASMCONSTANTS_C_ASSERT(OFFSETOF__MethodTable__m_pWriteableData
- == offsetof(MethodTable, m_pWriteableData));
-
#define OFFSETOF__MethodTable__m_pEEClass DBG_FRE(0x30, 0x28)
ASMCONSTANTS_C_ASSERT(OFFSETOF__MethodTable__m_pEEClass
== offsetof(MethodTable, m_pEEClass));
@@ -201,14 +197,6 @@ ASMCONSTANTS_C_ASSERT(METHODTABLE_EQUIVALENCE_FLAGS
ASMCONSTANTS_C_ASSERT(MethodTable__enum_flag_ContainsPointers
== MethodTable::enum_flag_ContainsPointers);
-#define OFFSETOF__MethodTableWriteableData__m_dwFlags 0
-ASMCONSTANTS_C_ASSERT(OFFSETOF__MethodTableWriteableData__m_dwFlags
- == offsetof(MethodTableWriteableData, m_dwFlags));
-
-#define MethodTableWriteableData__enum_flag_Unrestored 0x04
-ASMCONSTANTS_C_ASSERT(MethodTableWriteableData__enum_flag_Unrestored
- == MethodTableWriteableData::enum_flag_Unrestored);
-
#define OFFSETOF__InterfaceInfo_t__m_pMethodTable 0
ASMCONSTANTS_C_ASSERT(OFFSETOF__InterfaceInfo_t__m_pMethodTable
== offsetof(InterfaceInfo_t, m_pMethodTable));
diff --git a/src/coreclr/vm/arm/asmconstants.h b/src/coreclr/vm/arm/asmconstants.h
index 8d8a1f4f0ea0ecd49370b21711451342ab61a160..277afad56e763cee027a766d14829e657b6abaa3 100644
--- a/src/coreclr/vm/arm/asmconstants.h
+++ b/src/coreclr/vm/arm/asmconstants.h
@@ -76,9 +76,6 @@ ASMCONSTANTS_C_ASSERT(MethodTable__m_BaseSize == offsetof(MethodTable, m_BaseSiz
#define MethodTable__m_dwFlags 0x0
ASMCONSTANTS_C_ASSERT(MethodTable__m_dwFlags == offsetof(MethodTable, m_dwFlags));
-#define MethodTable__m_pWriteableData DBG_FRE(0x1c, 0x18)
-ASMCONSTANTS_C_ASSERT(MethodTable__m_pWriteableData == offsetof(MethodTable, m_pWriteableData));
-
#define MethodTable__enum_flag_ContainsPointers 0x01000000
ASMCONSTANTS_C_ASSERT(MethodTable__enum_flag_ContainsPointers == MethodTable::enum_flag_ContainsPointers);
@@ -88,12 +85,6 @@ ASMCONSTANTS_C_ASSERT(MethodTable__m_ElementType == offsetof(MethodTable, m_pMul
#define SIZEOF__MethodTable DBG_FRE(0x2c, 0x28)
ASMCONSTANTS_C_ASSERT(SIZEOF__MethodTable == sizeof(MethodTable));
-#define MethodTableWriteableData__m_dwFlags 0x00
-ASMCONSTANTS_C_ASSERT(MethodTableWriteableData__m_dwFlags == offsetof(MethodTableWriteableData, m_dwFlags));
-
-#define MethodTableWriteableData__enum_flag_Unrestored 0x04
-ASMCONSTANTS_C_ASSERT(MethodTableWriteableData__enum_flag_Unrestored == MethodTableWriteableData::enum_flag_Unrestored);
-
#define ArrayBase__m_NumComponents 0x4
ASMCONSTANTS_C_ASSERT(ArrayBase__m_NumComponents == offsetof(ArrayBase, m_NumComponents));
diff --git a/src/coreclr/vm/i386/gmsx86.cpp b/src/coreclr/vm/i386/gmsx86.cpp
index 9d982ad689a2eecd44a6c85b73c3ffe49437ad32..5bb4cb8c821b957904caedd91a873d49fdc0a6cb 100644
--- a/src/coreclr/vm/i386/gmsx86.cpp
+++ b/src/coreclr/vm/i386/gmsx86.cpp
@@ -897,6 +897,7 @@ void LazyMachState::unwindLazyState(LazyMachState* baseState,
case 0x03:
case 0x11: // ADC mod/rm
case 0x13:
+ case 0x21: // AND mod/rm
case 0x29: // SUB mod/rm
case 0x2B:
datasize = 0;
diff --git a/src/coreclr/vm/i386/jitinterfacex86.cpp b/src/coreclr/vm/i386/jitinterfacex86.cpp
index 641925821ac67ec277f08d0e6a4086bcb90bb0ca..82782d86c2bf621d7e01c55dcd21bc14f7696c1b 100644
--- a/src/coreclr/vm/i386/jitinterfacex86.cpp
+++ b/src/coreclr/vm/i386/jitinterfacex86.cpp
@@ -420,27 +420,18 @@ void *JIT_TrialAlloc::GenBox(Flags flags)
CodeLabel *noLock = sl.NewCodeLabel();
CodeLabel *noAlloc = sl.NewCodeLabel();
+ CodeLabel *nullRef = sl.NewCodeLabel();
// Save address of value to be boxed
sl.X86EmitPushReg(kEBX);
sl.Emit16(0xda8b);
- // Save the MethodTable ptr
- sl.X86EmitPushReg(kECX);
-
- // mov ecx, [ecx]MethodTable.m_pWriteableData
- sl.X86EmitOffsetModRM(0x8b, kECX, kECX, offsetof(MethodTable, m_pWriteableData));
-
- // Check whether the class has not been initialized
- // test [ecx]MethodTableWriteableData.m_dwFlags,MethodTableWriteableData::enum_flag_Unrestored
- sl.X86EmitOffsetModRM(0xf7, (X86Reg)0x0, kECX, offsetof(MethodTableWriteableData, m_dwFlags));
- sl.Emit32(MethodTableWriteableData::enum_flag_Unrestored);
+ // Check for null ref
+ // test edx, edx
+ sl.X86EmitR2ROp(0x85, kEDX, kEDX);
- // Restore the MethodTable ptr in ecx
- sl.X86EmitPopReg(kECX);
-
- // jne noAlloc
- sl.X86EmitCondJump(noAlloc, X86CondCode::kJNE);
+ // je nullRef
+ sl.X86EmitCondJump(nullRef, X86CondCode::kJE);
// Emit the main body of the trial allocator
EmitCore(&sl, noLock, noAlloc, flags);
@@ -527,8 +518,9 @@ void *JIT_TrialAlloc::GenBox(Flags flags)
sl.X86EmitReturn(0);
- // Come here in case of no space
+ // Come here in case of no space or null ref
sl.EmitLabel(noAlloc);
+ sl.EmitLabel(nullRef);
// Release the lock in the uniprocessor case
EmitNoAllocCode(&sl, flags);
diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp
index 0e2cbd76b566ca264edcff6099a6e90af511a869..44ec15481fa2f4141d1ada96204d7da17920385c 100644
--- a/src/coreclr/vm/jithelpers.cpp
+++ b/src/coreclr/vm/jithelpers.cpp
@@ -2691,6 +2691,10 @@ HCIMPL2(Object*, JIT_Box, CORINFO_CLASS_HANDLE type, void* unboxedData)
GCPROTECT_BEGININTERIOR(unboxedData);
HELPER_METHOD_POLL();
+ // A null can be passed for boxing of a null ref.
+ if (unboxedData == NULL)
+ COMPlusThrow(kNullReferenceException);
+
TypeHandle clsHnd(type);
_ASSERTE(!clsHnd.IsTypeDesc()); // boxable types have method tables
diff --git a/src/mono/mono/metadata/threads.c b/src/mono/mono/metadata/threads.c
index 378cec13b1efe02ae6c3f35105ba5caa96541cd1..de31cb1a120dc44b7a0be08448b81ecc0248ea7a 100644
--- a/src/mono/mono/metadata/threads.c
+++ b/src/mono/mono/metadata/threads.c
@@ -2060,13 +2060,30 @@ ves_icall_System_Threading_Thread_Join_internal (MonoThreadObjectHandle thread_h
return FALSE;
}
+// this is a bad idea but we're doing it anyway. we need to propagate
+// an exception out of these icalls in some way.
+static size_t
+set_pending_null_reference_exception (void)
+{
+ ERROR_DECL (error);
+ mono_error_set_null_reference (error);
+ mono_error_set_pending_exception (error);
+ return 0;
+}
+
gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
{
+ if (G_UNLIKELY (!location))
+ return (gint32)set_pending_null_reference_exception ();
+
return mono_atomic_inc_i32 (location);
}
gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
{
+ if (G_UNLIKELY (!location))
+ return (gint64)set_pending_null_reference_exception ();
+
#if SIZEOF_VOID_P == 4
if (G_UNLIKELY ((size_t)location & 0x7)) {
gint64 ret;
@@ -2082,11 +2099,17 @@ gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
{
+ if (G_UNLIKELY (!location))
+ return (gint32)set_pending_null_reference_exception ();
+
return mono_atomic_dec_i32(location);
}
gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
{
+ if (G_UNLIKELY (!location))
+ return (gint64)set_pending_null_reference_exception ();
+
#if SIZEOF_VOID_P == 4
if (G_UNLIKELY ((size_t)location & 0x7)) {
gint64 ret;
@@ -2102,12 +2125,21 @@ gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
{
+ if (G_UNLIKELY (!location))
+ return (gint32)set_pending_null_reference_exception ();
+
return mono_atomic_xchg_i32(location, value);
}
void
ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject *volatile*location, MonoObject *volatile*value, MonoObject *volatile*res)
{
+ if (G_UNLIKELY (!location))
+ {
+ (void)set_pending_null_reference_exception ();
+ return;
+ }
+
// Coop-equivalency here via pointers to pointers.
// value and res are to managed frames, location ought to be (or member or global) but it cannot be guaranteed.
//
@@ -2123,6 +2155,8 @@ ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject *volatile*loc
gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
{
IntFloatUnion val, ret;
+ if (G_UNLIKELY (!location))
+ return (gfloat)set_pending_null_reference_exception ();
val.fval = value;
ret.ival = mono_atomic_xchg_i32((gint32 *) location, val.ival);
@@ -2133,6 +2167,9 @@ gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location,
gint64
ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
{
+ if (G_UNLIKELY (!location))
+ return (gint64)set_pending_null_reference_exception ();
+
#if SIZEOF_VOID_P == 4
if (G_UNLIKELY ((size_t)location & 0x7)) {
gint64 ret;
@@ -2150,6 +2187,8 @@ gdouble
ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
{
LongDoubleUnion val, ret;
+ if (G_UNLIKELY (!location))
+ return (gdouble)set_pending_null_reference_exception ();
val.fval = value;
ret.ival = (gint64)mono_atomic_xchg_i64((gint64 *) location, val.ival);
@@ -2159,11 +2198,17 @@ ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdoub
gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
{
+ if (G_UNLIKELY (!location))
+ return (gint32)set_pending_null_reference_exception ();
+
return mono_atomic_cas_i32(location, value, comparand);
}
gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
{
+ if (G_UNLIKELY (!location))
+ return (gint32)set_pending_null_reference_exception ();
+
gint32 r = mono_atomic_cas_i32(location, value, comparand);
*success = r == comparand;
return r;
@@ -2172,6 +2217,12 @@ gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32
void
ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject *volatile*location, MonoObject *volatile*value, MonoObject *volatile*comparand, MonoObject *volatile* res)
{
+ if (G_UNLIKELY (!location))
+ {
+ (void)set_pending_null_reference_exception ();
+ return;
+ }
+
// Coop-equivalency here via pointers to pointers.
// value and comparand and res are to managed frames, location ought to be (or member or global) but it cannot be guaranteed.
//
@@ -2187,6 +2238,8 @@ ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject *volat
gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
{
IntFloatUnion val, ret, cmp;
+ if (G_UNLIKELY (!location))
+ return (gfloat)set_pending_null_reference_exception ();
val.fval = value;
cmp.fval = comparand;
@@ -2198,6 +2251,9 @@ gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *lo
gdouble
ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
{
+ if (G_UNLIKELY (!location))
+ return (gdouble)set_pending_null_reference_exception ();
+
#if SIZEOF_VOID_P == 8
LongDoubleUnion val, comp, ret;
@@ -2222,6 +2278,9 @@ ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location
gint64
ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
{
+ if (G_UNLIKELY (!location))
+ return (gint64)set_pending_null_reference_exception ();
+
#if SIZEOF_VOID_P == 4
if (G_UNLIKELY ((size_t)location & 0x7)) {
gint64 old;
@@ -2239,12 +2298,18 @@ ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, g
gint32
ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
{
+ if (G_UNLIKELY (!location))
+ return (gint32)set_pending_null_reference_exception ();
+
return mono_atomic_add_i32 (location, value);
}
gint64
ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
{
+ if (G_UNLIKELY (!location))
+ return (gint64)set_pending_null_reference_exception ();
+
#if SIZEOF_VOID_P == 4
if (G_UNLIKELY ((size_t)location & 0x7)) {
gint64 ret;
@@ -2261,6 +2326,9 @@ ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
gint64
ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
{
+ if (G_UNLIKELY (!location))
+ return (gint64)set_pending_null_reference_exception ();
+
#if SIZEOF_VOID_P == 4
if (G_UNLIKELY ((size_t)location & 0x7)) {
gint64 ret;
diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c
index 5e2907780faa99199c5e2f078638f8e76cfeca54..ed3a579523e5afa1e6371c891d706c2d95397f01 100644
--- a/src/mono/mono/mini/interp/interp.c
+++ b/src/mono/mono/mini/interp/interp.c
@@ -6681,6 +6681,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
gboolean flag = FALSE;
gint64 *dest = LOCAL_VAR (ip [2], gint64*);
gint64 exch = LOCAL_VAR (ip [3], gint64);
+ NULL_CHECK(dest);
#if SIZEOF_VOID_P == 4
if (G_UNLIKELY (((size_t)dest) & 0x7)) {
gint64 result;
diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c
index 6aecbff96dd1c8108db2e5f43901556c9a3874bc..17b78eb529462172b5ad80d78e37c2437e6a8a31 100644
--- a/src/mono/mono/mini/intrinsics.c
+++ b/src/mono/mono/mini/intrinsics.c
@@ -1238,6 +1238,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
ins_iconst->dreg = mono_alloc_ireg (cfg);
MONO_ADD_INS (cfg->cbb, ins_iconst);
+ MONO_EMIT_NULL_CHECK (cfg, args [0]->dreg, FALSE);
MONO_INST_NEW (cfg, ins, opcode);
ins->dreg = mono_alloc_ireg (cfg);
ins->inst_basereg = args [0]->dreg;
@@ -1266,6 +1267,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
ins_iconst->dreg = mono_alloc_ireg (cfg);
MONO_ADD_INS (cfg->cbb, ins_iconst);
+ MONO_EMIT_NULL_CHECK (cfg, args [0]->dreg, FALSE);
MONO_INST_NEW (cfg, ins, opcode);
ins->dreg = mono_alloc_ireg (cfg);
ins->inst_basereg = args [0]->dreg;
@@ -1304,6 +1306,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
// For now, only Add is supported in non-LLVM back-ends
if (opcode && (COMPILE_LLVM (cfg) || mono_arch_opcode_supported (opcode))) {
+ MONO_EMIT_NULL_CHECK (cfg, args [0]->dreg, FALSE);
MONO_INST_NEW (cfg, ins, opcode);
ins->dreg = mono_alloc_ireg (cfg);
ins->inst_basereg = args [0]->dreg;
@@ -1363,6 +1366,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
if (is_ref && !mini_debug_options.weak_memory_model)
mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
+ MONO_EMIT_NULL_CHECK (cfg, args [0]->dreg, FALSE);
MONO_INST_NEW (cfg, ins, opcode);
ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
ins->inst_basereg = args [0]->dreg;
@@ -1466,6 +1470,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
if (is_ref && !mini_debug_options.weak_memory_model)
mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
+ MONO_EMIT_NULL_CHECK (cfg, args [0]->dreg, FALSE);
MONO_INST_NEW (cfg, ins, opcode);
ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
ins->sreg1 = args [0]->dreg;
diff --git a/src/tests/baseservices/invalid_operations/InvalidOperations.csproj b/src/tests/baseservices/invalid_operations/InvalidOperations.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..3c04f092ae83ca3d48380b9f8b5778a74ed0d30b
--- /dev/null
+++ b/src/tests/baseservices/invalid_operations/InvalidOperations.csproj
@@ -0,0 +1,12 @@
+
+
+ Exe
+ true
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/tests/baseservices/invalid_operations/ManagedPointers.cs b/src/tests/baseservices/invalid_operations/ManagedPointers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c5357cf03541e6b3f867e279883cd992215b1856
--- /dev/null
+++ b/src/tests/baseservices/invalid_operations/ManagedPointers.cs
@@ -0,0 +1,84 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+using Xunit;
+
+public unsafe class ManagedPointers
+{
+ [Fact]
+ public static void Validate_BoxingHelpers_NullByRef()
+ {
+ Console.WriteLine($"Running {nameof(Validate_BoxingHelpers_NullByRef)}...");
+ Assert.Throws(() =>
+ {
+ object boxed = Unsafe.NullRef();
+ });
+ Assert.Throws(() =>
+ {
+ object boxed = Unsafe.NullRef();
+ });
+ Assert.Throws(() =>
+ {
+ object boxed = Unsafe.NullRef();
+ });
+ }
+
+ [Fact]
+ public static void Validate_GeneratedILStubs_NullByRef()
+ {
+ Console.WriteLine($"Running {nameof(Validate_GeneratedILStubs_NullByRef)}...");
+ {
+ var fptr = (delegate*unmanaged[)(delegate*unmanaged)&PassByRef;
+ Assert.Equal(0, fptr(ref Unsafe.NullRef()));
+ }
+
+ {
+ var fptr = (delegate*unmanaged][)(delegate*unmanaged)&PassByRef;
+ Assert.Equal(0, fptr(ref Unsafe.NullRef()));
+ }
+
+ Assert.Throws(() =>
+ {
+ var fptr = (delegate*unmanaged][)(delegate*unmanaged)&PassByRef;
+ fptr(ref Unsafe.NullRef());
+ });
+
+ [UnmanagedCallersOnly]
+ static nint PassByRef(void* a) => (nint)a;
+ }
+
+ [Fact]
+ public static void Validate_IntrinsicMethodsWithByRef_NullByRef()
+ {
+ Console.WriteLine($"Running {nameof(Validate_IntrinsicMethodsWithByRef_NullByRef)}...");
+
+ Assert.Throws(() => Interlocked.Increment(ref Unsafe.NullRef()));
+ Assert.Throws(() => Interlocked.Increment(ref Unsafe.NullRef()));
+ Assert.Throws(() => Interlocked.Decrement(ref Unsafe.NullRef()));
+ Assert.Throws(() => Interlocked.Decrement(ref Unsafe.NullRef()));
+
+ Assert.Throws(() => Interlocked.And(ref Unsafe.NullRef(), 0));
+ Assert.Throws(() => Interlocked.And(ref Unsafe.NullRef(), 0));
+ Assert.Throws(() => Interlocked.Or(ref Unsafe.NullRef(), 0));
+ Assert.Throws(() => Interlocked.Or(ref Unsafe.NullRef(), 0));
+
+ Assert.Throws(() => Interlocked.Exchange(ref Unsafe.NullRef(), 0));
+ Assert.Throws(() => Interlocked.Exchange(ref Unsafe.NullRef(), 0));
+ Assert.Throws(() => Interlocked.Exchange(ref Unsafe.NullRef(), 0));
+ Assert.Throws(() => Interlocked.Exchange(ref Unsafe.NullRef(), 0));
+ Assert.Throws(() => Interlocked.Exchange(ref Unsafe.NullRef]