Fix InvalidCastException in Control.OnHandleDestroyed for non-ControlAccessibleObject#14295
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes a regression in Control.OnHandleDestroyed where PropertyStore.TryGetValue<T> could throw InvalidCastException if a control’s accessibility object stored in the property store is not a ControlAccessibleObject.
Changes:
- Update
OnHandleDestroyedto retrieveAccessibleObjectinstances from thePropertyStoreinstead ofControlAccessibleObject. - Use type pattern matching to only clear the handle when the stored object is actually a
ControlAccessibleObject(including derived types).
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #14295 +/- ##
===================================================
+ Coverage 77.18395% 77.24652% +0.06257%
===================================================
Files 3279 3279
Lines 645138 645119 -19
Branches 47730 47731 +1
===================================================
+ Hits 497943 498332 +389
+ Misses 143503 143094 -409
- Partials 3692 3693 +1
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
src/test/unit/System.Windows.Forms/System/Windows/Forms/ControlTests.Methods.cs
Show resolved
Hide resolved
ricardobossan
left a comment
There was a problem hiding this comment.
Other than a small comment, all LGTM!
…leObject_DoesNotThrow1"
KlausLoeffelmann
left a comment
There was a problem hiding this comment.
We should think about pro-actively investigating potential other regressions connected to that Property Store "Optimization". But for now, this is OK to take.
Fixes #14291
Root Cause
Control.OnHandleDestroyedusedProperties.TryGetValue<ControlAccessibleObject>for both AccessibilityObject and NcAccessibilityObject, assuming the stored instance was always a ControlAccessibleObject. When a control overridesCreateAccessibleObject()to return a different AccessibleObject type, the genericTryGetValue<T>attempted an invalid cast and threwInvalidCastExceptionduring handle destruction.Proposed changes
Control.OnHandleDestroyedfors_accessibilityPropertyands_ncAccessibilityPropertyfromTryGetValue<ControlAccessibleObject>toTryGetValue<AccessibleObject>, then use type pattern matching (accObj is ControlAccessibleObject controlAccObj) before resettingcontrolAccObj.Handle = IntPtr.Zero, so only trueControlAccessibleObjectinstances are manipulated and other AccessibleObject types no longer cause invalid casts.Customer Impact
InvalidCastExceptioncrashes when controls with custom accessible objects are destroyedRegression?
Risk
Screenshots
Before
Sample project:
WinFormsApp15.zip
On teardown, If a custom overrode CreateAccessibleObject() and returned a different AccessibleObject type, TryGetValue threw an InvalidCastException when the handle was destroyed, potentially crashing the app.
BeforeChanges.mp4
After
Custom accessible objects that are not
ControlAccessibleObjectare left untouched during handle destruction, so noInvalidCastExceptionis thrown and the app stays stable.AfterChanges.mp4
Test methodology
Test environment(s)
Microsoft Reviewers: Open in CodeFlow