Skip to content

Fix undisposed PointerEvent JSObject on browser pointer move - #22112

Open
appel1 wants to merge 2 commits into
AvaloniaUI:mainfrom
appel1:fix/browser-pointerevent-dispose
Open

Fix undisposed PointerEvent JSObject on browser pointer move#22112
appel1 wants to merge 2 commits into
AvaloniaUI:mainfrom
appel1:fix/browser-pointerevent-dispose

Conversation

@appel1

@appel1 appel1 commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

OnPointerMove dropped argsObj (the JSObject wrapping the native DOM PointerEvent) without disposing it, except inside a Lazy factory only evaluated when GetIntermediatePoints() is called - which doesn't happen for ordinary moves/hover.

What does the pull request do?

Fix by disposing argsObj in a finally block after routing, guaranteeing deterministic release instead of depending on GC timing. Coalesced-event resolution (GetCoalescedEvents) is unaffected since it only runs synchronously within the same call when a consumer needs it.

What is the current behavior?

Without explicit Dispose(), release requires two steps: Mono GC must collect the abandoned JSObject wrapper to release its JS handle, then V8 can reclaim the underlying JS object. Verified with a standalone FinalizationRegistry-based repro that Mono GC does not trigger on its own under continuous pointermove-like allocation pressure, so undisposed objects pile up - not a permanent leak though.

What is the updated/expected behavior with this PR?

Reduced memory pressure.

OnPointerMove dropped argsObj (the JSObject wrapping the native DOM
PointerEvent) without disposing it, except inside a Lazy factory only
evaluated when GetIntermediatePoints() is called - which doesn't happen
for ordinary moves/hover.

Without explicit Dispose(), release requires two steps: Mono GC must
collect the abandoned JSObject wrapper to release its JS handle, then
V8 can reclaim the underlying JS object. Verified with a standalone
FinalizationRegistry-based repro that Mono GC does not trigger on its
own under continuous pointermove-like allocation pressure, so undisposed
objects pile up - not a permanent leak though.

Fix by disposing argsObj in a finally block after routing, guaranteeing
deterministic release instead of depending on GC timing. Coalesced-event
resolution (GetCoalescedEvents) is unaffected since it only runs
synchronously within the same call when a consumer needs it.
@MrJul MrJul added bug os-browser backport-candidate-12.1.x Consider this PR for backporting to 12.1 branch labels Aug 31, 2026
@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.2.999-cibuild0069200-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

try
{
// Note: routing here is only synchronous when _rawEventGrouper is null (the branch above
// that creates the Lazy referencing argsObj). When _rawEventGrouper is set, ScheduleInput

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ScheduleInput context is a good comment, clearing that dispose is safe here. But it can be greatly reduced (and better formatted).

Please follow AI guidelines: https://github.com/appel1/Avalonia/blob/328a7cfbec11bdbe471652b5335658dc22899bd2/CONTRIBUTING.md#ai-guidelines

@appel1 appel1 Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized, maybe it isn't so safe after all. Nothing stops an event listener from saving the RawTouchEventArgs and accessing the IntermediatePoints Lazy later after argsObj has been disposed.

Is that still ok? Is it implied that you should only touch event args objects during the event handler?

maxkatz6
maxkatz6 previously approved these changes Aug 31, 2026

@maxkatz6 maxkatz6 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM otherwise

@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.2.999-cibuild0069301-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-candidate-12.1.x Consider this PR for backporting to 12.1 branch bug os-browser

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants