From 83a0d7a63c769849e4cf943145fc9a1df66b9683 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Tue, 9 Jul 2024 20:13:08 +0500 Subject: [PATCH] prevent freezing the iterator in case of unhandled exceptions Solving an issue in 355cca3 I've noticed that because of some unhandled exception iterator was freezing and hanging indefinitely, this should be resolved now to be safe. Also added had_errors_during_initialization() method that can help identify whether there were errors either during iterator initialization or processing elements. --- src/ifcgeom/Iterator.h | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/Iterator.h b/src/ifcgeom/Iterator.h index 045724fb77..8b685972b4 100644 --- a/src/ifcgeom/Iterator.h +++ b/src/ifcgeom/Iterator.h @@ -103,6 +103,7 @@ namespace IfcGeom { std::atomic finished_{ false }; std::atomic terminating_{ false }; + std::atomic had_error_processing_elements_ { false }; std::atomic progress_{ 0 }; std::vector tasks_; @@ -163,9 +164,22 @@ namespace IfcGeom { const std::string& unit_name() const { return unit_name_; } double unit_magnitude() const { return unit_magnitude_; } + // Check if error occurred during iterator initialization or iteration over elements. + bool had_error_processing_elements() const { return had_error_processing_elements_; } boost::optional initialization_outcome_; + /** + * @return Returns true if the iterator is initialized with any elements, false otherwise. + * + * @note + * - A true return value does not guarantee successful initialization of all elements. + * Some elements may have failed to initialize. Check had_error_processing_elements() + * to see whether there were errors during the initialization. + * + * - For non-concurrent iterators, a false return may occur if initialization of the first + * element fails, even if subsequent elements could be initialized successfully. + */ bool initialize() { using std::chrono::high_resolution_clock; @@ -322,7 +336,23 @@ namespace IfcGeom { ifcopenshell::geometry::Converter* kernel, ifcopenshell::geometry::Settings settings, geometry_conversion_result* rep) { - this->create_element_(kernel, settings, rep); + // Catch exceptions to be safe from freezing the iterator. + try { + this->create_element_(kernel, settings, rep); + } catch (const std::exception& e) { + Logger::Error( + std::string("Exception '") + e.what() + + std::string("' occurred while iterator was creating a shape: "), + rep->item->instance + ); + had_error_processing_elements_ = true; + } catch (...) { + Logger::Error( + "Unknown exception occurred while iteartor was creating a shape: ", + rep->item->instance + ); + had_error_processing_elements_ = true; + } return rep; }, K, @@ -758,6 +788,7 @@ namespace IfcGeom { product = create_shape_model_for_next_entity(); } catch (const std::exception& e) { Logger::Error(e); + had_error_processing_elements_ = true; } #ifdef IFOPSH_WITH_OPENCASCADE catch (const Standard_Failure& e) { @@ -766,10 +797,12 @@ namespace IfcGeom { } else { Logger::Error("Unknown error creating geometry"); } - } + had_error_processing_elements_ = true; + } #endif catch (...) { Logger::Error("Unknown error creating geometry"); + had_error_processing_elements_ = true; } return product; }