Skip to content

PopupMenuBase retains destroyed items and disconnects sibling state handlers #13956

Description

@H234598

Distribution

Fedora Linux 44 (Cinnamon), X11

Package version

Cinnamon 6.6.7. The same faulty source pattern is present on current master at commit dc924304ff2f4aa5d972ff54dd933a9358ee1faa.

Graphics hardware in use

Intel Alder Lake-UP3 GT2 (Iris Xe Graphics), i915, Mesa 26.1.7.

Frequency

Always. The code-level reproduction is deterministic.

Bug description

PopupMenuBase retains destroyed menu items in its parent SignalManager.
Destroying a PopupSubMenuMenuItem can additionally disconnect unrelated
open-state-changed handlers belonging to sibling submenus and separators.

On unmodified Cinnamon 6.6.7, 1000 add/destroy cycles changed the parent
menu's managed signal count from 6 to 1006 while menu.length correctly
returned to 0.

The item destroy cleanup disconnects selected signal names but leaves its own
managed destroy record behind. The submenu cleanup also calls:

this._signals.disconnect('open-state-changed', this);

That removes all managed parent handlers with the same signal/object pair,
not only state associated with the destroyed submenu. Remaining submenus can
then stay open when their parent closes, and separators can stop updating.

Steps to reproduce

  1. Create a PopupMenu.
  2. Record menu._signals._storage.length.
  3. Repeat 1000 times:
    • create a PopupMenuItem,
    • add it with menu.addMenuItem(item),
    • destroy it with item.destroy().
  4. Check menu.length and menu._signals._storage.length again.

For the behavioral side effect:

  1. Add two submenu items to one parent menu.
  2. Destroy the first submenu item.
  3. Open the second submenu and close the parent menu.
  4. The second submenu's close handler has been removed by destruction of the
    first item. The equivalent issue affects separator visibility handlers.

Expected behavior

  • Destroyed items and child menus are no longer referenced by the parent
    SignalManager.
  • Managed signal count returns to its baseline after every add/destroy cycle.
  • Destroying one submenu does not affect sibling submenu or separator
    behavior.

Additional information

Root cause is the mismatch between signal-name-based cleanup and actual
object ownership. A focused fix is to:

  • disconnect all parent-managed signals owned by the destroyed item and its
    child menu,
  • replace per-item parent handlers with one menu-lifetime
    open-state-changed handler,
  • traverse current items recursively through PopupMenuSection.

I have a focused patch and an isolated regression runner ready. Verification
covers:

  • 1000 add/destroy cycles each for normal items, separators, submenu items,
    and sections,
  • sibling submenu close behavior,
  • separator updates after submenu destruction,
  • nested sections,
  • non-animated parent close,
  • animated deferred close through the real mapped/unmapped path,
  • the current master source file,
  • an exact source port to the 6.6.9 maintenance branch.

Searches for popupMenu SignalManager leak, PopupSubMenuMenuItem destroy,
open-state-changed popupMenu, and popup menu memory leak found no specific
duplicate. #6850 is a broad long-term memory-growth report without this
reproduction or root cause.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions