mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
824c1fc280
create_shape() returns a Python-owned Element (SWIG_POINTER_OWN in the boost::variant out typemap). Its .geometry property calls Element::geometry(), which returns a reference into the element's boost::shared_ptr<Representation> _geometry member. SWIG wraps that reference as a non-owning pointer, so the returned Triangulation/BRep/Serialization proxy does not keep the element alive. When a caller keeps only .geometry (e.g. create_shape(s, e).geometry) and drops the parent element, Python garbage-collects the element, destroying its shared_ptr and freeing the underlying representation. Subsequent reads of verts/faces then return freed memory: empty or implausible float/int garbage, non-deterministically depending on GC and allocator timing. This is silent data corruption, not a crash, and has bitten users since 2020. Fix: in the TriangulationElement/SerializedElement/BRepElement pythoncode, wrap the geometry getter so the returned geometry stores a backreference to its owning element (result._parent = self). This makes the parent's lifetime at least as long as the geometry's, automatically and transparently, so no caller has to remember to hold the element. This is aothms's suggested backreference, applied generically in the binding rather than left as a workaround. Reproduced deterministically (washBasin fixture): before, verts len 0 vs 133500 across repeated GC-pressure runs; after, 133500 every run for all three element types. test_create_shape passes; no regressions. Note: tree.select_ray()'s ray_intersection_result (2024 follow-up in #1124) is a separate ownership mechanism (std::vector element reference + std::array member pointer) and is left as follow-up scope. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>