Esempio n. 1
0
        public static unsafe void StructureToPtr(object structure, IntPtr ptr, bool fDeleteOld)
        {
            if (structure == null)
            {
                throw new ArgumentNullException(nameof(structure));
            }

            if (ptr == IntPtr.Zero)
            {
                throw new ArgumentNullException(nameof(ptr));
            }

            if (fDeleteOld)
            {
                DestroyStructure(ptr, structure.GetType());
            }

            RuntimeTypeHandle structureTypeHandle = structure.GetType().TypeHandle;

            if (structureTypeHandle.IsGenericType() || structureTypeHandle.IsGenericTypeDefinition())
            {
                throw new ArgumentException(SR.Argument_NeedNonGenericObject, nameof(structure));
            }

            IntPtr marshalStub;

            if (structureTypeHandle.IsBlittable())
            {
                if (!RuntimeAugments.InteropCallbacks.TryGetStructMarshalStub(structureTypeHandle, out marshalStub))
                {
                    marshalStub = IntPtr.Zero;
                }
            }
            else
            {
                marshalStub = RuntimeAugments.InteropCallbacks.GetStructMarshalStub(structureTypeHandle);
            }

            if (marshalStub != IntPtr.Zero)
            {
                if (structureTypeHandle.IsValueType())
                {
                    ((delegate * < ref byte, ref byte, void >)marshalStub)(ref structure.GetRawData(), ref *(byte *)ptr);
                }
                else
                {
                    ((delegate * < object, ref byte, void >)marshalStub)(structure, ref *(byte *)ptr);
                }
            }
            else
            {
                nuint size = (nuint)RuntimeAugments.InteropCallbacks.GetStructUnsafeStructSize(structureTypeHandle);

                Buffer.Memmove(ref *(byte *)ptr, ref structure.GetRawData(), size);
            }
        }
Esempio n. 2
0
        internal static unsafe void PtrToStructureImpl(IntPtr ptr, object structure)
        {
            RuntimeTypeHandle structureTypeHandle = structure.GetType().TypeHandle;

            // Boxed struct start at offset 1 (EEType* at offset 0) while class start at offset 0
            int offset = structureTypeHandle.IsValueType() ? 1 : 0;

            IntPtr unmarshalStub;

            if (structureTypeHandle.IsBlittable())
            {
                if (!RuntimeAugments.InteropCallbacks.TryGetStructUnmarshalStub(structureTypeHandle, out unmarshalStub))
                {
                    unmarshalStub = IntPtr.Zero;
                }
            }
            else
            {
                unmarshalStub = RuntimeAugments.InteropCallbacks.GetStructUnmarshalStub(structureTypeHandle);
            }

            if (unmarshalStub != IntPtr.Zero)
            {
                InteropExtensions.PinObjectAndCall(structure,
                                                   unboxedStructPtr =>
                {
                    CalliIntrinsics.Call <int>(
                        unmarshalStub,
                        (void *)ptr,                                        // unsafe (no need to adjust as it is always struct)
                        ((void *)((IntPtr *)unboxedStructPtr + offset))     // safe (need to adjust offset as it could be class)
                        );
                });
            }
            else
            {
                int structSize = Marshal.SizeOf(structure);
                InteropExtensions.PinObjectAndCall(structure,
                                                   unboxedStructPtr =>
                {
                    InteropExtensions.Memcpy(
                        (IntPtr)((IntPtr *)unboxedStructPtr + offset),      // safe (need to adjust offset as it could be class)
                        ptr,                                                // unsafe (no need to adjust as it is always struct)
                        structSize
                        );
                });
            }
        }
Esempio n. 3
0
        public override int GetStructUnsafeStructSize(RuntimeTypeHandle structureTypeHandle)
        {
            if (TryGetStructUnsafeStructSize(structureTypeHandle, out int size))
            {
                return(size);
            }

            // IsBlittable() checks whether the type contains GC references. It is approximate check with false positives.
            // This fallback path will return incorrect answer for types that do not contain GC references, but that are
            // not actually blittable; e.g. for types with bool fields.
            if (structureTypeHandle.IsBlittable() && structureTypeHandle.IsValueType())
            {
                return(structureTypeHandle.GetValueTypeSize());
            }

            throw new MissingInteropDataException(SR.StructMarshalling_MissingInteropData, Type.GetTypeFromHandle(structureTypeHandle));
        }
Esempio n. 4
0
        private static int SizeOf(Type t)
        {
            Debug.Assert(t != null, "t");

            if (t.TypeHandle.IsGenericType())
            {
                throw new ArgumentException(SR.Argument_NeedNonGenericType, "t");
            }

            RuntimeTypeHandle typeHandle = t.TypeHandle;

            if (!(typeHandle.IsBlittable() && typeHandle.IsValueType()))
            {
                throw new ArgumentException(SR.Argument_NeedStructWithNoRefs);
            }

            return(typeHandle.GetValueTypeSize());
        }
Esempio n. 5
0
        internal static unsafe void PtrToStructureImpl(IntPtr ptr, object structure)
        {
            RuntimeTypeHandle structureTypeHandle = structure.GetType().TypeHandle;

            IntPtr unmarshalStub;

            if (structureTypeHandle.IsBlittable())
            {
                if (!RuntimeAugments.InteropCallbacks.TryGetStructUnmarshalStub(structureTypeHandle, out unmarshalStub))
                {
                    unmarshalStub = IntPtr.Zero;
                }
            }
            else
            {
                unmarshalStub = RuntimeAugments.InteropCallbacks.GetStructUnmarshalStub(structureTypeHandle);
            }

            if (unmarshalStub != IntPtr.Zero)
            {
                if (structureTypeHandle.IsValueType())
                {
                    CalliIntrinsics.Call(
                        unmarshalStub,
                        ref *(byte *)ptr,
                        ref structure.GetRawData());
                }
                else
                {
                    CalliIntrinsics.Call(
                        unmarshalStub,
                        ref *(byte *)ptr,
                        structure);
                }
            }
            else
            {
                nuint size = (nuint)RuntimeAugments.InteropCallbacks.GetStructUnsafeStructSize(structureTypeHandle);
                fixed(byte *pDest = &structure.GetRawData())
                {
                    Buffer.Memmove(pDest, (byte *)ptr, size);
                }
            }
        }
Esempio n. 6
0
        internal static unsafe void PtrToStructureImpl(IntPtr ptr, object structure)
        {
            RuntimeTypeHandle structureTypeHandle = structure.GetType().TypeHandle;

            // Boxed struct start at offset 1 (EEType* at offset 0) while class start at offset 0
            nuint offset = structureTypeHandle.IsValueType() ? (nuint)sizeof(IntPtr) : 0;

            IntPtr unmarshalStub;
            if (structureTypeHandle.IsBlittable())
            {
                if (!RuntimeAugments.InteropCallbacks.TryGetStructUnmarshalStub(structureTypeHandle, out unmarshalStub))
                {
                    unmarshalStub = IntPtr.Zero;
                }
            }
            else
            {
                unmarshalStub = RuntimeAugments.InteropCallbacks.GetStructUnmarshalStub(structureTypeHandle);
            }

            ref byte dest = ref Unsafe.AddByteOffset(ref Unsafe.As<IntPtr, byte>(ref structure.m_pEEType), offset);
Esempio n. 7
0
        internal static unsafe void PtrToStructureImpl(IntPtr ptr, object structure)
        {
            RuntimeTypeHandle structureTypeHandle = structure.GetType().TypeHandle;

            IntPtr unmarshalStub;

            if (structureTypeHandle.IsBlittable())
            {
                if (!RuntimeAugments.InteropCallbacks.TryGetStructUnmarshalStub(structureTypeHandle, out unmarshalStub))
                {
                    unmarshalStub = IntPtr.Zero;
                }
            }
            else
            {
                unmarshalStub = RuntimeAugments.InteropCallbacks.GetStructUnmarshalStub(structureTypeHandle);
            }

            if (unmarshalStub != IntPtr.Zero)
            {
                if (structureTypeHandle.IsValueType())
                {
                    ((delegate * < ref byte, ref byte, void >)unmarshalStub)(ref *(byte *)ptr, ref structure.GetRawData());
                }
                else
                {
                    ((delegate * < ref byte, object, void >)unmarshalStub)(ref *(byte *)ptr, structure);
                }
            }
            else
            {
                nuint size = (nuint)RuntimeAugments.InteropCallbacks.GetStructUnsafeStructSize(structureTypeHandle);

                Buffer.Memmove(ref structure.GetRawData(), ref *(byte *)ptr, size);
            }
        }
Esempio n. 8
0
        private protected unsafe void CheckArguments(
            Span <object?> copyOfParameters,
            IntPtr *byrefParameters,
            Span <ParameterCopyBackAction> shouldCopyBack,
            ReadOnlySpan <object?> parameters,
            RuntimeType[] sigTypes,
            Binder?binder,
            CultureInfo?culture,
            BindingFlags invokeAttr
            )
        {
            Debug.Assert(parameters.Length > 0);

            ParameterInfo[]? paramInfos = null;
            for (int i = 0; i < parameters.Length; i++)
            {
                ParameterCopyBackAction copyBackArg = default;
                bool        isValueType             = false;
                object?     arg     = parameters[i];
                RuntimeType sigType = sigTypes[i];

                // Convert a Type.Missing to the default value.
                if (ReferenceEquals(arg, Type.Missing))
                {
                    paramInfos ??= GetParametersNoCopy();
                    ParameterInfo paramInfo = paramInfos[i];

                    if (paramInfo.DefaultValue == DBNull.Value)
                    {
                        throw new ArgumentException(SR.Arg_VarMissNull, nameof(parameters));
                    }

                    arg = paramInfo.DefaultValue;

                    if (sigType.IsNullableOfT)
                    {
                        copyBackArg = ParameterCopyBackAction.CopyNullable;

                        if (arg is not null)
                        {
                            // For nullable Enum types, the ParameterInfo.DefaultValue returns a raw value which
                            // needs to be parsed to the Enum type, for more info: https://github.com/dotnet/runtime/issues/12924
                            Type argumentType = sigType.GetGenericArguments()[0];
                            if (argumentType.IsEnum)
                            {
                                arg = Enum.ToObject(argumentType, arg);
                            }
                        }
                    }
                    else
                    {
                        copyBackArg = ParameterCopyBackAction.Copy;
                    }
                }

                if (arg is null)
                {
                    // Fast path for null reference types.
                    isValueType = RuntimeTypeHandle.IsValueType(sigType);
                    if (isValueType || RuntimeTypeHandle.IsByRef(sigType))
                    {
                        isValueType = sigType.CheckValue(ref arg, ref copyBackArg, binder, culture, invokeAttr);
                    }
                }
                else
                {
                    RuntimeType argType = (RuntimeType)arg.GetType();

                    if (ReferenceEquals(argType, sigType))
                    {
                        // Fast path when the value's type matches the signature type.
                        isValueType = RuntimeTypeHandle.IsValueType(argType);
                    }
                    else if (sigType.TryByRefFastPath(ref arg, ref isValueType))
                    {
                        // Fast path when the value's type matches the signature type of a byref parameter.
                        copyBackArg = ParameterCopyBackAction.Copy;
                    }
                    else
                    {
                        // Slow path that supports type conversions.
                        isValueType = sigType.CheckValue(ref arg, ref copyBackArg, binder, culture, invokeAttr);
                    }
                }

                // We need to perform type safety validation against the incoming arguments, but we also need
                // to be resilient against the possibility that some other thread (or even the binder itself!)
                // may mutate the array after we've validated the arguments but before we've properly invoked
                // the method. The solution is to copy the arguments to a different, not-user-visible buffer
                // as we validate them. n.b. This disallows use of ArrayPool, as ArrayPool-rented arrays are
                // considered user-visible to threads which may still be holding on to returned instances.
                // This separate array is also used to hold default values when 'null' is specified for value
                // types, and also used to hold the results from conversions such as from Int16 to Int32. For
                // compat, these default values and conversions are not be applied to the incoming arguments.
                shouldCopyBack[i]   = copyBackArg;
                copyOfParameters[i] = arg;

                if (isValueType)
                {
#if !MONO // Temporary until Mono is updated.
                    Debug.Assert(arg != null);
                    Debug.Assert(
                        arg.GetType() == sigType ||
                        (sigType.IsPointer && (arg.GetType() == typeof(IntPtr) || arg.GetType() == typeof(UIntPtr))) ||
                        (sigType.IsByRef && arg.GetType() == RuntimeTypeHandle.GetElementType(sigType)) ||
                        ((sigType.IsEnum || arg.GetType().IsEnum) && RuntimeType.GetUnderlyingType((RuntimeType)arg.GetType()) == RuntimeType.GetUnderlyingType(sigType)));
#endif
                    ByReference valueTypeRef = ByReference.Create(ref copyOfParameters[i] !.GetRawData());
                    *(ByReference *)(byrefParameters + i) = valueTypeRef;
                }
                else
                {
                    ByReference objRef = ByReference.Create(ref copyOfParameters[i]);
                    *(ByReference *)(byrefParameters + i) = objRef;
                }
            }
        }
Esempio n. 9
0
        private protected unsafe void CheckArguments(
            Span <object?> copyOfParameters,
            IntPtr *byrefParameters,
            Span <bool> shouldCopyBack,
            ReadOnlySpan <object?> parameters,
            RuntimeType[] sigTypes,
            Binder?binder,
            CultureInfo?culture,
            BindingFlags invokeAttr
            )
        {
            Debug.Assert(!parameters.IsEmpty);

            ParameterInfo[]? paramInfos = null;
            for (int i = 0; i < parameters.Length; i++)
            {
                bool        copyBackArg = false;
                bool        isValueType;
                object?     arg     = parameters[i];
                RuntimeType sigType = sigTypes[i];

                if (arg is null)
                {
                    // Fast path that avoids calling CheckValue() for reference types.
                    isValueType = RuntimeTypeHandle.IsValueType(sigType);
                    if (isValueType || RuntimeTypeHandle.IsByRef(sigType))
                    {
                        isValueType = sigType.CheckValue(ref arg, ref copyBackArg, binder, culture, invokeAttr);
                    }
                }
                else if (ReferenceEquals(arg.GetType(), sigType))
                {
                    // Fast path that avoids calling CheckValue() when argument value matches the signature type.
                    isValueType = RuntimeTypeHandle.IsValueType(sigType);
                }
                else
                {
                    paramInfos ??= GetParametersNoCopy();
                    ParameterInfo paramInfo = paramInfos[i];
                    if (!ReferenceEquals(arg, Type.Missing))
                    {
                        isValueType = sigType.CheckValue(ref arg, ref copyBackArg, binder, culture, invokeAttr);
                    }
                    else
                    {
                        if (paramInfo.DefaultValue == DBNull.Value)
                        {
                            throw new ArgumentException(SR.Arg_VarMissNull, nameof(parameters));
                        }

                        arg = paramInfo.DefaultValue;
                        if (ReferenceEquals(arg?.GetType(), sigType))
                        {
                            isValueType = RuntimeTypeHandle.IsValueType(sigType);
                        }
                        else
                        {
                            isValueType = sigType.CheckValue(ref arg, ref copyBackArg, binder, culture, invokeAttr);
                        }
                    }
                }

                // We need to perform type safety validation against the incoming arguments, but we also need
                // to be resilient against the possibility that some other thread (or even the binder itself!)
                // may mutate the array after we've validated the arguments but before we've properly invoked
                // the method. The solution is to copy the arguments to a different, not-user-visible buffer
                // as we validate them. n.b. This disallows use of ArrayPool, as ArrayPool-rented arrays are
                // considered user-visible to threads which may still be holding on to returned instances.
                // This separate array is also used to hold default values when 'null' is specified for value
                // types, and also used to hold the results from conversions such as from Int16 to Int32; these
                // default values and conversions should not be applied to the incoming arguments.
                shouldCopyBack[i]   = copyBackArg;
                copyOfParameters[i] = arg;

                if (isValueType)
                {
#if DEBUG
                    // Once Mono has managed conversion logic, VerifyValueType() can be lifted here as Asserts.
                    sigType.VerifyValueType(arg);
#endif
                    ByReference <byte> valueTypeRef = new(ref copyOfParameters[i] !.GetRawData());
                    *(ByReference <byte> *)(byrefParameters + i) = valueTypeRef;
                }
                else
                {
                    ByReference <object?> objRef = new(ref copyOfParameters[i]);
                    *(ByReference <object?> *)(byrefParameters + i) = objRef;
                }
            }
        }
Esempio n. 10
0
        public static unsafe void StructureToPtr(object structure, IntPtr ptr, bool fDeleteOld)
        {
            if (structure == null)
            {
                throw new ArgumentNullException(nameof(structure));
            }

            if (ptr == IntPtr.Zero)
            {
                throw new ArgumentNullException(nameof(ptr));
            }

            if (fDeleteOld)
            {
                DestroyStructure(ptr, structure.GetType());
            }

            RuntimeTypeHandle structureTypeHandle = structure.GetType().TypeHandle;

            if (structureTypeHandle.IsGenericType() || structureTypeHandle.IsGenericTypeDefinition())
            {
                throw new ArgumentException(nameof(structure), SR.Argument_NeedNonGenericObject);
            }

            // Boxed struct start at offset 1 (EEType* at offset 0) while class start at offset 0
            int offset = structureTypeHandle.IsValueType() ? 1 : 0;

            IntPtr marshalStub;

            if (structureTypeHandle.IsBlittable())
            {
                if (!RuntimeAugments.InteropCallbacks.TryGetStructMarshalStub(structureTypeHandle, out marshalStub))
                {
                    marshalStub = IntPtr.Zero;
                }
            }
            else
            {
                marshalStub = RuntimeAugments.InteropCallbacks.GetStructMarshalStub(structureTypeHandle);
            }

            if (marshalStub != IntPtr.Zero)
            {
                InteropExtensions.PinObjectAndCall(structure,
                                                   unboxedStructPtr =>
                {
                    CalliIntrinsics.Call <int>(
                        marshalStub,
                        ((void *)((IntPtr *)unboxedStructPtr + offset)),    // safe (need to adjust offset as it could be class)
                        (void *)ptr                                         // unsafe (no need to adjust as it is always struct)
                        );
                });
            }
            else
            {
                int structSize = Marshal.SizeOf(structure);
                InteropExtensions.PinObjectAndCall(structure,
                                                   unboxedStructPtr =>
                {
                    InteropExtensions.Memcpy(
                        ptr,                                                // unsafe (no need to adjust as it is always struct)
                        (IntPtr)((IntPtr *)unboxedStructPtr + offset),      // safe (need to adjust offset as it could be class)
                        structSize
                        );
                });
            }
        }