From 42104a5fd5d3d919d4f6cbbb47c147aa9d472bca Mon Sep 17 00:00:00 2001 From: NikEfth Date: Tue, 23 Dec 2025 10:20:36 +0100 Subject: [PATCH 1/2] Fix memory leak from repeated ProjDataInfo::clone() calls --- src/scatter_buildblock/ScatterSimulation.cxx | 21 ++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index 6ace332e5..5599164ed 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -743,15 +743,20 @@ void ScatterSimulation::set_template_proj_data_info(const ProjDataInfo& arg) { this->_already_set_up = false; - this->proj_data_info_sptr.reset(dynamic_cast(arg.clone())); - - if (is_null_ptr(this->proj_data_info_sptr)) + std::unique_ptr cloned(arg.clone()); + if (auto* blocks = dynamic_cast(cloned.get())) { - this->proj_data_info_sptr.reset(dynamic_cast(arg.clone())); - if (is_null_ptr(this->proj_data_info_sptr)) - { - error("ScatterSimulation: Can only handle non-arccorrected data"); - } + this->proj_data_info_sptr.reset(blocks); + cloned.release(); // transfer ownership + } + else if (auto* cyl = dynamic_cast(cloned.get())) + { + this->proj_data_info_sptr.reset(cyl); + cloned.release(); // transfer ownership + } + else + { + error("ScatterSimulation: Can only handle non-arccorrected data"); } // find final size of detection_points_vector From 149fb55f66441af64fadcb284d327434a9e521e0 Mon Sep 17 00:00:00 2001 From: NikEfth Date: Tue, 23 Dec 2025 11:39:17 +0100 Subject: [PATCH 2/2] Memory leak fixes. --- src/include/stir/scatter/ScatterSimulation.h | 4 +-- .../test_blocks_on_cylindrical_projectors.cxx | 9 ++++--- src/scatter_buildblock/ScatterEstimation.cxx | 4 +-- src/scatter_buildblock/ScatterSimulation.cxx | 27 +++++++++---------- .../scatter_detection_modelling.cxx | 4 +-- src/test/test_ScatterSimulation.cxx | 8 +++--- src/test/test_interpolate_projdata.cxx | 2 +- 7 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/include/stir/scatter/ScatterSimulation.h b/src/include/stir/scatter/ScatterSimulation.h index 0a2723b92..a086dcb6c 100644 --- a/src/include/stir/scatter/ScatterSimulation.h +++ b/src/include/stir/scatter/ScatterSimulation.h @@ -124,7 +124,7 @@ class ScatterSimulation : public RegisteredObject void set_template_proj_data_info(const std::string&); - void set_template_proj_data_info(const ProjDataInfo&); + void set_template_proj_data_info(std::shared_ptr arg); void set_activity_image_sptr(const shared_ptr>); @@ -334,7 +334,7 @@ class ScatterSimulation : public RegisteredObject std::string template_proj_data_filename; - shared_ptr proj_data_info_sptr; + shared_ptr proj_data_info_sptr; //! \details Exam info extracted from the scanner template shared_ptr template_exam_info_sptr; diff --git a/src/recon_test/test_blocks_on_cylindrical_projectors.cxx b/src/recon_test/test_blocks_on_cylindrical_projectors.cxx index ba8d13c2d..2c5455c85 100644 --- a/src/recon_test/test_blocks_on_cylindrical_projectors.cxx +++ b/src/recon_test/test_blocks_on_cylindrical_projectors.cxx @@ -195,7 +195,7 @@ BlocksTests::run_symmetry_test(ForwardProjectorByBin& forw_projector1, ForwardPr shared_ptr> image1_sptr(image.clone()); write_to_file("image_for", *image1_sptr); - image = *image.get_empty_copy(); + image.fill(0); //= *image.get_empty_copy(); for (int i = 15; i < 360; i += 30) { theta2 = i * _PI / 180; @@ -307,7 +307,8 @@ BlocksTests::run_plane_symmetry_test(ForwardProjectorByBin& forw_projector1, For // rotate by 30 degrees phi2 = 30 * _PI / 180; - VoxelsOnCartesianGrid image2 = *image.get_empty_copy(); + VoxelsOnCartesianGrid image2(image); // = *image.get_empty_copy(); + image2.fill(0); const Array<2, float> direction2 = make_array(make_1d_array(1.F, 0.F, 0.F), make_1d_array(0.F, cos(float(_PI) - phi2), sin(float(_PI) - phi2)), make_1d_array(0.F, -sin(float(_PI) - phi2), cos(float(_PI) - phi2))); @@ -591,7 +592,7 @@ BlocksTests::run_map_orientation_test(ForwardProjectorByBin& forw_projector1, Fo shared_ptr> image1_sptr(image.clone()); write_to_file("image_to_fwp", *image1_sptr); - image = *image.get_empty_copy(); + image.fill(0); //= *image.get_empty_copy(); shared_ptr map_sptr; auto scannerBlocks_sptr = std::make_shared(Scanner::SAFIRDualRingPrototype); @@ -700,7 +701,7 @@ BlocksTests::run_projection_test(ForwardProjectorByBin& forw_projector1, Forward shared_ptr> image1_sptr(image.clone()); write_to_file("image_with_voxel_at_30_0", *image1_sptr); - image = *image.get_empty_copy(); + image.fill(0); //= *image.get_empty_copy(); image[(image.get_min_index() + image.get_max_index()) / 2 * grid_spacing.z()][0][-25] = 1; shared_ptr> image2_sptr(image.clone()); diff --git a/src/scatter_buildblock/ScatterEstimation.cxx b/src/scatter_buildblock/ScatterEstimation.cxx index a52593020..093922242 100644 --- a/src/scatter_buildblock/ScatterEstimation.cxx +++ b/src/scatter_buildblock/ScatterEstimation.cxx @@ -610,12 +610,12 @@ ScatterEstimation::set_up() "discarded)"); if (run_in_2d_projdata) { - this->scatter_simulation_sptr->set_template_proj_data_info(*this->input_projdata_2d_sptr->get_proj_data_info_sptr()); + this->scatter_simulation_sptr->set_template_proj_data_info(this->input_projdata_2d_sptr->get_proj_data_info_sptr()); this->scatter_simulation_sptr->set_exam_info(this->input_projdata_2d_sptr->get_exam_info()); } else { - this->scatter_simulation_sptr->set_template_proj_data_info(*this->input_projdata_sptr->get_proj_data_info_sptr()); + this->scatter_simulation_sptr->set_template_proj_data_info(this->input_projdata_sptr->get_proj_data_info_sptr()); this->scatter_simulation_sptr->set_exam_info(this->input_projdata_sptr->get_exam_info()); } } diff --git a/src/scatter_buildblock/ScatterSimulation.cxx b/src/scatter_buildblock/ScatterSimulation.cxx index 5599164ed..72145f68d 100644 --- a/src/scatter_buildblock/ScatterSimulation.cxx +++ b/src/scatter_buildblock/ScatterSimulation.cxx @@ -352,14 +352,14 @@ ScatterSimulation::set_up() { CartesianCoordinate3D detector_coord_A, detector_coord_B; // check above statement - if (dynamic_cast(proj_data_info_sptr.get())) + if (dynamic_cast(proj_data_info_sptr.get())) { - auto ptr = dynamic_cast(proj_data_info_sptr.get()); + const auto* ptr = dynamic_cast(proj_data_info_sptr.get()); ptr->find_cartesian_coordinates_of_detection(detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); } else { - auto ptr = dynamic_cast(proj_data_info_sptr.get()); + const auto* ptr = dynamic_cast(proj_data_info_sptr.get()); ptr->find_cartesian_coordinates_of_detection(detector_coord_A, detector_coord_B, Bin(0, 0, 0, 0)); } @@ -374,14 +374,14 @@ ScatterSimulation::set_up() assert(fabs(m_last + m_first) < m_last * 10E-4); } #endif - if (dynamic_cast(proj_data_info_sptr.get())) + if (dynamic_cast(proj_data_info_sptr.get())) { this->shift_detector_coordinates_to_origin = CartesianCoordinate3D(this->proj_data_info_sptr->get_m(Bin(0, 0, 0, 0)), 0, 0); } else { - if (dynamic_cast(proj_data_info_sptr.get())) + if (dynamic_cast(proj_data_info_sptr.get())) { // align BlocksOnCylindrical scanner ring 0 to z=0. this->shift_detector_coordinates_to_origin @@ -736,23 +736,20 @@ ScatterSimulation::set_template_proj_data_info(const std::string& filename) this->set_exam_info(template_proj_data_sptr->get_exam_info()); - this->set_template_proj_data_info(*template_proj_data_sptr->get_proj_data_info_sptr()); + this->set_template_proj_data_info(template_proj_data_sptr->get_proj_data_info_sptr()); } void -ScatterSimulation::set_template_proj_data_info(const ProjDataInfo& arg) +ScatterSimulation::set_template_proj_data_info(std::shared_ptr arg) { this->_already_set_up = false; - std::unique_ptr cloned(arg.clone()); - if (auto* blocks = dynamic_cast(cloned.get())) + if (auto p = std::dynamic_pointer_cast(arg)) { - this->proj_data_info_sptr.reset(blocks); - cloned.release(); // transfer ownership + this->proj_data_info_sptr = p; } - else if (auto* cyl = dynamic_cast(cloned.get())) + else if (auto q = std::dynamic_pointer_cast(arg)) { - this->proj_data_info_sptr.reset(cyl); - cloned.release(); // transfer ownership + this->proj_data_info_sptr = q; } else { @@ -949,7 +946,7 @@ ScatterSimulation::downsample_scanner(int new_num_rings, int new_num_dets) false)); info(format("ScatterSimulation: down-sampled scanner info:\n{}", templ_proj_data_info_sptr->parameter_info()), 3); - this->set_template_proj_data_info(*templ_proj_data_info_sptr); + this->set_template_proj_data_info(templ_proj_data_info_sptr); this->set_output_proj_data(this->output_proj_data_filename); return Succeeded::yes; diff --git a/src/scatter_buildblock/scatter_detection_modelling.cxx b/src/scatter_buildblock/scatter_detection_modelling.cxx index ba2e182ad..e174e78ab 100644 --- a/src/scatter_buildblock/scatter_detection_modelling.cxx +++ b/src/scatter_buildblock/scatter_detection_modelling.cxx @@ -65,14 +65,14 @@ ScatterSimulation::find_detectors(unsigned& det_num_A, unsigned& det_num_B, cons error("ScatterSimulation::find_detectors: need to call set_up() first"); #endif CartesianCoordinate3D detector_coord_A, detector_coord_B; - auto ptr = dynamic_cast(proj_data_info_sptr.get()); + const auto* ptr = dynamic_cast(proj_data_info_sptr.get()); if (ptr) { ptr->find_cartesian_coordinates_of_detection(detector_coord_A, detector_coord_B, bin); } else { - auto ptr = dynamic_cast(proj_data_info_sptr.get()); + const auto* ptr = dynamic_cast(proj_data_info_sptr.get()); if (ptr) { ptr->find_cartesian_coordinates_of_detection(detector_coord_A, detector_coord_B, bin); diff --git a/src/test/test_ScatterSimulation.cxx b/src/test/test_ScatterSimulation.cxx index d8d4e5b16..72c61c9cf 100644 --- a/src/test/test_ScatterSimulation.cxx +++ b/src/test/test_ScatterSimulation.cxx @@ -92,7 +92,7 @@ ScatterSimulationTests::test_downsampling_ProjDataInfo() false))); unique_ptr sss(new SingleScatterSimulation()); - sss->set_template_proj_data_info(*original_projdata); + sss->set_template_proj_data_info(original_projdata); { auto sss_projdata = dynamic_cast(sss->get_template_proj_data_info_sptr().get()); check(*original_projdata == *sss_projdata, "Check the ProjDataInfo has been set correctly."); @@ -183,7 +183,7 @@ ScatterSimulationTests::test_downsampling_DiscretisedDensity() unique_ptr sss(new SingleScatterSimulation()); - sss->set_template_proj_data_info(*original_projdata); + sss->set_template_proj_data_info(original_projdata); sss->set_density_image_sptr(atten_density); // int total_scatter_points_orig = sss.get_num_scatter_points(); @@ -391,7 +391,7 @@ ScatterSimulationTests::test_scatter_simulation() //// sss settings sss->set_randomly_place_scatter_points(false); - sss->set_template_proj_data_info(*original_projdata_info); + sss->set_template_proj_data_info(original_projdata_info); sss->downsample_scanner(original_projdata_info->get_scanner_sptr()->get_num_rings(), -1); #if 1 set_tolerance(.02); @@ -448,7 +448,7 @@ ScatterSimulationTests::test_scatter_simulation() } // a few tests with more downsampled scanner - sss->set_template_proj_data_info(*original_projdata_info); + sss->set_template_proj_data_info(original_projdata_info); sss->downsample_scanner(original_projdata_info->get_scanner_sptr()->get_num_rings() / 2, -1); { const int new_size_z = 14; diff --git a/src/test/test_interpolate_projdata.cxx b/src/test/test_interpolate_projdata.cxx index 082d16a61..85489c1ec 100644 --- a/src/test/test_interpolate_projdata.cxx +++ b/src/test/test_interpolate_projdata.cxx @@ -850,7 +850,7 @@ InterpolationTests::transaxial_upsampling_interpolation_test_blocks() // use the code in scatter simulation to downsample the scanner auto scatter_simulation = SingleScatterSimulation(); - scatter_simulation.set_template_proj_data_info(*proj_data_info); + scatter_simulation.set_template_proj_data_info(proj_data_info); scatter_simulation.set_exam_info(exam_info); scatter_simulation.downsample_scanner(-1, 96 / 4); // number of detectors per ring reduced by factor of four auto downsampled_proj_data_info = scatter_simulation.get_template_proj_data_info_sptr();