Enable Invoke and GetValue for ref-returning members#17639
Conversation
https://github.com/dotnet/corefx/issues/15960 Returned magic object is the object pointed to by the ref. If the ref is null, NullReferenceException.
| // | ||
| // first take care of all the NO_INVOKE cases. | ||
| if (ContainsGenericParameters || | ||
| ReturnType.IsByRef || |
There was a problem hiding this comment.
Do we need IsByRefLike condition here as well? Or are the ByRefLike returns handled somewhere else?
There was a problem hiding this comment.
That gets handled in the "else" branch (RuntimeMethodHandle.GetSecurityFlags(this);)
| // first take care of all the NO_INVOKE cases. | ||
| if (ContainsGenericParameters || | ||
| ReturnType.IsByRef || | ||
| (ReturnType.IsByRef && ReturnType.GetElementType().IsByRefLike) || |
There was a problem hiding this comment.
Update the message that will be thrown for this case in ThrowNoInvokeException ?
| COMPlusThrow(kNullReferenceException, IDS_INVOKE_NULLREF_RETURNED); | ||
| } | ||
|
|
||
| // If the target was a value type, that scenario was handled above as part of the code path that copies value types into preallocated boxed objects. |
There was a problem hiding this comment.
Can we just call InvokeUtil::CreateObject here?
There was a problem hiding this comment.
InvokeUtil::CreateObject assumes it's free to allocate objects since the pointer it receives is in non-gc-heap memory. The specific cases we call it for happen not to do that but spreading out the GC restriction over function calls like that leaves the code base in a more fragile state than I'd like to. I went back and forth on this one several times - I decided that the small amount of repetition here was worth paying in order to keep the fragility in that one method.
There was a problem hiding this comment.
Ok, there are no other callers for InvokeUtil::CreateObject and it was doing things it didn't need to do so I changed the rules for it and made the byref case use it.
| // CreateObjectAfterInvoke | ||
| // This routine will create the specified object from the value returned by the Invoke target. | ||
| // | ||
| // This does not handle the ELEMENT_TYPE_VALUETYPE case. There is no way for this function to handle that case in a GC-safe way. |
There was a problem hiding this comment.
There is no way for this function to handle that case in a GC-safe way.
I do not think that this is valid statement. It can be handled by protecting pValue using GCPROTECT_BEGININTERIOR.
There was a problem hiding this comment.
Is that also safe when pValue is a completely unmanaged pointer (i.e. into the stack?)
There was a problem hiding this comment.
(I think it is fine for this function to not handle ELEMENT_TYPE_VALUETYPE.)
There was a problem hiding this comment.
Ok, we'll delete the phrase from the comment, then.
There was a problem hiding this comment.
Is that also safe when pValue is a completely unmanaged pointer (i.e. into the stack?)
Yes.
| obj = AllocateObject(pMT); | ||
| memcpyNoGCRefs(obj->UnBox(), &capturedValue, size); | ||
| } | ||
| break; |
There was a problem hiding this comment.
ELEMENT_TYPE_BYREF should not be needed anymore. Also, it is referring to resource string that no longer exists.
|
LGTM otherwise. I assume that there are matching corefx tests coming. |
| @@ -666,6 +671,9 @@ OBJECTREF InvokeUtil::CreateObject(TypeHandle th, void * pValue) { | |||
| MethodTable *pMT = NULL; | |||
There was a problem hiding this comment.
GetSignatureCorElementType is a regular element type that you find in metadata signatures, etc.
GetInternalCorElementType used by the caller is relevant for calling convention - what gets passed in registers, etc.
The bug that broke corefx is when these two differ.
There was a problem hiding this comment.
Yeah, it broke enums. I'm thinking we should just strip CreateObject down to handling objects, pointers and function pointers and let the prealloc-and-copy code handle all value types.
* Reapply #17639 * tryagain-wip 4/23/2018 7:27:37 AM - Fix Invoke of enum-returning methods * Assert for refbufargs implying valuetype * Catch ref to void in managed layer
…pes (#13901) CoreCLR allows reflection on methods with ByRef return types under certain conditions. The PR implementing it is dotnet/coreclr#17639. Mono already implemented most of it in the marshalling code but artificially blocked it in `ves_icall_InternalInvoke`. I changed the condition for the exception to match the condition in `emit_invoke_call` (marshal-ilgen.c). It's similar to the condition in CoreCLR, but it may not handle byref-like types correctly. It would have to fixed on both places if it turns out to be the case. The remaining issue is that null references returned in ByRef are not checked and converted to correct exception. It should result in `NullReferenceException` with special message that doesn't get wrapped in `TargetInvocationException`. I put a TODO marker at a place where I think it should be handled, but it's a bit over my head to implement it. /cc @vargaz
https://github.com/dotnet/corefx/issues/15960
Returned magic object is the object pointed to by
the ref. If the ref is null, NullReferenceException.