Skip to content

Commit

Permalink
[NativeAot] Null ref return is wrapped in TargetInvocationException (#…
Browse files Browse the repository at this point in the history
…69838)

When a null ref return method is invoked. Fixes #69755
  • Loading branch information
LakshanF authored May 31, 2022
1 parent 292e8c9 commit 68d16d5
Show file tree
Hide file tree
Showing 5 changed files with 12 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -127,5 +127,10 @@ public static void ThrowArgumentOutOfRangeException()
{
throw new ArgumentOutOfRangeException();
}

public static void ThrowInvokeNullRefReturned()
{
throw new NullReferenceException(SR.NullReference_InvokeNullRefReturned);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -427,9 +427,6 @@ internal static unsafe object CallDynamicInvokeMethod(
}
}

if (result == NullByRefValueSentinel)
throw new NullReferenceException(SR.NullReference_InvokeNullRefReturned);

return result;
}
}
Expand Down Expand Up @@ -671,18 +668,5 @@ public static object DynamicInvokeParamHelperCore(ref ArgSetupState argSetupStat
}
}
}

private static volatile object _nullByRefValueSentinel;
public static object NullByRefValueSentinel
{
get
{
if (_nullByRefValueSentinel == null)
{
Interlocked.CompareExchange(ref _nullByRefValueSentinel, new object(), null);
}
return _nullByRefValueSentinel;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1123,9 +1123,9 @@ private static unsafe void InvokeTarget(void* allocatedStackBuffer, ref CallConv
if (returnType == CorElementType.ELEMENT_TYPE_BYREF && returnValueToCopy == null)
{
// This is a byref return and dereferencing it would result in a NullReferenceException.
// Set the return value to a sentinel that InvokeUtils will recognize.
// Can't throw from here or we would wrap this in a TargetInvocationException.
returnValue = InvokeUtils.NullByRefValueSentinel;
CompilerHelpers.ThrowHelpers.ThrowInvokeNullRefReturned();
// Unreachable
returnValue = null;
}
else if (RuntimeAugments.IsUnmanagedPointerType(returnTypeRuntimeTypeHandle))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,9 +388,7 @@ public override MethodIL EmitIL()
//
// !if (ReturnType is ByRef)
// ByRefNull:
// pop
// call InvokeUtils.get_NullByRefValueSentinel
// ret
// throw NullReferenceException

ILCodeLabel lStaticCall = emitter.NewCodeLabel();
ILCodeLabel lProcessReturn = emitter.NewCodeLabel();
Expand Down Expand Up @@ -512,9 +510,8 @@ public override MethodIL EmitIL()
if (lByRefReturnNull != null)
{
returnCodeStream.EmitLabel(lByRefReturnNull);
returnCodeStream.Emit(ILOpcode.pop);
returnCodeStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("get_NullByRefValueSentinel", null)));
returnCodeStream.Emit(ILOpcode.ret);
MethodDesc nullReferencedExceptionHelper = Context.GetHelperEntryPoint("ThrowHelpers", "ThrowInvokeNullRefReturned");
returnCodeStream.EmitCallThrowHelper(emitter, nullReferencedExceptionHelper);
}

return emitter.Link(this);
Expand Down
2 changes: 1 addition & 1 deletion src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1215,7 +1215,7 @@ public static unsafe void TestNullRefReturnOfPointer()

PropertyInfo p = typeof(TestClassIntPointer).GetProperty(nameof(TestClassIntPointer.NullRefReturningProp));
Assert.NotNull(p);
Assert.Throws<NullReferenceException>(() => p.GetValue(tc));
Assert.Throws<TargetInvocationException>(() => p.GetValue(tc));
}

public static unsafe void TestByRefLikeRefReturn()
Expand Down

0 comments on commit 68d16d5

Please sign in to comment.