Skip to content

Commit 39130f8

Browse files
committed
fix: re-acquire menu handle after removeItem loop to prevent segfault
Closes #78. When every tracked item is removed from the Griptape (node) menu, Nuke silently destroys the parent menu object, leaving a dangling C++ pointer. The next addCommand through that stale handle triggers a segfault. Re-call addMenu after the removal loop to obtain a fresh (or still-valid) handle.
1 parent 56e5c2e commit 39130f8

2 files changed

Lines changed: 20 additions & 0 deletions

File tree

publish_gizmo/nuke_gizmo_publisher.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,11 @@ def _refresh_griptape_menu():
461461
pass
462462
_GRIPTAPE_MENU_ITEMS = []
463463
464+
# If all items were removed, then the menu itself is removed and we
465+
# have a dangling pointer, potentially leading to segfault, so
466+
# idempotently re-add the menu.
467+
griptape_nodes = nodes_toolbar.addMenu('Griptape')
468+
464469
for stem in sorted(workflows):
465470
label = stem.replace('_', ' ').title()
466471
versions = workflows[stem]

tests/unit/test_nuke_gizmo_publisher_menu.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,21 @@ def test_menu_code_reuses_existing_griptape_menu() -> None:
9191
assert code.index("nodes_toolbar.addMenu('Griptape')") < code.index("griptape_nodes.removeItem(")
9292

9393

94+
def test_menu_code_readds_menu_after_removing_all_items() -> None:
95+
"""Re-acquire the menu handle after the removeItem loop.
96+
97+
When every tracked item is removed, Nuke silently destroys the parent menu
98+
object, leaving a dangling C++ pointer. The next addCommand through that
99+
stale handle triggers a segfault. A second addMenu call after the loop
100+
obtains a fresh (or still-valid) handle and prevents the crash.
101+
"""
102+
code = _extract_menu_code()
103+
remove_idx = code.rindex("griptape_nodes.removeItem(")
104+
add_cmd_idx = code.index("griptape_nodes.addCommand(")
105+
readd_idx = code.index("nodes_toolbar.addMenu('Griptape')", remove_idx)
106+
assert remove_idx < readd_idx < add_cmd_idx
107+
108+
94109
def test_menu_code_warns_on_remote_mount() -> None:
95110
"""Must include remote-mount heuristic and print warning inside the Qt guard block.
96111

0 commit comments

Comments
 (0)