Commit 35dc92a7 authored by Tudor Bosman's avatar Tudor Bosman Committed by Jordan DeLong

Add async-signal-safe flavor of demangle

Summary: To be used in the new fatal signal handler.

Test Plan: test added

Reviewed By: lucian@fb.com

FB internal diff: D1076169

@override-unit-failures
parent 25b8374a
...@@ -25,9 +25,27 @@ ...@@ -25,9 +25,27 @@
#include <glog/logging.h> #include <glog/logging.h>
#undef FOLLY_DEMANGLE #undef FOLLY_DEMANGLE
#if defined(__GNUG__) && __GNUG__ >= 4 #if defined(__GNUG__) && __GNUG__ >= 4
# include <cxxabi.h> # include <cxxabi.h>
# define FOLLY_DEMANGLE 1 # define FOLLY_DEMANGLE 1
// From libiberty
//
// TODO(tudorb): Detect this with autoconf for the open-source version.
//
// __attribute__((weak)) doesn't work, because cplus_demangle_v3_callback
// is exported by an object file in libiberty.a, and the ELF spec says
// "The link editor does not extract archive members to resolve undefined weak
// symbols" (but, interestingly enough, will resolve undefined weak symbols
// with definitions from archive members that were extracted in order to
// resolve an undefined global (strong) symbol)
extern "C" int cplus_demangle_v3_callback(
const char* mangled,
int options, // We use DMGL_PARAMS | DMGL_TYPES, aka 0x11
void (*callback)(const char*, size_t, void*),
void* arg);
#endif #endif
namespace folly { namespace folly {
...@@ -264,6 +282,21 @@ fbstring errnoStr(int err) { ...@@ -264,6 +282,21 @@ fbstring errnoStr(int err) {
return result; return result;
} }
namespace {
// glibc doesn't have strlcpy
size_t my_strlcpy(char* dest, const char* src, size_t size) {
size_t len = strlen(src);
if (size != 0) {
size_t n = std::min(len, size - 1); // always null terminate!
memcpy(dest, src, n);
dest[n] = '\0';
}
return len;
}
} // namespace
#ifdef FOLLY_DEMANGLE #ifdef FOLLY_DEMANGLE
fbstring demangle(const char* name) { fbstring demangle(const char* name) {
...@@ -279,12 +312,56 @@ fbstring demangle(const char* name) { ...@@ -279,12 +312,56 @@ fbstring demangle(const char* name) {
return fbstring(demangled, strlen(demangled), len, AcquireMallocatedString()); return fbstring(demangled, strlen(demangled), len, AcquireMallocatedString());
} }
namespace {
struct DemangleBuf {
char* dest;
size_t remaining;
size_t total;
};
void demangleCallback(const char* str, size_t size, void* p) {
DemangleBuf* buf = static_cast<DemangleBuf*>(p);
size_t n = std::min(buf->remaining, size);
memcpy(buf->dest, str, n);
buf->dest += n;
buf->remaining -= n;
buf->total += size;
}
} // namespace
size_t demangle(const char* name, char* out, size_t outSize) {
DemangleBuf dbuf;
dbuf.dest = out;
dbuf.remaining = outSize ? outSize - 1 : 0; // leave room for null term
dbuf.total = 0;
// Unlike most library functions, this returns 1 on success and 0 on failure
int status = cplus_demangle_v3_callback(
name,
0x11, // DMGL_PARAMS | DMGL_TYPES
demangleCallback,
&dbuf);
if (status == 0) { // failed, return original
return my_strlcpy(out, name, outSize);
}
if (outSize != 0) {
*dbuf.dest = '\0';
}
return dbuf.total;
}
#else #else
fbstring demangle(const char* name) { fbstring demangle(const char* name) {
return name; return name;
} }
size_t demangle(const char* name, char* out, size_t outSize) {
return my_strlcpy(out, name, outSize);
}
#endif #endif
#undef FOLLY_DEMANGLE #undef FOLLY_DEMANGLE
......
...@@ -322,13 +322,36 @@ fbstring errnoStr(int err); ...@@ -322,13 +322,36 @@ fbstring errnoStr(int err);
* *
* Use for debugging -- do not rely on demangle() returning anything useful. * Use for debugging -- do not rely on demangle() returning anything useful.
* *
* This function may allocate memory (and therefore throw). * This function may allocate memory (and therefore throw std::bad_alloc).
*/ */
fbstring demangle(const char* name); fbstring demangle(const char* name);
inline fbstring demangle(const std::type_info& type) { inline fbstring demangle(const std::type_info& type) {
return demangle(type.name()); return demangle(type.name());
} }
/**
* Return the demangled (prettyfied) version of a C++ type in a user-provided
* buffer.
*
* The semantics are the same as for snprintf or strlcpy: bufSize is the size
* of the buffer, the string is always null-terminated, and the return value is
* the number of characters (not including the null terminator) that would have
* been written if the buffer was big enough. (So a return value >= bufSize
* indicates that the output was truncated)
*
* This function does not allocate memory and is async-signal-safe.
*
* Note that the underlying function for the fbstring-returning demangle is
* somewhat standard (abi::__cxa_demangle, which uses malloc), the underlying
* function for this version is less so (cplus_demangle_v3_callback from
* libiberty), so it is possible for the fbstring version to work, while this
* version returns the original, mangled name.
*/
size_t demangle(const char* name, char* buf, size_t bufSize);
inline size_t demangle(const std::type_info& type, char* buf, size_t bufSize) {
return demangle(type.name(), buf, bufSize);
}
/** /**
* Debug string for an exception: include type and what(). * Debug string for an exception: include type and what().
*/ */
......
...@@ -464,8 +464,23 @@ struct ThisIsAVeryLongStructureName { ...@@ -464,8 +464,23 @@ struct ThisIsAVeryLongStructureName {
} // namespace folly_test } // namespace folly_test
TEST(System, demangle) { TEST(System, demangle) {
EXPECT_EQ("folly_test::ThisIsAVeryLongStructureName", char expected[] = "folly_test::ThisIsAVeryLongStructureName";
demangle(typeid(folly_test::ThisIsAVeryLongStructureName))); EXPECT_STREQ(
expected,
demangle(typeid(folly_test::ThisIsAVeryLongStructureName)).c_str());
{
char buf[sizeof(expected)];
EXPECT_EQ(sizeof(expected) - 1,
demangle(typeid(folly_test::ThisIsAVeryLongStructureName),
buf, sizeof(buf)));
EXPECT_STREQ(expected, buf);
EXPECT_EQ(sizeof(expected) - 1,
demangle(typeid(folly_test::ThisIsAVeryLongStructureName),
buf, 11));
EXPECT_STREQ("folly_test", buf);
}
} }
namespace { namespace {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment