From 4b7182b048a979a3aca40782d9d1685a99f632c4 Mon Sep 17 00:00:00 2001 From: Kris Austin Date: Sat, 11 Jul 2026 04:41:22 -0500 Subject: [PATCH] fix: guard against stale instance ids in PartPlate instance scans (#14523) Deleting an object's instance leaves a stale (obj_id, instance_id) pair in PartPlate::obj_to_instance_set until it is pruned. object_list_changed() runs during the delete path and calls has_printable_instances(), which guarded only obj_id and then indexed object->instances[instance_id] on the now-shorter vector, dereferencing a garbage ModelInstance* and crashing with SIGSEGV. The reported fault address (0x12a) matches a member read on that bad pointer. Reuse the existing valid_instance() helper, which bounds-checks both obj_id and instance_id, at every obj_to_instance_set scan that was missing the instance-id check: has_printable_instances(), printable_instance_size(), is_all_instances_unprintable(), get_extruders_under_cli(), duplicate_all_instance() and set_pos_and_size() (the last had no bounds check at all). valid_instance() is made const so the const CLI scan can call it. Fixes #14159 --- src/slic3r/GUI/PartPlate.cpp | 20 ++++++++++++-------- src/slic3r/GUI/PartPlate.hpp | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index 18d6e17b33..6a4e747d3a 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -385,7 +385,7 @@ void PartPlate::set_spiral_vase_mode(bool spiral_mode, bool as_global) } } -bool PartPlate::valid_instance(int obj_id, int instance_id) +bool PartPlate::valid_instance(int obj_id, int instance_id) const { if ((obj_id >= 0) && (obj_id < m_model->objects.size())) { @@ -1688,7 +1688,7 @@ std::vector PartPlate::get_extruders_under_cli(bool conside_custom_gcode, D int obj_id = it->first; int instance_id = it->second; - if ((obj_id >= 0) && (obj_id < m_model->objects.size())) + if (valid_instance(obj_id, instance_id)) { ModelObject* object = m_model->objects[obj_id]; ModelInstance* instance = object->instances[instance_id]; @@ -2359,6 +2359,9 @@ void PartPlate::set_pos_and_size(Vec3d& origin, int width, int depth, int height for (std::set>::iterator it = obj_to_instance_set.begin(); it != obj_to_instance_set.end(); ++it) { int obj_id = it->first; int instance_id = it->second; + if (!valid_instance(obj_id, instance_id)) + continue; + ModelObject* object = m_model->objects[obj_id]; ModelInstance* instance = object->instances[instance_id]; @@ -2833,7 +2836,7 @@ void PartPlate::duplicate_all_instance(unsigned int dup_count, bool need_skip, s int obj_id = it->first; int instance_id = it->second; - if ((obj_id >= 0) && (obj_id < m_model->objects.size())) + if (valid_instance(obj_id, instance_id)) { ModelObject* object = m_model->objects[obj_id]; ModelInstance* instance = object->instances[instance_id]; @@ -2866,7 +2869,7 @@ void PartPlate::duplicate_all_instance(unsigned int dup_count, bool need_skip, s int obj_id = it->first; int instance_id = it->second; - if ((obj_id >= 0) && (obj_id < m_model->objects.size())) + if (valid_instance(obj_id, instance_id)) { ModelObject* object = m_model->objects[obj_id]; ModelInstance* instance = object->instances[instance_id]; @@ -2983,8 +2986,8 @@ int PartPlate::printable_instance_size() int obj_id = it->first; int instance_id = it->second; - if (obj_id >= m_model->objects.size()) - continue; + if (!valid_instance(obj_id, instance_id)) + continue; ModelObject * object = m_model->objects[obj_id]; ModelInstance *instance = object->instances[instance_id]; @@ -3006,7 +3009,7 @@ bool PartPlate::has_printable_instances() int obj_id = it->first; int instance_id = it->second; - if (obj_id >= m_model->objects.size()) + if (!valid_instance(obj_id, instance_id)) continue; ModelObject* object = m_model->objects[obj_id]; @@ -3030,7 +3033,8 @@ bool PartPlate::is_all_instances_unprintable() int obj_id = it->first; int instance_id = it->second; - if (obj_id >= m_model->objects.size()) continue; + if (!valid_instance(obj_id, instance_id)) + continue; ModelObject * object = m_model->objects[obj_id]; ModelInstance *instance = object->instances[instance_id]; diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index d4c5399142..f841c001a5 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -167,7 +167,7 @@ private: wxCoord m_name_texture_height; void init(); - bool valid_instance(int obj_id, int instance_id); + bool valid_instance(int obj_id, int instance_id) const; void generate_print_polygon(ExPolygon &print_polygon); void generate_exclude_polygon(ExPolygon &exclude_polygon); void generate_logo_polygon(ExPolygon &logo_polygon);