From bfd8aaff653cedda07e4b249c8bee88911660b0e Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Thu, 6 Mar 2025 22:09:50 +0100 Subject: [PATCH] Stop throwing in destructors When exception processing is unwinding the stack, any exception thrown in destructors end up std::terminate()-in our process. Since all workarounds to report errors from destructors seems an overkill, and the only important place where we should notify the user about a failure is the stdex::stream::cache::~cache() (data loss occurs when failure happens here), and if we'd throw in stdex::stream::cache:: ~cache(), our process would get terminated anyway so the data loss is inevitable, let's just silence this for now and come up with a better solution later if we get smarter anytime in the future. Signed-off-by: Simon Rozman --- include/stdex/stream.hpp | 19 +++++++++++-------- include/stdex/system.hpp | 8 +++++--- include/stdex/zlib.hpp | 31 +++++++++++++++++-------------- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/include/stdex/stream.hpp b/include/stdex/stream.hpp index 880df1896..1f8cd3151 100644 --- a/include/stdex/stream.hpp +++ b/include/stdex/stream.hpp @@ -86,7 +86,7 @@ namespace stdex public: basic(_In_ state_t state = state_t::ok) : m_state(state) {} - virtual ~basic() noexcept(false) {} + virtual ~basic() {} /// /// Reads block of data from the stream @@ -1852,17 +1852,20 @@ namespace stdex #endif {} - virtual ~cache() noexcept(false) + virtual ~cache() { if (m_source) { - flush_cache(); - if (!ok()) _Unlikely_ - throw std::system_error(sys_error(), std::system_category(), "failed to flush cache"); // Data loss occurred - m_source->seekbeg(m_offset); + try { + flush_cache(); + if (!ok()) _Unlikely_ + throw std::system_error(sys_error(), std::system_category(), "failed to flush cache"); // Data loss occurred + m_source->seekbeg(m_offset); #if SET_FILE_OP_TIMES - m_source->set_atime(m_atime); - m_source->set_mtime(m_mtime); + m_source->set_atime(m_atime); + m_source->set_mtime(m_mtime); #endif + } + catch (...) {} // TODO: Never throw in destructors. If we'd throw here exception stack unwinding would std::terminate() our process anyway. Is there a way to catch this? } } diff --git a/include/stdex/system.hpp b/include/stdex/system.hpp index fd00ab414..a8da26f54 100644 --- a/include/stdex/system.hpp +++ b/include/stdex/system.hpp @@ -171,10 +171,12 @@ namespace stdex return *this; } - virtual ~basic_sys_object() noexcept(false) + virtual ~basic_sys_object() { - if (m_h != TR::invalid_handle) - TR::close(m_h); + if (m_h != TR::invalid_handle) { + try { TR::close(m_h); } + catch (...) {} // Failure to close a handle should not be that devastating as throwing in a destructor may be. + } } /// diff --git a/include/stdex/zlib.hpp b/include/stdex/zlib.hpp index 3f6df3698..adc8c4536 100644 --- a/include/stdex/zlib.hpp +++ b/include/stdex/zlib.hpp @@ -61,20 +61,23 @@ namespace stdex virtual ~zlib_writer() { - m_zlib.avail_in = 0; - m_zlib.next_in = NULL; - do { - m_zlib.avail_out = m_block_size; - m_zlib.next_out = m_block.get(); - throw_on_zlib_error(deflate(&m_zlib, Z_FINISH)); - m_source->write(m_block.get(), m_block_size - m_zlib.avail_out); - if (!m_source->ok()) _Unlikely_ - throw std::system_error(sys_error(), std::system_category(), "failed to flush compressed stream"); // Data loss occured - } while (m_zlib.avail_out == 0); - // m_zlib.avail_out = m_block_size; - // m_zlib.next_out = m_block.get(); - // deflateReset(&m_zlib); - deflateEnd(&m_zlib); + try { + m_zlib.avail_in = 0; + m_zlib.next_in = NULL; + do { + m_zlib.avail_out = m_block_size; + m_zlib.next_out = m_block.get(); + throw_on_zlib_error(deflate(&m_zlib, Z_FINISH)); + m_source->write(m_block.get(), m_block_size - m_zlib.avail_out); + if (!m_source->ok()) _Unlikely_ + throw std::system_error(sys_error(), std::system_category(), "failed to flush compressed stream"); // Data loss occured + } while (m_zlib.avail_out == 0); + // m_zlib.avail_out = m_block_size; + // m_zlib.next_out = m_block.get(); + // deflateReset(&m_zlib); + deflateEnd(&m_zlib); + } + catch (...) {} // TODO: Never throw in destructors. If we'd throw here exception stack unwinding would std::terminate() our process anyway. Is there a way to catch this? } virtual _Success_(return != 0) size_t write(