Skip to content

Conversation

@Lamparter
Copy link

@Lamparter Lamparter commented Dec 1, 2024

Fixes #366

PR Type: Bugfix


This PR fixes an issue where DWM crashes if the arguments for both min and max of the range selector control are equal.

What is the current behavior?

When the Maximum and Minimum arguments of RangeSelector are equal, DWM crashes. This can be reproduced by even the Toolkit gallery app.

What is the new behavior?

If the max and min args of the range selector are equal, an exception will be thrown.

PR Checklist

Please check if your PR fulfills the following requirements:

  • Created a feature/dev branch in your fork (vs. submitting directly from a commit on main)
  • Based off latest main branch of toolkit
  • Tested code with current supported SDKs
  • Contains NO breaking changes

@sylveon
Copy link

sylveon commented Dec 1, 2024

Should probably change the gallery app to prevent this as well (with the fix, gallery app would just crash)

@Arlodotexe
Copy link
Member

Arlodotexe commented Dec 1, 2024

Should probably change the gallery app to prevent this as well (with the fix, gallery app would just crash)

The same would happen in any app. The issue is in the RangeSelector control, it's crashing because it threw an unhandled exception. A fix in the component should be enough.

@Lamparter
Copy link
Author

Lamparter commented Dec 1, 2024

But don't you need to handle the exception in the WCT gallery app?

That's what I meant in my message in the dev-chat channel in uwpc

@Arlodotexe
Copy link
Member

@michael-hawker There seems to be some undefined behavior here. Should the control simply ignore when Min == Max, should it prevent that tick, or something else?

@michael-hawker
Copy link
Member

We should pattern off Slider's behavior here for what we should do. In the base case there, setting min/max to the same value is allowed, and the value is just locked to those values as well:

image

So, I think the best expected behavior is the same here; we should honor that same underlying contract.

Therefore, we should understand what's not working in this scenario to enable that vs. just throwing a different exception.

This would also be worth doing anyway, as we should root-cause the underlying issue; as we should file a platform bug around the DWM crash, as that shouldn't happen regardless. (I wonder if this repros on WinUI 3 as well...)

@Lamparter is this still something you could/would be willing to help us with?

@Lamparter
Copy link
Author

Sure!

@michael-hawker
Copy link
Member

@Lamparter thanks! Let us know if you need any assistance and how we can help support you.

Once we understand the root cause of what's causing the underlying crash, we can open/raise a platform issue on the WinUI repo too with a minimal repro without the toolkit maybe.

Then, we can hopefully just find a good workaround in our toolkit code here to prevent that scenario from occurring when the edge case bounds are setup, and add a test or two to help us ensure we don't regress in the future.

@Arlodotexe Arlodotexe changed the title Fix: Throw exception if RangeSelector min and max args are equal Fix: Handle if RangeSelector min and max args are equal Dec 12, 2025
…where Maximum values less than Minimum would erroneously overwrite Minimum
@Arlodotexe
Copy link
Member

Arlodotexe commented Dec 13, 2025

I traced through the lineage of this component to find the reason why the += Epsilon exists throughout the code:

This exact line doesn't serve the specific feature implemented in that original commit, so presumably the += Epsilon bits are "other bug fixes".

Challenging this, I removed the Epsilon variable entirely and allowed Maximum to be equal to Minimum to see where the component would break.

Both UWP and Wasdk have this issue now too, not sure if pre-existing but it's related:

Recording.2025-12-12.180606.mp4

The issue here is that lowering Maximum to be less than Minimum then raising Maximum reveals that Minimum was improperly overwritten with the new Maximum value. The cause is twofold: VerifyValues() is only called in OnApplyTemplate, and the logic of VerifyValues() is duplicated in the MinimumChangedCallback and MaximumChangedCallback.

Pushed in c28bc00, these errors are all fixed.

New behavior in Wasdk:

Recording.2025-12-12.191906.mp4

New behavior in UWP:

Recording.2025-12-12.192421.mp4

@michael-hawker If this looks good to you, we can close PR

…ly overwrite minimum, cleaned up duplicate logic

Amends c28bc00
@michael-hawker
Copy link
Member

Looks like the tests are failing across a number of scenarios. Question is if they were coded against the observed behavior or defining the expected behavior. So needs to be investigated.

Minor other comment would be if we can still show the thumb like slider in this edge case: #576 (comment)

…ch other

When RangeStart is set to a value that snaps beyond RangeEnd (or vice versa), the control now snaps to the nearest valid step that respects the constraint, rather than being clamped to a non-step value.

Problem: With StepFrequency=40, RangeStart=40, RangeEnd=60, setting RangeStart=60 would:
1. Snap 60 → 80 (nearest step via Math.Round)
2. VerifyValues() clamps 80 → 60 (to not exceed RangeEnd)
3. Result: RangeStart=60, which is not on a valid step (valid steps: 0, 40, 80, 100)

Solution: RangeMinToStepFrequency and RangeMaxToStepFrequency now handle the range constraint directly after step snapping:
• RangeMinToStepFrequency: If snapped value exceeds RangeEnd, snap down to previous valid step using Math.Floor
• RangeMaxToStepFrequency: If snapped value is below RangeStart, snap up to next valid step using Math.Ceiling

This keeps MoveToStepFrequency as a pure step-snapping utility, while the range constraint logic lives in the methods that understand the relationship between the two range values.

Note: The interaction between VerifyValues() (bounds clamping) and step frequency snapping remains complex and should be refactored in a future PR to clarify responsibilities.
@michael-hawker michael-hawker added hotfix Used for PRs/Issues that more immediately need review to be included in an upcoming hotfix. and removed hotfix Used for PRs/Issues that more immediately need review to be included in an upcoming hotfix. labels Dec 18, 2025
@Arlodotexe
Copy link
Member

It turns out that fixing the bounds check here has cascaded into a series of other bugs that lay dormant, especially around existing code allowing RangeStart to be greater than RangeEnd.

I'll need to push to a separate branch and rewind this one to contain only the minimal fixes for the DWM crashes we've observed on 23H2 and 24H2.


I've pushed to the branch rangeselector/rangestart-rangeend-fixup and will file a follow-up issue under this component's test and source areas with appropriate labels.

Reverting this branch back to the absolute minimum needed to fix observed DWM issues.

@Arlodotexe Arlodotexe enabled auto-merge (rebase) December 18, 2025 23:33
@michael-hawker michael-hawker added the hotfix Used for PRs/Issues that more immediately need review to be included in an upcoming hotfix. label Dec 18, 2025
@michael-hawker
Copy link
Member

Thanks @Arlodotexe, please file the tracking issue for 8.3 consideration and link back here to the discussion. We can merge this and then kick-off the 8.2 hotfix release then!

@michael-hawker
Copy link
Member

intermittent test failure, rekicked

@michael-hawker
Copy link
Member

Kicked again, still SizersTests.ExampleSizerBaseTestClass.ShouldConfigureGridSplitterAutomationPeer I think both times... oddly

@michael-hawker
Copy link
Member

Finally actually got a clean test-pass, but @Arlodotexe this still causes test failures:

Failed Initialize_MinEqMax (0,0,0,0) [198 ms]

Let's just fix this proper in 8.3, as it seems it's a mess right now to fix this.

@michael-hawker michael-hawker removed the hotfix Used for PRs/Issues that more immediately need review to be included in an upcoming hotfix. label Dec 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Setting RangeSelector to 100-100 with max value to 1 crashes DWM.

5 participants