From 7dd27789cbe9db30da0a55f7522454a3764c4d3e Mon Sep 17 00:00:00 2001 From: Jevan Saks Date: Tue, 28 Oct 2025 12:25:22 -0700 Subject: [PATCH] Fix issues in HANDLE types and other helpers when CheckForOverflowUnderflow is enabled --- src/Microsoft.Windows.CsWin32/Generator.TypeDef.cs | 2 +- src/Microsoft.Windows.CsWin32/templates/HRESULT.cs | 2 +- src/Microsoft.Windows.CsWin32/templates/NTSTATUS.cs | 4 ++-- .../templates/PInvokeClassMacros.cs | 4 ++-- test/GenerationSandbox.Tests/BasicTests.cs | 7 +++++++ .../GenerationSandbox.Tests/GenerationSandbox.Tests.csproj | 4 ++++ 6 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.Windows.CsWin32/Generator.TypeDef.cs b/src/Microsoft.Windows.CsWin32/Generator.TypeDef.cs index 5ab1a2a4..754ad689 100644 --- a/src/Microsoft.Windows.CsWin32/Generator.TypeDef.cs +++ b/src/Microsoft.Windows.CsWin32/Generator.TypeDef.cs @@ -278,7 +278,7 @@ private IEnumerable CreateCommonTypeDefMembers(Identifi yield return ConstructorDeclaration(structName.Identifier) .AddModifiers(TokenWithSpace(this.Visibility)) .AddParameterListParameters(Parameter(valueParameter.Identifier).WithType(IntPtrTypeSyntax.WithTrailingTrivia(TriviaList(Space)))) - .WithInitializer(ConstructorInitializer(SyntaxKind.ThisConstructorInitializer).AddArgumentListArguments(Argument(CastExpression(fieldType, valueParameter)))) + .WithInitializer(ConstructorInitializer(SyntaxKind.ThisConstructorInitializer).AddArgumentListArguments(Argument(UncheckedExpression(CastExpression(fieldType, valueParameter))))) .WithBody(Block()); } diff --git a/src/Microsoft.Windows.CsWin32/templates/HRESULT.cs b/src/Microsoft.Windows.CsWin32/templates/HRESULT.cs index 14d86119..4744d1d4 100644 --- a/src/Microsoft.Windows.CsWin32/templates/HRESULT.cs +++ b/src/Microsoft.Windows.CsWin32/templates/HRESULT.cs @@ -38,7 +38,7 @@ partial struct HRESULT { public static implicit operator uint(HRESULT value) => (uint)value.Value; - public static explicit operator HRESULT(uint value) => new HRESULT((int)value); + public static explicit operator HRESULT(uint value) => new HRESULT(unchecked((int)value)); [DebuggerBrowsable(DebuggerBrowsableState.Never)] internal bool Succeeded => this.Value >= 0; diff --git a/src/Microsoft.Windows.CsWin32/templates/NTSTATUS.cs b/src/Microsoft.Windows.CsWin32/templates/NTSTATUS.cs index 699266aa..1f8d20c7 100644 --- a/src/Microsoft.Windows.CsWin32/templates/NTSTATUS.cs +++ b/src/Microsoft.Windows.CsWin32/templates/NTSTATUS.cs @@ -26,9 +26,9 @@ partial struct NTSTATUS { public static implicit operator uint(NTSTATUS value) => (uint)value.Value; - public static explicit operator NTSTATUS(uint value) => new NTSTATUS((int)value); + public static explicit operator NTSTATUS(uint value) => new NTSTATUS(unchecked((int)value)); - internal Severity SeverityCode => (Severity)(((uint)this.Value & 0xc0000000) >> 30); + internal Severity SeverityCode => (Severity)unchecked(((uint)this.Value & 0xc0000000) >> 30); internal enum Severity { diff --git a/src/Microsoft.Windows.CsWin32/templates/PInvokeClassMacros.cs b/src/Microsoft.Windows.CsWin32/templates/PInvokeClassMacros.cs index 132e252f..6462f815 100644 --- a/src/Microsoft.Windows.CsWin32/templates/PInvokeClassMacros.cs +++ b/src/Microsoft.Windows.CsWin32/templates/PInvokeClassMacros.cs @@ -19,7 +19,7 @@ internal class PInvokeClassMacros /// The low word. /// The high word. /// A 32-bit unsigned integer. - internal static uint MAKELONG(ushort a, ushort b) => (uint)(a | b << 16); + internal static uint MAKELONG(ushort a, ushort b) => unchecked((uint)(a | b << 16)); /// /// Constructs a from two 16-bit values. @@ -57,5 +57,5 @@ internal class PInvokeClassMacros /// /// The 32-bit value. /// The high-order word. - internal static ushort HIWORD(uint value) => (ushort)(value >> 16); + internal static ushort HIWORD(uint value) => unchecked((ushort)(value >> 16)); } diff --git a/test/GenerationSandbox.Tests/BasicTests.cs b/test/GenerationSandbox.Tests/BasicTests.cs index 0d96d441..3e8887e0 100644 --- a/test/GenerationSandbox.Tests/BasicTests.cs +++ b/test/GenerationSandbox.Tests/BasicTests.cs @@ -200,6 +200,13 @@ public void HANDLE_OverridesEqualityOperator() Assert.False(handle5 == handle8); } + [Fact] + public void HANDLE_CanCreateFromNegative() + { + // unchecked this will throw overflow exception in .NET Core. + var handle = new HANDLE(new IntPtr(-3)); + } + [Fact] public void GetWindowText_FriendlyOverload() { diff --git a/test/GenerationSandbox.Tests/GenerationSandbox.Tests.csproj b/test/GenerationSandbox.Tests/GenerationSandbox.Tests.csproj index a50f5a1c..35a2ad40 100644 --- a/test/GenerationSandbox.Tests/GenerationSandbox.Tests.csproj +++ b/test/GenerationSandbox.Tests/GenerationSandbox.Tests.csproj @@ -5,6 +5,10 @@ + + true + +