Skip to content

Commit 25df5f1

Browse files
authored
Merge pull request #760 from microsoft/fix755
Use documented invalid handles when SafeHandle is null
2 parents 874445e + be494bf commit 25df5f1

3 files changed

Lines changed: 37 additions & 9 deletions

File tree

src/Microsoft.Windows.CsWin32/FastSyntaxFactory.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ internal static ForStatementSyntax ForStatement(VariableDeclarationSyntax? decla
135135

136136
internal static ThrowStatementSyntax ThrowStatement(ExpressionSyntax expression) => SyntaxFactory.ThrowStatement(Token(TriviaList(), SyntaxKind.ThrowKeyword, TriviaList(Space)), expression, Semicolon);
137137

138+
internal static ThrowExpressionSyntax ThrowExpression(ExpressionSyntax expression) => SyntaxFactory.ThrowExpression(Token(TriviaList(), SyntaxKind.ThrowKeyword, TriviaList(Space)), expression);
139+
140+
internal static ExpressionSyntax NameOfExpression(IdentifierNameSyntax identifierName) => SyntaxFactory.InvocationExpression(IdentifierName("nameof"), ArgumentList(SingletonSeparatedList(Argument(identifierName))));
141+
138142
internal static ReturnStatementSyntax ReturnStatement(ExpressionSyntax? expression) => SyntaxFactory.ReturnStatement(Token(TriviaList(), SyntaxKind.ReturnKeyword, TriviaList(Space)), expression!, Semicolon);
139143

140144
internal static DelegateDeclarationSyntax DelegateDeclaration(TypeSyntax returnType, SyntaxToken identifier) => SyntaxFactory.DelegateDeclaration(default(SyntaxList<AttributeListSyntax>), default(SyntaxTokenList), Token(TriviaList(), SyntaxKind.DelegateKeyword, TriviaList(Space)), returnType.WithTrailingTrivia(TriviaList(Space)), identifier, null, ParameterList(), default, Semicolon);

src/Microsoft.Windows.CsWin32/Generator.cs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ public class Generator : IDisposable
9090
private const string SystemRuntimeInteropServices = "System.Runtime.InteropServices";
9191
private const string NativeTypedefAttribute = "NativeTypedefAttribute";
9292
private const string InvalidHandleValueAttribute = "InvalidHandleValueAttribute";
93+
private const string CanReturnMultipleSuccessValuesAttribute = "CanReturnMultipleSuccessValuesAttribute";
94+
private const string CanReturnErrorsAsSuccessAttribute = "CanReturnErrorsAsSuccessAttribute";
9395
private const string SimpleFileNameAnnotation = "SimpleFileName";
9496
private const string NamespaceContainerAnnotation = "NamespaceContainer";
9597
private const string OriginalDelegateAnnotation = "OriginalDelegate";
@@ -1378,9 +1380,9 @@ nsContents.Key is object
13781380
nativeArrayInfo?.CountParamIndex.HasValue is true ? LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(nativeArrayInfo.Value.CountParamIndex.Value)) : null);
13791381
}
13801382

1381-
internal static TypeSyntax MakeSpanOfT(TypeSyntax typeArgument) => GenericName("Span").AddTypeArgumentListArguments(typeArgument);
1383+
internal static TypeSyntax MakeSpanOfT(TypeSyntax typeArgument) => GenericName(nameof(Span<int>)).AddTypeArgumentListArguments(typeArgument);
13821384

1383-
internal static TypeSyntax MakeReadOnlySpanOfT(TypeSyntax typeArgument) => GenericName("ReadOnlySpan").AddTypeArgumentListArguments(typeArgument);
1385+
internal static TypeSyntax MakeReadOnlySpanOfT(TypeSyntax typeArgument) => GenericName(nameof(ReadOnlySpan<int>)).AddTypeArgumentListArguments(typeArgument);
13841386

13851387
/// <summary>
13861388
/// Checks whether an exception was originally thrown because of a target platform incompatibility.
@@ -1754,7 +1756,7 @@ internal void RequestMacro(MethodDeclarationSyntax macro)
17541756
// Collect all the known invalid values for this handle.
17551757
// If no invalid values are given (e.g. BSTR), we'll just assume 0 is invalid.
17561758
HashSet<IntPtr> invalidHandleValues = this.GetInvalidHandleValues(((HandleTypeHandleInfo)releaseMethodParameterTypeHandleInfo).Handle);
1757-
long preferredInvalidValue = invalidHandleValues.Contains(new IntPtr(-1)) ? -1 : invalidHandleValues.FirstOrDefault().ToInt64();
1759+
IntPtr preferredInvalidValue = GetPreferredInvalidHandleValue(invalidHandleValues);
17581760

17591761
CustomAttributeHandleCollection? atts = this.GetReturnTypeCustomAttributes(releaseMethodDef);
17601762
TypeSyntaxAndMarshaling releaseMethodReturnType = releaseMethodSignature.ReturnType.ToTypeSyntax(this.externSignatureTypeSettings, atts);
@@ -1765,7 +1767,7 @@ internal void RequestMacro(MethodDeclarationSyntax macro)
17651767

17661768
MemberAccessExpressionSyntax thisHandle = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName("handle"));
17671769
ExpressionSyntax intptrZero = DefaultExpression(IntPtrTypeSyntax);
1768-
ExpressionSyntax invalidHandleIntPtr = ObjectCreationExpression(IntPtrTypeSyntax).AddArgumentListArguments(Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(preferredInvalidValue))));
1770+
ExpressionSyntax invalidHandleIntPtr = IntPtrExpr(preferredInvalidValue);
17691771

17701772
// private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
17711773
IdentifierNameSyntax invalidValueFieldName = IdentifierName("INVALID_HANDLE_VALUE");
@@ -2247,6 +2249,8 @@ protected virtual void Dispose(bool disposing)
22472249

22482250
private static SyntaxToken TokenWithLineFeed(SyntaxKind syntaxKind) => SyntaxFactory.Token(TriviaList(), syntaxKind, TriviaList(LineFeed));
22492251

2252+
private static IntPtr GetPreferredInvalidHandleValue(HashSet<IntPtr> invalidHandleValues) => invalidHandleValues.Contains(new IntPtr(-1)) ? new IntPtr(-1) : invalidHandleValues.FirstOrDefault();
2253+
22502254
private static bool RequiresUnsafe(TypeSyntax? typeSyntax) => typeSyntax is PointerTypeSyntax || typeSyntax is FunctionPointerTypeSyntax;
22512255

22522256
private static string GetClassNameForModule(string moduleName) =>
@@ -2620,6 +2624,9 @@ private static Guid DecodeGuidFromAttribute(CustomAttribute guidAttribute)
26202624

26212625
private static bool IsHresult(TypeHandleInfo? typeHandleInfo) => typeHandleInfo is HandleTypeHandleInfo handleInfo && handleInfo.IsType("HRESULT");
26222626

2627+
private static ExpressionSyntax IntPtrExpr(IntPtr value) => ObjectCreationExpression(IntPtrTypeSyntax).AddArgumentListArguments(
2628+
Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(value.ToInt64()))));
2629+
26232630
private T AddApiDocumentation<T>(string api, T memberDeclaration)
26242631
where T : MemberDeclarationSyntax
26252632
{
@@ -3784,8 +3791,8 @@ StatementSyntax ThrowOnHRFailure(ExpressionSyntax hrExpression) => ExpressionSta
37843791
bool preserveSig = interfaceAsSubtype
37853792
|| !IsHresult(signature.ReturnType)
37863793
|| (methodDefinition.ImplAttributes & MethodImplAttributes.PreserveSig) == MethodImplAttributes.PreserveSig
3787-
|| this.FindInteropDecorativeAttribute(methodDefinition.GetCustomAttributes(), "CanReturnMultipleSuccessValuesAttribute") is not null
3788-
|| this.FindInteropDecorativeAttribute(methodDefinition.GetCustomAttributes(), "CanReturnErrorsAsSuccessAttribute") is not null
3794+
|| this.FindInteropDecorativeAttribute(methodDefinition.GetCustomAttributes(), CanReturnMultipleSuccessValuesAttribute) is not null
3795+
|| this.FindInteropDecorativeAttribute(methodDefinition.GetCustomAttributes(), CanReturnErrorsAsSuccessAttribute) is not null
37893796
|| this.options.ComInterop.PreserveSigMethods.Contains($"{ifaceName}.{methodName}")
37903797
|| this.options.ComInterop.PreserveSigMethods.Contains(ifaceName.ToString());
37913798

@@ -4715,6 +4722,22 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverloads(MethodDefi
47154722
leadingStatements.Add(LocalDeclarationStatement(VariableDeclaration(externParam.Type).AddVariables(
47164723
VariableDeclarator(typeDefHandleName.Identifier))));
47174724

4725+
// throw new ArgumentNullException(nameof(hTemplateFile));
4726+
StatementSyntax nullHandleStatement = ThrowStatement(ObjectCreationExpression(IdentifierName(nameof(ArgumentNullException))).WithArgumentList(ArgumentList().AddArguments(Argument(NameOfExpression(IdentifierName(externParam.Identifier.ValueText))))));
4727+
if (isOptional)
4728+
{
4729+
HashSet<IntPtr> invalidValues = this.GetInvalidHandleValues(parameterHandleTypeInfo.Handle);
4730+
if (invalidValues.Count > 0)
4731+
{
4732+
// (HANDLE)new IntPtr(-1);
4733+
IntPtr invalidValue = GetPreferredInvalidHandleValue(invalidValues);
4734+
ExpressionSyntax invalidExpression = CastExpression(externParam.Type, IntPtrExpr(invalidValue));
4735+
4736+
// hTemplateFileLocal = invalid-handle-value;
4737+
nullHandleStatement = ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, typeDefHandleName, invalidExpression));
4738+
}
4739+
}
4740+
47184741
// if (hTemplateFile is object)
47194742
leadingStatements.Add(IfStatement(
47204743
BinaryExpression(SyntaxKind.IsExpression, origName, PredefinedType(Token(SyntaxKind.ObjectKeyword))),
@@ -4732,7 +4755,7 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverloads(MethodDefi
47324755
InvocationExpression(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, origName, IdentifierName(nameof(SafeHandle.DangerousGetHandle))), ArgumentList())))
47334756
.WithOperatorToken(TokenWithSpaces(SyntaxKind.EqualsToken)))),
47344757
//// else hTemplateFileLocal = default;
4735-
ElseClause(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, typeDefHandleName, DefaultExpression(externParam.Type.WithoutTrailingTrivia())).WithOperatorToken(TokenWithSpaces(SyntaxKind.EqualsToken))))));
4758+
ElseClause(nullHandleStatement)));
47364759

47374760
// if (hTemplateFileAddRef)
47384761
// hTemplateFile.DangerousRelease();
@@ -5753,7 +5776,7 @@ InvocationExpressionSyntax SliceAtLengthToString(ExpressionSyntax readOnlySpan)
57535776
BinaryExpression(SyntaxKind.LessThanExpression, lengthParameterName, LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0))),
57545777
BinaryExpression(SyntaxKind.GreaterThanExpression, lengthParameterName, lengthConstant)),
57555778
ThrowStatement(ObjectCreationExpression(IdentifierName(nameof(ArgumentOutOfRangeException))).AddArgumentListArguments(
5756-
Argument(InvocationExpression(IdentifierName("nameof"), ArgumentList().AddArguments(Argument(lengthParameterName)))),
5779+
Argument(NameOfExpression(lengthParameterName)),
57575780
Argument(lengthParameterName),
57585781
Argument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal("Length must be between 0 and the fixed array length, inclusive.")))))),
57595782
FixedBlock(

test/Microsoft.Windows.CsWin32.Tests/GeneratorTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ public void InterestingAPIs(
297297
"PZZWSTR",
298298
"PCZZSTR",
299299
"PCZZWSTR",
300+
"NCryptImportKey", // friendly overload takes SafeHandle backed by a UIntPtr instead of IntPtr
300301
"IUIAutomation", // non-preservesig retval COM method with a array size index parameter
301302
"IHTMLWindow2", // contains properties named with C# reserved keywords
302303
"CreateFile", // built-in SafeHandle use
@@ -2653,7 +2654,7 @@ internal static unsafe Microsoft.Win32.SafeHandles.SafeFileHandle CreateFile(str
26532654
hTemplateFileLocal = (winmdroot.Foundation.HANDLE)hTemplateFile.DangerousGetHandle();
26542655
}}
26552656
else
2656-
hTemplateFileLocal = default(winmdroot.Foundation.HANDLE);
2657+
hTemplateFileLocal= (winmdroot.Foundation.HANDLE )new IntPtr(-1L);
26572658
winmdroot.Foundation.HANDLE __result = PInvoke.CreateFile(lpFileNameLocal, dwDesiredAccess, dwShareMode, lpSecurityAttributes.HasValue ? &lpSecurityAttributesLocal : null, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFileLocal);
26582659
return new Microsoft.Win32.SafeHandles.SafeFileHandle(__result, ownsHandle: true);
26592660
}}

0 commit comments

Comments
 (0)