Skip to content

Commit acf6265

Browse files
authored
Merge pull request #4351 from roystgnr/fix_terminate_segfault
Fix segfaults after terminate()
2 parents 069b1b5 + cd248fb commit acf6265

File tree

1 file changed

+50
-28
lines changed

1 file changed

+50
-28
lines changed

src/base/libmesh.C

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ void libmesh_handleSEGV(int /*signo*/, siginfo_t * info, void * /*context*/)
174174
<< " bt");
175175
}
176176
#endif
177-
}
177+
} // anonymous namespace
178178

179179

180180

@@ -278,6 +278,36 @@ void uninstall_thread_buffered_sync()
278278
}
279279
}
280280

281+
282+
/**
283+
* Helper to do cleanup from both destructor and terminate
284+
*/
285+
void cleanup_stream_buffers()
286+
{
287+
// Before resetting the stream buffers, let's remove our thread wrappers
288+
if (!libMesh::on_command_line ("--disable-thread-safe-output"))
289+
uninstall_thread_buffered_sync();
290+
291+
if (libMesh::on_command_line ("--redirect-stdout") ||
292+
libMesh::on_command_line ("--redirect-output"))
293+
{
294+
// If stdout/stderr were redirected to files, reset them now.
295+
libMesh::out.rdbuf (out_buf);
296+
libMesh::err.rdbuf (err_buf);
297+
}
298+
299+
// If we built our own output streams, we want to clean them up.
300+
if (libMesh::on_command_line ("--separate-libmeshout"))
301+
{
302+
delete libMesh::out.get();
303+
delete libMesh::err.get();
304+
305+
libMesh::out.reset(std::cout);
306+
libMesh::err.reset(std::cerr);
307+
}
308+
}
309+
310+
281311
bool warned_about_auto_ptr(false);
282312

283313
PerfLog perflog ("libMesh",
@@ -401,6 +431,11 @@ void libmesh_terminate_handler()
401431
libMesh::perflog.print_log();
402432
libMesh::perflog.clear();
403433

434+
// Now that we're done with output we should clean up our stream
435+
// buffers; if we fail to uninstall_thread_buffered_sync() when
436+
// needed we can end up seeing a segfault in iostreams destructors
437+
cleanup_stream_buffers();
438+
404439
// If we have MPI and it has been initialized, we need to be sure
405440
// and call MPI_Abort instead of std::abort, so that the parallel
406441
// job can die nicely.
@@ -794,14 +829,21 @@ LibMeshInit::LibMeshInit (int argc, const char * const * argv,
794829
LibMeshInit::~LibMeshInit()
795830
{
796831
// Every processor had better be ready to exit at the same time.
797-
// This would be a libmesh_parallel_only() function, except that
798-
// libmesh_parallel_only() uses libmesh_assert() which throws an
799-
// exception() which causes compilers to scream about exceptions
800-
// inside destructors.
801-
802832
// Even if we're not doing parallel_only debugging, we don't want
803833
// one processor to try to exit until all others are done working.
804-
this->comm().barrier();
834+
835+
// We could be destructing here because we're unwinding the stack
836+
// due to a thrown exception, though. It's possible that an
837+
// application is catching exceptions outside of the LibMeshInit
838+
// scope, or that we're using a C++ compiler that does unwinding
839+
// for uncaught exceptions (the standard says whether to go straight
840+
// to terminate() or unwind first is "implementation-defined"). If
841+
// *that* is the case then we can't safely communicate with other
842+
// processors that might not all be unwinding too.
843+
#ifdef LIBMESH_ENABLE_EXCEPTIONS
844+
if (!std::uncaught_exceptions())
845+
#endif
846+
this->comm().barrier();
805847

806848
// We can't delete, finalize, etc. more than once without
807849
// reinitializing in between
@@ -854,27 +896,7 @@ LibMeshInit::~LibMeshInit()
854896
// Set the initialized() flag to false
855897
libMeshPrivateData::_is_initialized = false;
856898

857-
// Before resetting the stream buffers, let's remove our thread wrappers
858-
if (!libMesh::on_command_line ("--disable-thread-safe-output"))
859-
uninstall_thread_buffered_sync();
860-
861-
if (libMesh::on_command_line ("--redirect-stdout") ||
862-
libMesh::on_command_line ("--redirect-output"))
863-
{
864-
// If stdout/stderr were redirected to files, reset them now.
865-
libMesh::out.rdbuf (out_buf);
866-
libMesh::err.rdbuf (err_buf);
867-
}
868-
869-
// If we built our own output streams, we want to clean them up.
870-
if (libMesh::on_command_line ("--separate-libmeshout"))
871-
{
872-
delete libMesh::out.get();
873-
delete libMesh::err.get();
874-
875-
libMesh::out.reset(std::cout);
876-
libMesh::err.reset(std::cerr);
877-
}
899+
cleanup_stream_buffers();
878900

879901
#ifdef LIBMESH_ENABLE_EXCEPTIONS
880902
// Reset the old terminate handler; maybe the user code wants to

0 commit comments

Comments
 (0)