diff --git a/CMakeLists.txt b/CMakeLists.txt index 3533cb29a4..913f604f82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -803,6 +803,7 @@ if(openPMD_BUILD_TESTING) list(APPEND ${out_list} test/Files_SerialIO/close_and_reopen_test.cpp test/Files_SerialIO/filebased_write_test.cpp + test/Files_SerialIO/issue_1744_unique_ptrs_at_close_time.cpp ) elseif(${test_name} STREQUAL "ParallelIO" AND openPMD_HAVE_MPI) list(APPEND ${out_list} diff --git a/src/IO/ADIOS/ADIOS2File.cpp b/src/IO/ADIOS/ADIOS2File.cpp index 625261a864..4678e13bec 100644 --- a/src/IO/ADIOS/ADIOS2File.cpp +++ b/src/IO/ADIOS/ADIOS2File.cpp @@ -225,16 +225,18 @@ void ADIOS2File::finalize() { return; } - if (!m_uniquePtrPuts.empty()) - { - throw error::Internal( - "[ADIOS2 backend] Orphaned unique-ptr put operations found " - "when closing file."); - } // if write accessing, ensure that the engine is opened - if (!m_engine && writeOnly(m_mode)) + // and that all datasets are written + // (attributes and unique_ptr datasets are written upon closing a step + // or a file which users might never do) + bool needToWrite = !m_uniquePtrPuts.empty(); + if ((needToWrite || !m_engine) && writeOnly(m_mode)) { getEngine(); + for (auto &entry : m_uniquePtrPuts) + { + entry.run(*this); + } } if (m_engine) { @@ -250,6 +252,7 @@ void ADIOS2File::finalize() m_ADIOS.RemoveIO(m_IOName); } } + m_uniquePtrPuts.clear(); finalized = true; } diff --git a/test/Files_SerialIO/SerialIOTests.hpp b/test/Files_SerialIO/SerialIOTests.hpp index 541d4dcaf1..f5e770681b 100644 --- a/test/Files_SerialIO/SerialIOTests.hpp +++ b/test/Files_SerialIO/SerialIOTests.hpp @@ -8,3 +8,7 @@ namespace close_and_reopen_test { auto close_and_reopen_test() -> void; } +namespace issue_1744_unique_ptrs_at_close_time +{ +auto issue_1744_unique_ptrs_at_close_time() -> void; +} diff --git a/test/Files_SerialIO/issue_1744_unique_ptrs_at_close_time.cpp b/test/Files_SerialIO/issue_1744_unique_ptrs_at_close_time.cpp new file mode 100644 index 0000000000..51464e05f7 --- /dev/null +++ b/test/Files_SerialIO/issue_1744_unique_ptrs_at_close_time.cpp @@ -0,0 +1,33 @@ +#include "SerialIOTests.hpp" + +#include "openPMD/Dataset.hpp" +#include "openPMD/openPMD.hpp" + +#include +#include + +// clang-format off +/* + * Tests regression introduced with #1743: + * terminate called after throwing an instance of 'openPMD::error::Internal' + * what(): Internal error: [ADIOS2 backend] Orphaned unique-ptr put operations found when closing file. + * This is a bug. Please report at ' https://github.com/openPMD/openPMD-api/issues'. + */ +// clang-format on + +namespace issue_1744_unique_ptrs_at_close_time +{ +auto issue_1744_unique_ptrs_at_close_time() -> void +{ + openPMD::Series write( + "../samples/issue_1744_unique_ptrs_at_close_time.bp4", + openPMD::Access::CREATE, + R"({"iteration_encoding": "group_based"})"); + std::unique_ptr data_unique(new int[10]); + std::iota(data_unique.get(), data_unique.get() + 10, 0); + auto E_x = write.snapshots()[0].meshes["E"]["x"]; + E_x.resetDataset({openPMD::Datatype::INT, {10}}); + E_x.storeChunk(std::move(data_unique), {0}, {10}); + write.close(); +} +} // namespace issue_1744_unique_ptrs_at_close_time diff --git a/test/SerialIOTest.cpp b/test/SerialIOTest.cpp index b814eb0a9c..e3050ac7da 100644 --- a/test/SerialIOTest.cpp +++ b/test/SerialIOTest.cpp @@ -760,6 +760,14 @@ TEST_CASE("close_and_copy_attributable_test", "[serial]") } } +TEST_CASE("issue_1744_unique_ptrs_at_close_time", "[serial]") +{ +#if openPMD_HAVE_ADIOS2 + issue_1744_unique_ptrs_at_close_time:: + issue_1744_unique_ptrs_at_close_time(); +#endif +} + #if openPMD_HAVE_ADIOS2 TEST_CASE("close_and_reopen_test", "[serial]") {