Skip to content

Commit

Permalink
Merge pull request #1109 from microsoft/fix1081
Browse files Browse the repository at this point in the history
Fix NullReferenceException in friendly overloads of COM methods with optional pointer parameters
  • Loading branch information
AArnott authored Jan 10, 2024
2 parents 7c8e27c + dcca27d commit efd80a7
Show file tree
Hide file tree
Showing 20 changed files with 143 additions and 43 deletions.
4 changes: 2 additions & 2 deletions src/Microsoft.Windows.CsWin32/ArrayTypeHandleInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ internal record ArrayTypeHandleInfo(TypeHandleInfo ElementType, ArrayShape Shape
{
public override string ToString() => this.ToTypeSyntaxForDisplay().ToString();

internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs, CustomAttributeHandleCollection? customAttributes, ParameterAttributes parameterAttributes)
internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs, Generator.GeneratingElement forElement, CustomAttributeHandleCollection? customAttributes, ParameterAttributes parameterAttributes)
{
TypeSyntaxAndMarshaling element = this.ElementType.ToTypeSyntax(inputs, customAttributes);
TypeSyntaxAndMarshaling element = this.ElementType.ToTypeSyntax(inputs, forElement, customAttributes);
if (inputs.AllowMarshaling || inputs.IsField)
{
ArrayTypeSyntax arrayType = ArrayType(element.Type, SingletonList(ArrayRankSpecifier().AddSizes(this.Shape.Sizes.Select(size => LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(size))).ToArray<ExpressionSyntax>())));
Expand Down
12 changes: 6 additions & 6 deletions src/Microsoft.Windows.CsWin32/Generator.Com.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,10 @@ from property in methodsByMetadata.Key.GetDeclarableProperties(methodDefs, origi

MethodSignature<TypeHandleInfo> signature = methodDefinition.Method.DecodeSignature(SignatureHandleProvider.Instance, null);
CustomAttributeHandleCollection? returnTypeAttributes = methodDefinition.Generator.GetReturnTypeCustomAttributes(methodDefinition.Method);
TypeSyntax returnType = signature.ReturnType.ToTypeSyntax(typeSettings, returnTypeAttributes).Type;
TypeSyntax returnType = signature.ReturnType.ToTypeSyntax(typeSettings, GeneratingElement.InterfaceAsStructMember, returnTypeAttributes).Type;
TypeSyntax returnTypePreserveSig = returnType;

ParameterListSyntax parameterList = methodDefinition.Generator.CreateParameterList(methodDefinition.Method, signature, typeSettings);
ParameterListSyntax parameterList = methodDefinition.Generator.CreateParameterList(methodDefinition.Method, signature, typeSettings with { Generator = methodDefinition.Generator }, GeneratingElement.InterfaceAsStructMember);
ParameterListSyntax parameterListPreserveSig = parameterList; // preserve a copy that has no mutations.
bool requiresMarshaling = parameterList.Parameters.Any(p => p.AttributeLists.SelectMany(al => al.Attributes).Any(a => a.Name is IdentifierNameSyntax { Identifier.ValueText: "MarshalAs" }) || p.Modifiers.Any(SyntaxKind.RefKeyword) || p.Modifiers.Any(SyntaxKind.OutKeyword) || p.Modifiers.Any(SyntaxKind.InKeyword));
FunctionPointerParameterListSyntax funcPtrParameters = FunctionPointerParameterList()
Expand Down Expand Up @@ -596,7 +596,7 @@ static ExpressionSyntax ThisPointer(PointerTypeSyntax? typedPointer = null)
else
{
baseTypeHandle.Generator.RequestInteropType(baseTypeHandle.DefinitionHandle, context);
TypeSyntax baseTypeSyntax = new HandleTypeHandleInfo(baseTypeHandle.Reader, baseTypeHandle.DefinitionHandle).ToTypeSyntax(this.comSignatureTypeSettings, null).Type;
TypeSyntax baseTypeSyntax = new HandleTypeHandleInfo(baseTypeHandle.Reader, baseTypeHandle.DefinitionHandle).ToTypeSyntax(this.comSignatureTypeSettings, GeneratingElement.InterfaceMember, null).Type;
if (interfaceAsSubtype)
{
baseTypeSyntax = QualifiedName(
Expand Down Expand Up @@ -666,11 +666,11 @@ static ExpressionSyntax ThisPointer(PointerTypeSyntax? typedPointer = null)
MethodSignature<TypeHandleInfo> signature = methodDefinition.DecodeSignature(SignatureHandleProvider.Instance, null);

CustomAttributeHandleCollection? returnTypeAttributes = this.GetReturnTypeCustomAttributes(methodDefinition);
TypeSyntaxAndMarshaling returnTypeDetails = signature.ReturnType.ToTypeSyntax(typeSettings, returnTypeAttributes);
TypeSyntaxAndMarshaling returnTypeDetails = signature.ReturnType.ToTypeSyntax(typeSettings, GeneratingElement.InterfaceMember, returnTypeAttributes);
TypeSyntax returnType = returnTypeDetails.Type;
AttributeSyntax? returnsAttribute = MarshalAs(returnTypeDetails.MarshalAsAttribute, returnTypeDetails.NativeArrayInfo);

ParameterListSyntax? parameterList = this.CreateParameterList(methodDefinition, signature, this.comSignatureTypeSettings);
ParameterListSyntax? parameterList = this.CreateParameterList(methodDefinition, signature, this.comSignatureTypeSettings, GeneratingElement.InterfaceMember);

bool preserveSig = interfaceAsSubtype || this.UsePreserveSigForComMethod(methodDefinition, signature, actualIfaceName, methodName);
if (!preserveSig)
Expand Down Expand Up @@ -972,7 +972,7 @@ private bool TryGetPropertyAccessorInfo(MethodDefinition methodDefinition, strin

Parameter propertyTypeParameter = this.Reader.GetParameter(parameters.Skip(1).Single());
TypeHandleInfo propertyTypeInfo = signature.ParameterTypes[0];
propertyType = propertyTypeInfo.ToTypeSyntax(syntaxSettings, propertyTypeParameter.GetCustomAttributes(), propertyTypeParameter.Attributes).Type;
propertyType = propertyTypeInfo.ToTypeSyntax(syntaxSettings, GeneratingElement.Property, propertyTypeParameter.GetCustomAttributes(), propertyTypeParameter.Attributes).Type;

if (isGetter)
{
Expand Down
6 changes: 3 additions & 3 deletions src/Microsoft.Windows.CsWin32/Generator.Constant.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ private ExpressionSyntax CreateConstant(ReadOnlyMemory<char> argsAsString, TypeH
{
ArrayTypeHandleInfo { ElementType: PrimitiveTypeHandleInfo { PrimitiveTypeCode: PrimitiveTypeCode.Byte } } pointerType => this.CreateByteArrayConstant(argsAsString),
PrimitiveTypeHandleInfo primitiveType => ToExpressionSyntax(primitiveType.PrimitiveTypeCode, argsAsString),
HandleTypeHandleInfo handleType => this.CreateConstant(argsAsString, targetType.ToTypeSyntax(this.fieldTypeSettings, null).Type, (TypeReferenceHandle)handleType.Handle),
HandleTypeHandleInfo handleType => this.CreateConstant(argsAsString, targetType.ToTypeSyntax(this.fieldTypeSettings, GeneratingElement.Constant, null).Type, (TypeReferenceHandle)handleType.Handle),
_ => throw new GenerationFailedException($"Unsupported constant type: {targetType}"),
};
}
Expand Down Expand Up @@ -334,7 +334,7 @@ private ExpressionSyntax CreateConstant(CustomAttribute constantAttribute, TypeH
CustomAttributeValue<TypeSyntax> args = constantAttribute.DecodeValue(CustomAttributeTypeProvider.Instance);
return this.CreateConstant(
((string)args.FixedArguments[0].Value!).AsMemory(),
targetType.ToTypeSyntax(this.fieldTypeSettings, null).Type,
targetType.ToTypeSyntax(this.fieldTypeSettings, GeneratingElement.Constant, null).Type,
targetTypeRefHandle);
}

Expand All @@ -345,7 +345,7 @@ private FieldDeclarationSyntax DeclareConstant(FieldDefinition fieldDef)
{
TypeHandleInfo fieldTypeInfo = fieldDef.DecodeSignature(SignatureHandleProvider.Instance, null) with { IsConstantField = true };
CustomAttributeHandleCollection customAttributes = fieldDef.GetCustomAttributes();
TypeSyntaxAndMarshaling fieldType = fieldTypeInfo.ToTypeSyntax(this.fieldTypeSettings, customAttributes);
TypeSyntaxAndMarshaling fieldType = fieldTypeInfo.ToTypeSyntax(this.fieldTypeSettings, GeneratingElement.Constant, customAttributes);
ExpressionSyntax value =
fieldDef.GetDefaultValue() is { IsNil: false } constantHandle ? ToExpressionSyntax(this.Reader, constantHandle) :
this.FindInteropDecorativeAttribute(customAttributes, nameof(GuidAttribute)) is CustomAttribute guidAttribute ? GuidValue(guidAttribute) :
Expand Down
6 changes: 3 additions & 3 deletions src/Microsoft.Windows.CsWin32/Generator.Delegate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ private DelegateDeclarationSyntax DeclareDelegate(TypeDefinition typeDef)
}

this.GetSignatureForDelegate(typeDef, out MethodDefinition invokeMethodDef, out MethodSignature<TypeHandleInfo> signature, out CustomAttributeHandleCollection? returnTypeAttributes);
TypeSyntaxAndMarshaling returnValue = signature.ReturnType.ToTypeSyntax(typeSettings, returnTypeAttributes);
TypeSyntaxAndMarshaling returnValue = signature.ReturnType.ToTypeSyntax(typeSettings, GeneratingElement.Delegate, returnTypeAttributes);

DelegateDeclarationSyntax result = DelegateDeclaration(returnValue.Type, Identifier(name))
.WithParameterList(FixTrivia(this.CreateParameterList(invokeMethodDef, signature, typeSettings)))
.WithParameterList(FixTrivia(this.CreateParameterList(invokeMethodDef, signature, typeSettings, GeneratingElement.Delegate)))
.AddModifiers(TokenWithSpace(this.Visibility), TokenWithSpace(SyntaxKind.UnsafeKeyword));
result = returnValue.AddReturnMarshalAs(result);

Expand Down Expand Up @@ -149,6 +149,6 @@ private FunctionPointerParameterSyntax TranslateDelegateToFunctionPointer(TypeHa
return FunctionPointerParameter(delegateTypeDef.Generator.FunctionPointer(delegateTypeDef.Definition));
}

return FunctionPointerParameter(parameterTypeInfo.ToTypeSyntax(this.functionPointerTypeSettings, customAttributeHandles).GetUnmarshaledType());
return FunctionPointerParameter(parameterTypeInfo.ToTypeSyntax(this.functionPointerTypeSettings, GeneratingElement.FunctionPointer, customAttributeHandles).GetUnmarshaledType());
}
}
2 changes: 1 addition & 1 deletion src/Microsoft.Windows.CsWin32/Generator.Enum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ private EnumDeclarationSyntax DeclareEnum(TypeDefinition typeDef)
ConstantHandle valueHandle = fieldDef.GetDefaultValue();
if (valueHandle.IsNil)
{
enumBaseType = fieldDef.DecodeSignature(SignatureHandleProvider.Instance, null).ToTypeSyntax(this.enumTypeSettings, null).Type;
enumBaseType = fieldDef.DecodeSignature(SignatureHandleProvider.Instance, null).ToTypeSyntax(this.enumTypeSettings, GeneratingElement.EnumValue, null).Type;
continue;
}

Expand Down
6 changes: 3 additions & 3 deletions src/Microsoft.Windows.CsWin32/Generator.Extern.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ private void DeclareExternMethod(MethodDefinitionHandle methodDefinitionHandle)
bool requiresUnicodeCharSet = signature.ParameterTypes.Any(p => p is PrimitiveTypeHandleInfo { PrimitiveTypeCode: PrimitiveTypeCode.Char });

CustomAttributeHandleCollection? returnTypeAttributes = this.GetReturnTypeCustomAttributes(methodDefinition);
TypeSyntaxAndMarshaling returnType = signature.ReturnType.ToTypeSyntax(typeSettings, returnTypeAttributes, ParameterAttributes.Out);
TypeSyntaxAndMarshaling returnType = signature.ReturnType.ToTypeSyntax(typeSettings, GeneratingElement.ExternMethod, returnTypeAttributes, ParameterAttributes.Out);

// Search for any enum substitutions.
TypeSyntax? returnTypeEnumName = this.FindAssociatedEnum(returnTypeAttributes);
Expand Down Expand Up @@ -231,7 +231,7 @@ AttributeListSyntax CreateDllImportAttributeList() => AttributeList()
explicitInterfaceSpecifier: null!,
SafeIdentifier(methodName),
null!,
this.CreateParameterList(methodDefinition, signature, typeSettings),
this.CreateParameterList(methodDefinition, signature, typeSettings, GeneratingElement.ExternMethod),
List<TypeParameterConstraintClauseSyntax>(),
body: null!,
TokenWithLineFeed(SyntaxKind.SemicolonToken));
Expand Down Expand Up @@ -259,7 +259,7 @@ AttributeListSyntax CreateDllImportAttributeList() => AttributeList()
{
string ns = this.GetMethodNamespace(methodDefinition);
NameSyntax nsSyntax = ParseName(ReplaceCommonNamespaceWithAlias(this, ns));
ParameterListSyntax exposedParameterList = this.CreateParameterList(methodDefinition, signature, typeSettings);
ParameterListSyntax exposedParameterList = this.CreateParameterList(methodDefinition, signature, typeSettings, GeneratingElement.ExternMethod);
static SyntaxToken RefInOutKeyword(ParameterSyntax p) =>
p.Modifiers.Any(SyntaxKind.OutKeyword) ? TokenWithSpace(SyntaxKind.OutKeyword) :
p.Modifiers.Any(SyntaxKind.RefKeyword) ? TokenWithSpace(SyntaxKind.RefKeyword) :
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverloads(MethodDefi
.WithModifiers(TokenList(TokenWithSpace(SyntaxKind.OutKeyword)));

// HANDLE SomeLocal;
leadingStatements.Add(LocalDeclarationStatement(VariableDeclaration(pointedElementInfo.ToTypeSyntax(parameterTypeSyntaxSettings, null).Type).AddVariables(
leadingStatements.Add(LocalDeclarationStatement(VariableDeclaration(pointedElementInfo.ToTypeSyntax(parameterTypeSyntaxSettings, GeneratingElement.FriendlyOverload, null).Type).AddVariables(
VariableDeclarator(typeDefHandleName.Identifier))));

// Argument: &SomeLocal
Expand Down
6 changes: 3 additions & 3 deletions src/Microsoft.Windows.CsWin32/Generator.Handle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public partial class Generator

MethodSignature<TypeHandleInfo> releaseMethodSignature = releaseMethodDef.DecodeSignature(SignatureHandleProvider.Instance, null);
TypeHandleInfo releaseMethodParameterTypeHandleInfo = releaseMethodSignature.ParameterTypes[0];
TypeSyntaxAndMarshaling releaseMethodParameterType = releaseMethodParameterTypeHandleInfo.ToTypeSyntax(this.externSignatureTypeSettings, default);
TypeSyntaxAndMarshaling releaseMethodParameterType = releaseMethodParameterTypeHandleInfo.ToTypeSyntax(this.externSignatureTypeSettings, GeneratingElement.HelperClassMember, default);

// If the release method takes more than one parameter, we can't generate a SafeHandle for it.
if (releaseMethodSignature.RequiredParameterCount != 1)
Expand Down Expand Up @@ -80,7 +80,7 @@ public partial class Generator
IntPtr preferredInvalidValue = GetPreferredInvalidHandleValue(invalidHandleValues, new IntPtr(-1));

CustomAttributeHandleCollection? atts = this.GetReturnTypeCustomAttributes(releaseMethodDef);
TypeSyntaxAndMarshaling releaseMethodReturnType = releaseMethodSignature.ReturnType.ToTypeSyntax(this.externSignatureTypeSettings, atts);
TypeSyntaxAndMarshaling releaseMethodReturnType = releaseMethodSignature.ReturnType.ToTypeSyntax(this.externSignatureTypeSettings, GeneratingElement.HelperClassMember, atts);

this.TryGetRenamedMethod(releaseMethod, out string? renamedReleaseMethod);

Expand Down Expand Up @@ -134,7 +134,7 @@ public partial class Generator
bool implicitConversion = typeDefStructFieldType is PrimitiveTypeHandleInfo { PrimitiveTypeCode: PrimitiveTypeCode.IntPtr } or PointerTypeHandleInfo;
ArgumentSyntax releaseHandleArgument = Argument(CastExpression(
releaseMethodParameterType.Type,
implicitConversion ? thisHandle : CheckedExpression(CastExpression(typeDefStructFieldType!.ToTypeSyntax(this.fieldTypeSettings, null).Type, CastExpression(IdentifierName("nint"), thisHandle)))));
implicitConversion ? thisHandle : CheckedExpression(CastExpression(typeDefStructFieldType!.ToTypeSyntax(this.fieldTypeSettings, GeneratingElement.HelperClassMember, null).Type, CastExpression(IdentifierName("nint"), thisHandle)))));

// protected override bool ReleaseHandle() => ReleaseMethod((struct)this.handle);
// Special case release functions based on their return type as follows: (https://github.com/microsoft/win32metadata/issues/25)
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.Windows.CsWin32/Generator.InlineArrays.cs
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,7 @@ StatementSyntax ClearSlice(ExpressionSyntax span) =>
}
else
{
qualifiedElementType = fieldTypeHandleInfo.ToTypeSyntax(this.extensionMethodSignatureTypeSettings, customAttributes).Type switch
qualifiedElementType = fieldTypeHandleInfo.ToTypeSyntax(this.extensionMethodSignatureTypeSettings, GeneratingElement.Other, customAttributes).Type switch
{
ArrayTypeSyntax at => at.ElementType,
PointerTypeSyntax ptrType => ptrType.ElementType,
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.Windows.CsWin32/Generator.MetadataHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ private bool IsManagedType(TypeDefinitionHandle typeDefinitionHandle)
}
catch (Exception ex)
{
throw new GenerationFailedException($"Unable to determine if {new HandleTypeHandleInfo(this.Reader, typeDefinitionHandle).ToTypeSyntax(this.errorMessageTypeSettings, null)} is a managed type.", ex);
throw new GenerationFailedException($"Unable to determine if {new HandleTypeHandleInfo(this.Reader, typeDefinitionHandle).ToTypeSyntax(this.errorMessageTypeSettings, GeneratingElement.Other, null)} is a managed type.", ex);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Microsoft.Windows.CsWin32/Generator.Struct.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private StructDeclarationSyntax DeclareStruct(TypeDefinitionHandle typeDefHandle
}
}

TypeSyntaxAndMarshaling fieldTypeSyntax = fieldTypeInfo.ToTypeSyntax(thisFieldTypeSettings, fieldAttributes);
TypeSyntaxAndMarshaling fieldTypeSyntax = fieldTypeInfo.ToTypeSyntax(thisFieldTypeSettings, GeneratingElement.StructMember, fieldAttributes);
(TypeSyntax FieldType, SyntaxList<MemberDeclarationSyntax> AdditionalMembers, AttributeSyntax? MarshalAsAttribute) fieldInfo = this.ReinterpretFieldType(fieldDef, fieldTypeSyntax.Type, fieldAttributes, context);
additionalMembers = additionalMembers.AddRange(fieldInfo.AdditionalMembers);

Expand Down Expand Up @@ -195,7 +195,7 @@ private StructDeclarationSyntax DeclareStruct(TypeDefinitionHandle typeDefHandle
// then we must type it as an array.
if (context.AllowMarshaling && fieldTypeHandleInfo is PointerTypeHandleInfo ptr3 && this.IsInterface(ptr3.ElementType))
{
return (ArrayType(ptr3.ElementType.ToTypeSyntax(typeSettings, null).Type).AddRankSpecifiers(ArrayRankSpecifier()), default(SyntaxList<MemberDeclarationSyntax>), marshalAs);
return (ArrayType(ptr3.ElementType.ToTypeSyntax(typeSettings, GeneratingElement.Field, null).Type).AddRankSpecifiers(ArrayRankSpecifier()), default(SyntaxList<MemberDeclarationSyntax>), marshalAs);
}

return (originalType, default(SyntaxList<MemberDeclarationSyntax>), marshalAs);
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.Windows.CsWin32/Generator.TypeDef.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ private StructDeclarationSyntax DeclareTypeDefStruct(TypeDefinition typeDef, Typ
VariableDeclaratorSyntax fieldDeclarator = VariableDeclarator(fieldIdentifierName.Identifier);
CustomAttributeHandleCollection fieldAttributes = fieldDef.GetCustomAttributes();
TypeHandleInfo fieldTypeInfo = fieldDef.DecodeSignature(SignatureHandleProvider.Instance, null);
TypeSyntaxAndMarshaling fieldType = fieldTypeInfo.ToTypeSyntax(typeSettings, fieldAttributes);
TypeSyntaxAndMarshaling fieldType = fieldTypeInfo.ToTypeSyntax(typeSettings, GeneratingElement.Field, fieldAttributes);
(TypeSyntax FieldType, SyntaxList<MemberDeclarationSyntax> AdditionalMembers, AttributeSyntax? _) fieldInfo =
this.ReinterpretFieldType(fieldDef, fieldType.Type, fieldAttributes, this.DefaultContext);
SyntaxList<MemberDeclarationSyntax> members = List<MemberDeclarationSyntax>();
Expand Down
Loading

0 comments on commit efd80a7

Please sign in to comment.