Skip to content
Snippets Groups Projects
Commit db1d39e8 authored by Walter Lampl's avatar Walter Lampl
Browse files

Merge branch 'exctrace.CxxUtils-20210327' into 'master'

CxxUtils: Make exctrace properly MT-safe.

See merge request atlas/athena!42072
parents 7559f12c 658bf04d
No related branches found
No related tags found
No related merge requests found
/* /*
Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
*/ */
/** /**
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
//# include "SealBase/Macros.h" wlav //# include "SealBase/Macros.h" wlav
//# include "SealBase/sysapi/IOTypes.h" wlav //# include "SealBase/sysapi/IOTypes.h" wlav
# include <cstddef> # include <cstddef>
# include <atomic>
// wlav copied from SealBase/sysapi/DebugAids.h // wlav copied from SealBase/sysapi/DebugAids.h
// Windows doesn't have this, so fake a suitable substitute // Windows doesn't have this, so fake a suitable substitute
...@@ -60,7 +61,7 @@ class DebugAids ...@@ -60,7 +61,7 @@ class DebugAids
{ {
public: public:
// Miscellaneous functions // Miscellaneous functions
static IOFD stacktraceFd ATLAS_NOT_THREAD_SAFE (IOFD fd = IOFD_INVALID); static IOFD stacktraceFd (IOFD fd = IOFD_INVALID);
static void stacktrace ATLAS_NOT_THREAD_SAFE (IOFD fd = IOFD_INVALID); static void stacktrace ATLAS_NOT_THREAD_SAFE (IOFD fd = IOFD_INVALID);
static void coredump (int sig, ...); static void coredump (int sig, ...);
// sss // sss
...@@ -69,7 +70,7 @@ public: ...@@ -69,7 +70,7 @@ public:
static void setStackTraceAddr2Line ATLAS_NOT_THREAD_SAFE (const char* path); static void setStackTraceAddr2Line ATLAS_NOT_THREAD_SAFE (const char* path);
private: private:
static IOFD s_stackTraceFd; static std::atomic<IOFD> s_stackTraceFd;
}; };
//<<<<<< PUBLIC FUNCTIONS >>>>>> //<<<<<< PUBLIC FUNCTIONS >>>>>>
......
// This file's extension implies that it's C, but it's really -*- C++ -*-. // This file's extension implies that it's C, but it's really -*- C++ -*-.
/* /*
Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
*/ */
// $Id$
/** /**
* @file CxxUtils/exctrace.h * @file CxxUtils/exctrace.h
* @author scott snyder <snyder@bnl.gov> * @author scott snyder <snyder@bnl.gov>
...@@ -44,7 +43,7 @@ namespace CxxUtils { ...@@ -44,7 +43,7 @@ namespace CxxUtils {
* @param e The exception to print. * @param e The exception to print.
* @param fd The file descriptor to which to write. * @param fd The file descriptor to which to write.
*/ */
void exctrace ATLAS_NOT_THREAD_SAFE (const std::exception& e, IOFD fd = IOFD_INVALID); void exctrace (const std::exception& e, IOFD fd = IOFD_INVALID);
} // namespace CxxUtils } // namespace CxxUtils
......
...@@ -243,7 +243,7 @@ namespace Athena { // wlav ...@@ -243,7 +243,7 @@ namespace Athena { // wlav
//<<<<<< CLASS STRUCTURE INITIALIZATION >>>>>> //<<<<<< CLASS STRUCTURE INITIALIZATION >>>>>>
/** The default output file descriptor for #stacktrace(). */ /** The default output file descriptor for #stacktrace(). */
IOFD DebugAids::s_stackTraceFd = IOFD_INVALID; std::atomic<IOFD> DebugAids::s_stackTraceFd = IOFD_INVALID;
//<<<<<< PRIVATE FUNCTION DEFINITIONS >>>>>> //<<<<<< PRIVATE FUNCTION DEFINITIONS >>>>>>
...@@ -578,15 +578,19 @@ extern "C" void xl__trbk (void); ...@@ -578,15 +578,19 @@ extern "C" void xl__trbk (void);
effective for #stacktrace(), but can be overridden by the effective for #stacktrace(), but can be overridden by the
argument given to that function. */ argument given to that function. */
IOFD IOFD
DebugAids::stacktraceFd ATLAS_NOT_THREAD_SAFE (IOFD fd /* = IOFD_INVALID */) DebugAids::stacktraceFd (IOFD fd /* = IOFD_INVALID */)
{ {
if (s_stackTraceFd == IOFD_INVALID) IOFD old = s_stackTraceFd;
s_stackTraceFd = STDERR_HANDLE; if (fd == IOFD_INVALID) {
if (old == IOFD_INVALID) {
IOFD old = s_stackTraceFd; s_stackTraceFd.compare_exchange_strong (old, STDERR_HANDLE);
if (fd != IOFD_INVALID) return s_stackTraceFd;
s_stackTraceFd = fd; }
return old; }
else {
s_stackTraceFd.compare_exchange_strong (old, fd);
}
return old;
} }
/** Produce a stack trace. /** Produce a stack trace.
...@@ -606,11 +610,8 @@ DebugAids::stacktraceFd ATLAS_NOT_THREAD_SAFE (IOFD fd /* = IOFD_INVALID */) ...@@ -606,11 +610,8 @@ DebugAids::stacktraceFd ATLAS_NOT_THREAD_SAFE (IOFD fd /* = IOFD_INVALID */)
void void
DebugAids::stacktrace ATLAS_NOT_THREAD_SAFE (IOFD fd /* = IOFD_INVALID */) DebugAids::stacktrace ATLAS_NOT_THREAD_SAFE (IOFD fd /* = IOFD_INVALID */)
{ {
if (s_stackTraceFd == IOFD_INVALID)
s_stackTraceFd = STDERR_HANDLE;
if (fd == IOFD_INVALID) if (fd == IOFD_INVALID)
fd = s_stackTraceFd; fd = stacktraceFd();
std::cerr.flush (); std::cerr.flush ();
fflush (stderr); fflush (stderr);
......
/* /*
Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
*/ */
// $Id$
/** /**
* @file CxxUtils/src/exctrace.cxx * @file CxxUtils/src/exctrace.cxx
* @author scott snyder <snyder@bnl.gov> * @author scott snyder <snyder@bnl.gov>
...@@ -17,9 +16,11 @@ ...@@ -17,9 +16,11 @@
#include "CxxUtils/exctrace.h" #include "CxxUtils/exctrace.h"
#include "CxxUtils/checker_macros.h"
#include <cstring> #include <cstring>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <iterator>
#include <execinfo.h> #include <execinfo.h>
#include <unistd.h> #include <unistd.h>
#include <dlfcn.h> #include <dlfcn.h>
...@@ -34,6 +35,15 @@ using std::free; ...@@ -34,6 +35,15 @@ using std::free;
# define MYWRITELIT(fd,str) MYWRITE(fd,str,sizeof(str)-1) # define MYWRITELIT(fd,str) MYWRITE(fd,str,sizeof(str)-1)
namespace {
bool stacktraceLine ATLAS_NOT_THREAD_SAFE (IOFD fd, unsigned long addr)
{
Athena::DebugAids::stacktraceLine (fd, addr);
return false;
}
}
namespace CxxUtils { namespace CxxUtils {
...@@ -46,37 +56,40 @@ namespace CxxUtils { ...@@ -46,37 +56,40 @@ namespace CxxUtils {
* @param e The exception to print. * @param e The exception to print.
* @param fd The file descriptor to which to write. * @param fd The file descriptor to which to write.
*/ */
void exctrace ATLAS_NOT_THREAD_SAFE (const std::exception& e, IOFD fd /*= IOFD_INVALID*/) void exctrace (const std::exception& e, IOFD fd /*= IOFD_INVALID*/)
{ {
if (fd == IOFD_INVALID) if (fd == IOFD_INVALID)
fd = Athena::DebugAids::stacktraceFd(); fd = Athena::DebugAids::stacktraceFd();
static bool init = false; typedef int (*get_last_trace_fn) (int max_depth, void* trace[]);
static int* exctrace_last_depth = 0; get_last_trace_fn get_last_trace = (get_last_trace_fn) dlsym (RTLD_DEFAULT, "exctrace_get_last_trace");
static void** exctrace_last_trace = 0;
if (!init) {
init = true;
exctrace_last_depth = (int*)dlsym (RTLD_DEFAULT, "exctrace_last_depth");
exctrace_last_trace = (void**)dlsym (RTLD_DEFAULT, "exctrace_last_trace");
}
MYWRITELIT(fd, "Exception: "); MYWRITELIT(fd, "Exception: ");
MYWRITE(fd, e.what(), strlen (e.what())); MYWRITE(fd, e.what(), strlen (e.what()));
if (exctrace_last_depth && exctrace_last_trace) { if (get_last_trace) {
void* trace[100];
int depth = get_last_trace (std::end(trace)-std::begin(trace), trace);
MYWRITELIT(fd, "\n"); MYWRITELIT(fd, "\n");
// Index 0 is __cxa_throw. Skip it. // Index 0 is __cxa_throw. Skip it.
for (int i = 1; i < *exctrace_last_depth; ++i) { for (int i = 1; i < depth; ++i) {
unsigned long ip = unsigned long ip =
reinterpret_cast<unsigned long> (exctrace_last_trace[i]); reinterpret_cast<unsigned long> (trace[i]);
// A function that throws may have the call to __cxa_throw // A function that throws may have the call to __cxa_throw
// as the last instruction in the function. In that case, the IP // as the last instruction in the function. In that case, the IP
// we see here will be one beyond the end of the function, // we see here will be one beyond the end of the function,
// and we'll report the wrong function. So move back the IP // and we'll report the wrong function. So move back the IP
// slightly for the function that threw. // slightly for the function that threw.
if (i == 1) --ip; if (i == 1) --ip;
Athena::DebugAids::stacktraceLine (fd, ip);
// It's true that stacktraceLine is not really thread-safe.
// However, if we're here, things are going south fast anyway,
// so we'll just cross our fingers and try to shovel out as much
// information as we can.
[[maybe_unused]]
bool dum ATLAS_THREAD_SAFE = stacktraceLine (fd, ip);
} }
} }
else else
......
/* /*
Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
*/ */
// $Id$
/** /**
* @file CxxUtils/src/exctrace/exctrace_collector.cxx * @file CxxUtils/src/exctrace/exctrace_collector.cxx
* @author scott snyder <snyder@bnl.gov> * @author scott snyder <snyder@bnl.gov>
...@@ -21,6 +19,8 @@ ...@@ -21,6 +19,8 @@
#include <execinfo.h> #include <execinfo.h>
#include <cstdio> #include <cstdio>
#include <typeinfo> #include <typeinfo>
#include <utility>
#include <algorithm>
#include "CxxUtils/checker_macros.h" #include "CxxUtils/checker_macros.h"
// Maximum stack depth. // Maximum stack depth.
...@@ -28,13 +28,24 @@ static ...@@ -28,13 +28,24 @@ static
const int bt_depth = 100; const int bt_depth = 100;
// Static buffer used to save the backtrace. // Static buffer used to save the backtrace.
int exctrace_last_depth = 0; static thread_local int exctrace_last_depth = 0;
void* exctrace_last_trace[bt_depth]; static thread_local void* exctrace_last_trace[bt_depth];
// The real __cxa_throw function. // The real __cxa_throw function.
typedef void throwfn (void*, std::type_info*, void (*dest)(void*)); typedef void throwfn (void*, std::type_info*, void (*dest)(void*));
static throwfn* old_throw; static throwfn* old_throw;
extern "C" {
// Function to retrieve the last trace.
// extern "C" because we want to find it with dlsym.
int exctrace_get_last_trace (int max_depth, void* trace[])
{
int ncopy = std::min (exctrace_last_depth, max_depth);
std::copy (exctrace_last_trace, exctrace_last_trace+ncopy, trace);
return ncopy;
}
}
// The __cxa_throw hook function. // The __cxa_throw hook function.
// Record a backtrace, then chain to the real throw function. // Record a backtrace, then chain to the real throw function.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment