FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Bonsai: fix segfault when deleting an aggregate with its parts by BIMvoice · Pull Request #9308 · IfcOpenShell/IfcOpenShell · GitHub

Bonsai: fix segfault when deleting an aggregate with its parts - #9308

Draft
BIMvoice wants to merge 1 commit into
IfcOpenShell:v0.8.0from
BIMvoice:fix-9299-aggregate-delete-segfault
Draft

Bonsai: fix segfault when deleting an aggregate with its parts#9308
BIMvoice wants to merge 1 commit into
IfcOpenShell:v0.8.0from
BIMvoice:fix-9299-aggregate-delete-segfault

Conversation

Copy link
Copy Markdown
Contributor

Fixes #9299.

Deleting an IFC aggregate together with its parts in one bim.override_object_delete batch takes Blender down with a native segfault, losing unsaved work. It is a C++ fault in the binding layer, not a Python exception, so nothing on the Bonsai side can catch it.

Root cause

OverrideDelete.track_aggregates() collects live ifcopenshell.entity_instance wrappers before the deletion loop runs. When the aggregate is itself part of the selection, remove_product frees its backing C++ entity during that loop. delete_empty_aggregates() then calls .id() on the now stale wrapper.

The existing guard could never work:

try:
    aggregate.id()
except:
    continue

entity_instance.id() forwards directly to self.wrapped_data.id(), a raw C++ call with no liveness check, so the dangling dereference is a segfault rather than a Python exception.

Fix

Store aggregate ids instead of wrappers, and re-resolve each id through tool.Ifc.get_entity_by_id(), which wraps file.by_id() in except RuntimeError and returns None for a removed entity. Its docstring already describes exactly this use: "useful to check whether entity_id is still exists in IFC".

This is the direction the reporter proposed, and it fixes the problem at the point where the assumption is wrong, which is retaining a handle across a mutation, rather than adding another guard that cannot fire.

Verification

Reproduced live in Blender 5.2.0 using the reporter's script, in an isolated profile against ifcopenshell 0.8.5.

Before: exit 139, crash log backtrace matching the issue exactly (_wrap_entity_instance_id, then entity_instance.py:442 id, then delete_empty_aggregates at operator.py:1009, then _execute at 955).

After: OP RESULT: {'FINISHED'} and the IFC graph empty, with 0 remaining stairs, flights and slabs.

A scenario covering aggregate plus part deletion is added to src/bonsai/test/bim/feature/geometry.feature, alongside the existing override delete scenarios. Scope honesty: that scenario was validated through an equivalent isolated Blender harness, red before and green after, but it has not been run through the project's pytest-blender CI harness locally, and a pure Python test cannot catch a native crash in any case.

black and ruff clean on the changed file, both before and after.

Related, not changed here

BIM_OT_aggregate_unassign_object._execute in bim/module/aggregate/operator.py uses the same pattern, collecting live wrappers in a first pass and calling .is_a(), .id(), get_parts() and remove_product() on them in a second. It does not crash today because the first pass only unassigns, but it is the same fragile shape. Left alone to keep this PR to one bug.

Separately, it is worth considering whether entity_instance accessors should raise a catchable exception when the backing entity has been removed. That would close this class of bug rather than this instance of it, but it is a core decision rather than a Bonsai one.

Produced with AI assistance.

OverrideDelete.track_aggregates() snapshotted live
entity_instance wrappers before the deletion loop. When the
aggregate itself was also selected for deletion,
delete_empty_aggregates() later called .id() on a wrapper whose
backing native entity had already been freed by remove_product,
segfaulting instead of raising a catchable Python exception.

Store aggregate ids instead of wrappers, and re-resolve each one
through tool.Ifc.get_entity_by_id() after the delete loop, which
safely returns None for ids that no longer exist.

Fixes IfcOpenShell#9299.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Segfault when batch-deleting an IFC aggregate and its decomposed parts

1 participant


Back | FazBrowse Home | New Git URL