Skip to content

Complete warnings for AOT unsafe interop #74697

@jkotas

Description

@jkotas

Warnings for AOT unsafe interop are incomplete best effort currently: #74630 (comment)

  • Generate warnings for unsafe interop in marshalled structs
  • Generate warnings for AOT unsafe marshallers like AsAny and LayoutClass
  • Use actual marshaller kind to produce the warning instead of the approximation at
    static bool IsComInterop(MarshalAsDescriptor? marshalInfoProvider, TypeDesc parameterType)
    {
    // This is best effort. One can likely find ways how to get COM without triggering these alarms.
    // AsAny marshalling of a struct with an object-typed field would be one, for example.
    // This logic roughly corresponds to MarshalInfo::MarshalInfo in CoreCLR,
    // not trying to handle invalid cases and distinctions that are not interesting wrt
    // "is this COM?" question.
    NativeTypeKind nativeType = NativeTypeKind.Default;
    if (marshalInfoProvider != null)
    {
    nativeType = marshalInfoProvider.Type;
    }
    if (nativeType == NativeTypeKind.IUnknown || nativeType == NativeTypeKind.IDispatch || nativeType == NativeTypeKind.Intf)
    {
    // This is COM by definition
    return true;
    }
    if (nativeType == NativeTypeKind.Default)
    {
    TypeSystemContext context = parameterType.Context;
    if (parameterType.IsPointer)
    return false;
    while (parameterType.IsParameterizedType)
    parameterType = ((ParameterizedType)parameterType).ParameterType;
    if (parameterType.IsWellKnownType(Internal.TypeSystem.WellKnownType.Array))
    {
    // System.Array marshals as IUnknown by default
    return true;
    }
    else if (parameterType.IsWellKnownType(Internal.TypeSystem.WellKnownType.String) ||
    InteropTypes.IsStringBuilder(context, parameterType))
    {
    // String and StringBuilder are special cased by interop
    return false;
    }
    if (parameterType.IsValueType)
    {
    // Value types don't marshal as COM
    return false;
    }
    else if (parameterType.IsInterface)
    {
    // Interface types marshal as COM by default
    return true;
    }
    else if (parameterType.IsDelegate || parameterType.IsWellKnownType(Internal.TypeSystem.WellKnownType.MulticastDelegate)
    || parameterType == context.GetWellKnownType(Internal.TypeSystem.WellKnownType.MulticastDelegate).BaseType)
    {
    // Delegates are special cased by interop
    return false;
    }
    else if (InteropTypes.IsCriticalHandle(context, parameterType))
    {
    // Subclasses of CriticalHandle are special cased by interop
    return false;
    }
    else if (InteropTypes.IsSafeHandle(context, parameterType))
    {
    // Subclasses of SafeHandle are special cased by interop
    return false;
    }
    else if (parameterType is MetadataType mdType && !mdType.IsSequentialLayout && !mdType.IsExplicitLayout)
    {
    // Rest of classes that don't have layout marshal as COM
    return true;
    }
    }
    return false;
    }
  • Steer people towards P/Invoke source generator by the warning text

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    No status

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions