未验证 提交 4adb1172 编写于 作者: A Aaron Robinson 提交者: GitHub

Harden for null byrefs (#70317)

* Remove enum_flag_Unrestored usage in boxing stubs.

* Add AND instruction (21h) to x86 decoder.

* Update mono for null ref in interpreter paths.

* Disable test on llvmfullaot and wasm

* Handle null destination for intrinsics.
上级 e9175f47
......@@ -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
......
......@@ -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
......
......@@ -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));
......
......@@ -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));
......
......@@ -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;
......
......@@ -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);
......
......@@ -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
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="ManagedPointers.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(TestSourceDir)Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
</ItemGroup>
</Project>
\ No newline at end of file
// 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<NullReferenceException>(() =>
{
object boxed = Unsafe.NullRef<int>();
});
Assert.Throws<NullReferenceException>(() =>
{
object boxed = Unsafe.NullRef<Guid>();
});
Assert.Throws<NullReferenceException>(() =>
{
object boxed = Unsafe.NullRef<string>();
});
}
[Fact]
public static void Validate_GeneratedILStubs_NullByRef()
{
Console.WriteLine($"Running {nameof(Validate_GeneratedILStubs_NullByRef)}...");
{
var fptr = (delegate*unmanaged<ref int, nint>)(delegate*unmanaged<void*, nint>)&PassByRef;
Assert.Equal(0, fptr(ref Unsafe.NullRef<int>()));
}
{
var fptr = (delegate*unmanaged<ref Guid, nint>)(delegate*unmanaged<void*, nint>)&PassByRef;
Assert.Equal(0, fptr(ref Unsafe.NullRef<Guid>()));
}
Assert.Throws<NullReferenceException>(() =>
{
var fptr = (delegate*unmanaged<ref string, nint>)(delegate*unmanaged<void*, nint>)&PassByRef;
fptr(ref Unsafe.NullRef<string>());
});
[UnmanagedCallersOnly]
static nint PassByRef(void* a) => (nint)a;
}
[Fact]
public static void Validate_IntrinsicMethodsWithByRef_NullByRef()
{
Console.WriteLine($"Running {nameof(Validate_IntrinsicMethodsWithByRef_NullByRef)}...");
Assert.Throws<NullReferenceException>(() => Interlocked.Increment(ref Unsafe.NullRef<int>()));
Assert.Throws<NullReferenceException>(() => Interlocked.Increment(ref Unsafe.NullRef<long>()));
Assert.Throws<NullReferenceException>(() => Interlocked.Decrement(ref Unsafe.NullRef<int>()));
Assert.Throws<NullReferenceException>(() => Interlocked.Decrement(ref Unsafe.NullRef<long>()));
Assert.Throws<NullReferenceException>(() => Interlocked.And(ref Unsafe.NullRef<int>(), 0));
Assert.Throws<NullReferenceException>(() => Interlocked.And(ref Unsafe.NullRef<long>(), 0));
Assert.Throws<NullReferenceException>(() => Interlocked.Or(ref Unsafe.NullRef<int>(), 0));
Assert.Throws<NullReferenceException>(() => Interlocked.Or(ref Unsafe.NullRef<long>(), 0));
Assert.Throws<NullReferenceException>(() => Interlocked.Exchange(ref Unsafe.NullRef<int>(), 0));
Assert.Throws<NullReferenceException>(() => Interlocked.Exchange(ref Unsafe.NullRef<long>(), 0));
Assert.Throws<NullReferenceException>(() => Interlocked.Exchange(ref Unsafe.NullRef<float>(), 0));
Assert.Throws<NullReferenceException>(() => Interlocked.Exchange(ref Unsafe.NullRef<double>(), 0));
Assert.Throws<NullReferenceException>(() => Interlocked.Exchange(ref Unsafe.NullRef<object>(), new object()));
Assert.Throws<NullReferenceException>(() => Interlocked.Exchange<object>(ref Unsafe.NullRef<object>(), new object()));
Assert.Throws<NullReferenceException>(() => Interlocked.CompareExchange(ref Unsafe.NullRef<int>(), 0, 0));
Assert.Throws<NullReferenceException>(() => Interlocked.CompareExchange(ref Unsafe.NullRef<long>(), 0, 0));
Assert.Throws<NullReferenceException>(() => Interlocked.CompareExchange(ref Unsafe.NullRef<float>(), 0, 0));
Assert.Throws<NullReferenceException>(() => Interlocked.CompareExchange(ref Unsafe.NullRef<double>(), 0, 0));
Assert.Throws<NullReferenceException>(() => Interlocked.CompareExchange(ref Unsafe.NullRef<object>(), new object(), new object()));
Assert.Throws<NullReferenceException>(() => Interlocked.CompareExchange<object>(ref Unsafe.NullRef<object>(), new object(), new object()));
}
}
\ No newline at end of file
......@@ -3114,6 +3114,9 @@
<ExcludeList Include = "$(XunitTestBinBase)/Loader/classloader/generics/Pointers/**">
<Issue>Doesn't compile with LLVM AOT.</Issue>
</ExcludeList>
<ExcludeList Include = "$(XunitTestBinBase)/baseservices/invalid_operations/**">
<Issue>Doesn't compile with LLVM AOT.</Issue>
</ExcludeList>
</ItemGroup>
<ItemGroup Condition="'$(RuntimeFlavor)' == 'mono' and ('$(RuntimeVariant)' == 'llvmfullaot' or '$(RuntimeVariant)' == 'llvmaot') and '$(TargetArchitecture)' == 'arm64'">
......@@ -3290,6 +3293,9 @@
<Issue>https://github.com/dotnet/runtime/issues/54122</Issue>
</ExcludeList>
<ExcludeList Include = "$(XunitTestBinBase)/baseservices/invalid_operations/**">
<Issue>Function mismatch</Issue>
</ExcludeList>
<ExcludeList Include = "$(XunitTestBinBase)/baseservices/threading/DeadThreads/DeadThreads/**">
<Issue>https://github.com/dotnet/runtime/issues/41472</Issue>
</ExcludeList>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册