Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Unsafe.IsNullRef and Unsafe.NullRef #40008

Merged
merged 8 commits into from
Jul 29, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public static void InitBlockUnaligned(ref byte startAddress, byte value, uint by
public static unsafe void InitBlockUnaligned(void* startAddress, byte value, uint byteCount) { }
public static bool IsAddressGreaterThan<T>(ref T left, ref T right) { throw null; }
public static bool IsAddressLessThan<T>(ref T left, ref T right) { throw null; }
public static bool IsNullRef<T>(ref T source) { throw null; }
public static ref T NullRef<T>() { throw null; }
public static T ReadUnaligned<T>(ref byte source) { throw null; }
public static unsafe T ReadUnaligned<T>(void* source) { throw null; }
public static unsafe T Read<T>(void* source) { throw null; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,26 @@
ret
} // end of method Unsafe::IsAddressLessThan

.method public hidebysig static bool IsNullRef<T>(!!T& source) cil managed aggressiveinlining
{
.custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 )
.maxstack 2
ldarg.0
ldc.i4.0
conv.u
ceq
ret
} // end of method Unsafe::IsNullRef

.method public hidebysig static !!T& NullRef<T>() cil managed aggressiveinlining
{
.custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 )
.maxstack 1
ldc.i4.0
conv.u
ret
} // end of method Unsafe::NullRef
jkotas marked this conversation as resolved.
Show resolved Hide resolved

} // end of class System.Runtime.CompilerServices.Unsafe

.class private auto ansi sealed beforefieldinit System.Runtime.Versioning.NonVersionableAttribute
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ public static void ByteOffsetStackByte4()
public static unsafe void AsRef()
{
byte[] b = new byte[4] { 0x42, 0x42, 0x42, 0x42 };
fixed (byte * p = b)
fixed (byte* p = b)
{
ref int r = ref Unsafe.AsRef<int>(p);
Assert.Equal(0x42424242, r);
Expand Down Expand Up @@ -839,7 +839,7 @@ public static void SkipInit()
Unsafe.SkipInit(out double doubleValue);

// Validate that calling on user-defined unmanaged structs works.

Unsafe.SkipInit(out Byte4 byte4Value);
Unsafe.SkipInit(out Byte4Short2 byte4Short2Value);
Unsafe.SkipInit(out Byte512 byte512Value);
Expand Down Expand Up @@ -931,6 +931,84 @@ public static void SkipInit_PreservesPrevious()
Unsafe.SkipInit(out stringValue);
Assert.Equal("25", stringValue);
}

[Fact]
public static unsafe void IsNullRef_NotNull()
{
// Validate that calling with a primitive type works.

int intValue = 5;
Assert.False(Unsafe.IsNullRef<int>(ref intValue));

// Validate that calling on user-defined unmanaged structs works.

Int32Double int32DoubleValue = default;
Assert.False(Unsafe.IsNullRef<Int32Double>(ref int32DoubleValue));

// Validate that calling on reference types works.

object objectValue = new object();
Assert.False(Unsafe.IsNullRef<object>(ref objectValue));

string stringValue = nameof(IsNullRef_NotNull);
Assert.False(Unsafe.IsNullRef<string>(ref stringValue));

// Validate on ref created from a pointer

int* p = (int*)1;
Assert.False(Unsafe.IsNullRef<int>(ref Unsafe.AsRef<int>(p)));
}

[Fact]
public static unsafe void IsNullRef_Null()
{
// Validate that calling with a primitive type works.

Assert.True(Unsafe.IsNullRef<int>(ref Unsafe.AsRef<int>(null)));

// Validate that calling on user-defined unmanaged structs works.

Assert.True(Unsafe.IsNullRef<Int32Double>(ref Unsafe.AsRef<Int32Double>(null)));

// Validate that calling on reference types works.

Assert.True(Unsafe.IsNullRef<object>(ref Unsafe.AsRef<object>(null)));
Assert.True(Unsafe.IsNullRef<string>(ref Unsafe.AsRef<string>(null)));

// Validate on ref created from a pointer

int* p = (int*)0;
Assert.True(Unsafe.IsNullRef<int>(ref Unsafe.AsRef<int>(p)));
}

[Fact]
public static unsafe void NullRef()
{
// Validate that calling with a primitive type works.

Assert.True(Unsafe.IsNullRef<int>(ref Unsafe.NullRef<int>()));

// Validate that calling on user-defined unmanaged structs works.

Assert.True(Unsafe.IsNullRef<Int32Double>(ref Unsafe.NullRef<Int32Double>()));

// Validate that calling on reference types works.

Assert.True(Unsafe.IsNullRef<object>(ref Unsafe.NullRef<object>()));
Assert.True(Unsafe.IsNullRef<string>(ref Unsafe.NullRef<string>()));

// Validate that pinning results in a null pointer

fixed (void* p = &Unsafe.NullRef<int>())
{
Assert.True(p == (void*)0);
}

// Validate that dereferencing a null ref throws a NullReferenceException

Assert.Throws<NullReferenceException>(() => Unsafe.NullRef<int>() = 42);
Assert.Throws<NullReferenceException>(() => Unsafe.NullRef<int>());
}
}

[StructLayout(LayoutKind.Explicit)]
Expand Down Expand Up @@ -968,7 +1046,7 @@ public unsafe struct Byte512
public fixed byte Bytes[512];
}

[StructLayout(LayoutKind.Explicit, Size=16)]
[StructLayout(LayoutKind.Explicit, Size = 16)]
public unsafe struct Int32Double
{
[FieldOffset(0)]
Expand Down