From d57549159dda3cf727ec46f09d576c39cf4f458f Mon Sep 17 00:00:00 2001 From: harrierpigeon Date: Fri, 25 Sep 2026 01:54:17 -0500 Subject: [PATCH] 3MF loader: refuse non-finite vertex coordinates A 3MF vertex with a nan/inf coordinate was accepted by both parsers and crashed qhull in ModelVolume's convex hull while the file was still loading. Both vertex handlers refuse it, and volume generation checks again whichever parser produced the geometry. The main parser's _stop_object_xml_parser keeps a message a handler already set. --- src/libslic3r/Format/bbs_3mf.cpp | 43 +++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index e2091da1db..366104bfa8 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -978,10 +978,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) void _stop_object_xml_parser(const std::string& msg = std::string()) { assert(! obj_parse_error); - assert(obj_parse_error_message.empty()); assert(object_xml_parser != nullptr); obj_parse_error = true; - obj_parse_error_message = msg; + if (! msg.empty() || obj_parse_error_message.empty()) // a handler may have set the message already + obj_parse_error_message = msg; XML_StopParser(object_xml_parser, false); } @@ -3815,11 +3815,18 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) { // appends the vertex coordinates // missing values are set equal to ZERO - if (m_curr_object) - m_curr_object->geometry.vertices.emplace_back( - m_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, X_ATTR), - m_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, Y_ATTR), - m_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, Z_ATTR)); + if (m_curr_object) { + const Vec3f v(m_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, X_ATTR), + m_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, Y_ATTR), + m_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, Z_ATTR)); + // A non-finite coordinate ("nan", "inf") used to be accepted and crashed + // qhull in ModelVolume's convex hull while the file was still loading. Refuse the file. + if (! v.allFinite()) { + _stop_xml_parser("Invalid vertex coordinate: not a finite number"); + return true; // the parser is stopped; returning false would overwrite the message + } + m_curr_object->geometry.vertices.emplace_back(v); + } return true; } @@ -5109,6 +5116,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } } + for (const Vec3f &v : sub_object->geometry.vertices) + if (! v.allFinite()) { // Qhull cannot take a NaN vertex + add_error("invalid (non-finite) vertex in object " + std::to_string(sub_object->id)); + return false; + } its.vertices.assign(sub_object->geometry.vertices.begin(), sub_object->geometry.vertices.end()); // BBS @@ -5600,11 +5612,18 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) { // appends the vertex coordinates // missing values are set equal to ZERO - if (current_object) - current_object->geometry.vertices.emplace_back( - object_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, X_ATTR), - object_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, Y_ATTR), - object_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, Z_ATTR)); + if (current_object) { + const Vec3f v(object_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, X_ATTR), + object_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, Y_ATTR), + object_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, Z_ATTR)); + // See _BBS_3MF_Importer::_handle_start_vertex: a non-finite coordinate + // crashed qhull while the file loaded. The dispatcher stops this parser on `false`. + if (! v.allFinite()) { + obj_parse_error_message = "Invalid vertex coordinate: not a finite number"; + return false; + } + current_object->geometry.vertices.emplace_back(v); + } return true; }