Skip to content

macOS: no mouse-hover events (tooltips, I-beam cursor) in AddressSanitizer builds #141

Description

@jfultz

[I asked Claude to spin this issue off after it became a distraction from some interface work I was trying to accomplish. -jf]

When Quackle is built with -DQUACKLE_SANITIZE_ADDRESS=ON on macOS, the app receives no mouse-hover feedback: tooltips never appear, and the I-beam cursor does not appear over enabled QLineEdits. Rebuilding the identical source with QUACKLE_SANITIZE_ADDRESS=OFF restores both immediately.

This was noticed while adding tooltips to the simulation controls, but the tooltips are only the symptom that got noticed first. The two symptoms share a cause: on macOS, both mouse-moved events and cursor-shape updates are delivered through the same NSTrackingArea that QNSView installs. Hover-event delivery is what's broken; tooltips and cursor shape are downstream of it.

Root cause not yet identified.

Environment

  • macOS 15.7.2 (24G325), arm64
  • Qt 6.11.1 (macOS build), used for every build below
  • Apple clang 17.0.0 (clang-1700.0.13.5)
  • Quackle at 169b6f8
  • ASan flags are just what Settings.cmake adds: -fsanitize=address -fno-omit-frame-pointer -g for compile, -fsanitize=address for link. Nothing else differs between the two configurations.

Reproducing

cmake -S quacker -B build-asan -G Ninja -DCMAKE_PREFIX_PATH=<qt> -DQUACKLE_SANITIZE_ADDRESS=ON
cmake --build build-asan --target Quackle

Run it, start a game, go to the Choices tab, and hover the simulation controls. No tooltip, and no I-beam over the "Partial oppo rack" / "Log sim to file" fields when they are enabled. The same build with -DQUACKLE_SANITIZE_ADDRESS=OFF behaves correctly.

ASan prints no report; the app does not crash or misbehave otherwise.

What has been ruled out

All of the following were measured on ASan-ON vs ASan-OFF builds of the same source, same Qt 6.11.1:

  1. The tooltip machinery is fine under ASan. Injecting a synthetic QEvent::MouseMove at the QWidgetWindow level (rather than at the widget, which does not reach the tooltip code) triggers a full, correct tooltip cycle in both builds: the 700 ms wake-up timer fires, QToolTip::isVisible() becomes true, the text is identical (322 chars), and the popup renders on screen — screenshots of the two builds are comparable pixel-for-pixel. So QToolTip, QTipLabel, the timer, and the popup window are all healthy under ASan. Something upstream of them is not delivering real hover events.

  2. NSTrackingArea setup is identical, at least in a minimal Qt app (a bare QWidget + QLineEdit, built both ways). Both report one tracking area with options 0x287MouseEnteredAndExited | MouseMoved | CursorUpdate | ActiveInActiveApp | InVisibleRect — plus appActive=1, keyWindow=1, acceptsMouseMovedEvents=0. Not yet checked inside Quackle's own window, and not yet confirmed by hand whether the minimal app actually loses hover under ASan (see below).

  3. Not event-loop starvation. Both builds sit at 0.0% CPU when idle, so the ASan build is not too busy to service the Cocoa event queue.

  4. Nothing else in the build differs. Settings.cmake adds only the sanitizer flags; no bundling, optimization-level, or Qt-configuration difference between the two.

Note on methodology: attempts to drive a real hover programmatically failed and are not evidence about ASan. QCursor::setPos warps the pointer without generating mouseMoved: events (measured: 0 QEvent::MouseMove after 40 warps, in both builds), and posting synthetic HID events via CGEventPost requires Accessibility permission. Every automated result above therefore comes from injection below the platform layer; the ASan failure itself has only been observed by hand.

Suggested next step

Build a minimal Qt app (bare QWidget + QLineEdit with a tooltip) twice, differing only in -fsanitize=address, and hover each by hand:

  • If the ASan build also loses the I-beam and tooltip, this is a Qt/ASan/macOS interaction with nothing to do with Quackle. Worth a note in the build docs so nobody chases a phantom UI bug, and possibly worth an upstream Qt report.
  • If the ASan build behaves correctly, something in Quackle is implicated — most likely a latent memory bug whose behavior changes under ASan's allocator and redzones — and bisecting Quackle's own startup/widget code is the way in.

If it turns out to be the first case, the practical impact is limited: ASan builds are used for headless regression testing in CI, where hover is irrelevant. The trap is a developer running an ASan build interactively and concluding the GUI is broken.

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions