Fix NaN regression in double parameter validation#11731
Open
wnvko-msft wants to merge 3 commits into
Open
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a .NET 9 regression in WPF where double-typed parameters/properties began rejecting NaN due to ArgumentOutOfRangeException.ThrowIfNegative* using floating-point sign-bit semantics that differ from the historical value < 0 checks. It restores the pre-.NET 9 validation behavior (notably allowing NaN where it previously flowed through), reintroduces the prior localized resource strings used by WPF’s custom exceptions, and adds targeted unit tests to prevent regressions.
Changes:
- Revert
doublevalidation fromThrowIfNegative*helpers back to manual comparisons (e.g.,< 0,<= 0) to preserve historicalNaNbehavior. - Restore WPF resource strings (
ParameterCannotBeNegative,ParameterMustBeBetween,ParameterMustBeGreaterThanZero) and corresponding XLF entries. - Add new unit tests validating
NaNacceptance and negative-value rejection forFormattedTextandD3DImage.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/System/Windows/Media/FormattedText.Tests.cs | Adds unit tests for FormattedText.LineHeight / MaxTextWidth NaN/zero acceptance and negative rejection. |
| src/Microsoft.DotNet.Wpf/tests/UnitTests/PresentationCore.Tests/System/Windows/Interop/D3DImage.Tests.cs | Adds unit tests ensuring D3DImage constructor accepts NaN DPI and rejects negative DPI. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/textformatting/TextCharacters.cs | Restores manual validation for FontRenderingEmSize to avoid NaN being treated as negative/zero by throw helpers. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/FormattedText.cs | Restores manual double validation for ValidateFontSize, LineHeight, and MaxTextWidth to preserve NaN behavior. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/D3DImage.cs | Restores manual validation for DPI parameters to preserve NaN behavior. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/Resources/Strings.resx | Reintroduces removed resource strings used for validation error messages. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/TextFormatting/TextFormatterImp.cs | Restores manual range checks for FontRenderingEmSize and DefaultIncrementalTab with WPF resource-based messages. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/Resources/xlf/Strings.cs.xlf | Restores XLF entries for reintroduced resource strings. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/Resources/xlf/Strings.de.xlf | Restores XLF entries for reintroduced resource strings. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/Resources/xlf/Strings.es.xlf | Restores XLF entries for reintroduced resource strings. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/Resources/xlf/Strings.fr.xlf | Restores XLF entries for reintroduced resource strings. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/Resources/xlf/Strings.it.xlf | Restores XLF entries for reintroduced resource strings. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/Resources/xlf/Strings.ja.xlf | Restores XLF entries for reintroduced resource strings. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/Resources/xlf/Strings.ko.xlf | Restores XLF entries for reintroduced resource strings. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/Resources/xlf/Strings.pl.xlf | Restores XLF entries for reintroduced resource strings. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/Resources/xlf/Strings.pt-BR.xlf | Restores XLF entries for reintroduced resource strings. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/Resources/xlf/Strings.ru.xlf | Restores XLF entries for reintroduced resource strings. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/Resources/xlf/Strings.tr.xlf | Restores XLF entries for reintroduced resource strings. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/Resources/xlf/Strings.zh-Hans.xlf | Restores XLF entries for reintroduced resource strings. |
| src/Microsoft.DotNet.Wpf/src/PresentationCore/Resources/xlf/Strings.zh-Hant.xlf | Restores XLF entries for reintroduced resource strings. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #11317
Description
Reverts
ArgumentOutOfRangeException.ThrowIfNegative/ThrowIfNegativeOrZerousage ondoubleparameters introduced in PR #8408. TheThrowIfNegativehelper internally usesdouble.IsNegative()which returnstrueforNaN(becauseNaNhas the sign bit set), while the originalvalue < 0check returnsfalseper IEEE 754 semantics. This caused properties likeFormattedText.LineHeightto rejectNaNvalues that were previously valid (e.g., the defaultTextBox.LineHeightisNaN).Affected files:
FormattedText.cs-ValidateFontSize,LineHeightsetter,MaxTextWidthsetterD3DImage.cs-dpiX,dpiYconstructor parametersTextFormatterImp.cs-FontRenderingEmSize,DefaultIncrementalTabvalidationAlso restores removed resource strings (
ParameterCannotBeNegative,ParameterMustBeBetween,ParameterMustBeGreaterThanZero) and their xlf translation entries.Customer Impact
Applications that pass
NaNto double properties (most commonlyFormattedText.LineHeight = textBox.LineHeightwhere the default isNaN) now throwArgumentOutOfRangeExceptionunexpectedly. This breaks existing code that worked in .NET Framework and up to .NET 8.Regression
Yes. This is a regression introduced in .NET 9 by PR #8408. The behavior worked correctly in .NET Framework and all versions through .NET 8.
Testing
Added unit tests in PresentationCore.Tests covering the NaN regression:
FormattedTextTests: VerifiesLineHeightandMaxTextWidthacceptdouble.NaNand0.0without throwing, while negative values still throwArgumentOutOfRangeException.D3DImageTests: Verifies constructor acceptsdouble.NaNfor DPI parameters without throwing, while negative values still throwArgumentOutOfRangeException.Risk
Low. This is a targeted revert of the specific
ThrowIfNegativecalls ondoubleparameters back to the original manual comparison pattern. Integer-parameter usages ofThrowIfNegative(which have noNaNconcern) are left unchanged. The fix restores the exact validation semantics from .NET 8 and earlier.Microsoft Reviewers: Open in CodeFlow