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 <simon@rozman.si>
This commit is contained in:
Simon Rozman 2025-03-06 22:09:50 +01:00
parent 69f2c639cd
commit bfd8aaff65
3 changed files with 33 additions and 25 deletions

View File

@ -86,7 +86,7 @@ namespace stdex
public: public:
basic(_In_ state_t state = state_t::ok) : m_state(state) {} basic(_In_ state_t state = state_t::ok) : m_state(state) {}
virtual ~basic() noexcept(false) {} virtual ~basic() {}
/// ///
/// Reads block of data from the stream /// Reads block of data from the stream
@ -1852,17 +1852,20 @@ namespace stdex
#endif #endif
{} {}
virtual ~cache() noexcept(false) virtual ~cache()
{ {
if (m_source) { if (m_source) {
flush_cache(); try {
if (!ok()) _Unlikely_ flush_cache();
throw std::system_error(sys_error(), std::system_category(), "failed to flush cache"); // Data loss occurred if (!ok()) _Unlikely_
m_source->seekbeg(m_offset); 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 #if SET_FILE_OP_TIMES
m_source->set_atime(m_atime); m_source->set_atime(m_atime);
m_source->set_mtime(m_mtime); m_source->set_mtime(m_mtime);
#endif #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?
} }
} }

View File

@ -171,10 +171,12 @@ namespace stdex
return *this; return *this;
} }
virtual ~basic_sys_object() noexcept(false) virtual ~basic_sys_object()
{ {
if (m_h != TR::invalid_handle) if (m_h != TR::invalid_handle) {
TR::close(m_h); try { TR::close(m_h); }
catch (...) {} // Failure to close a handle should not be that devastating as throwing in a destructor may be.
}
} }
/// ///

View File

@ -61,20 +61,23 @@ namespace stdex
virtual ~zlib_writer() virtual ~zlib_writer()
{ {
m_zlib.avail_in = 0; try {
m_zlib.next_in = NULL; m_zlib.avail_in = 0;
do { m_zlib.next_in = NULL;
m_zlib.avail_out = m_block_size; do {
m_zlib.next_out = m_block.get(); m_zlib.avail_out = m_block_size;
throw_on_zlib_error(deflate(&m_zlib, Z_FINISH)); m_zlib.next_out = m_block.get();
m_source->write(m_block.get(), m_block_size - m_zlib.avail_out); throw_on_zlib_error(deflate(&m_zlib, Z_FINISH));
if (!m_source->ok()) _Unlikely_ m_source->write(m_block.get(), m_block_size - m_zlib.avail_out);
throw std::system_error(sys_error(), std::system_category(), "failed to flush compressed stream"); // Data loss occured if (!m_source->ok()) _Unlikely_
} while (m_zlib.avail_out == 0); throw std::system_error(sys_error(), std::system_category(), "failed to flush compressed stream"); // Data loss occured
// m_zlib.avail_out = m_block_size; } while (m_zlib.avail_out == 0);
// m_zlib.next_out = m_block.get(); // m_zlib.avail_out = m_block_size;
// deflateReset(&m_zlib); // m_zlib.next_out = m_block.get();
deflateEnd(&m_zlib); // 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( virtual _Success_(return != 0) size_t write(