From acd8ed50ea0e493e97a9e28a5b145ee287ace0a2 Mon Sep 17 00:00:00 2001 From: Giuseppe Ottaviano Date: Fri, 29 Jul 2016 14:24:41 -0700 Subject: [PATCH] Limit symbol length in demangle() Summary: GCC's `__cxa_demangle()` uses on-stack data structures for the parser state which are linear in the number of components of the symbol. For extremely long symbols, this can cause a stack overflow. This diff introduces an arbitrary symbol length limit above which we just return the mangled name. Reviewed By: philippv Differential Revision: D3641115 fbshipit-source-id: ec360bb20ca499fd0eaf3a06c5bbcbd1e936d845 --- folly/Demangle.cpp | 25 ++++++++++++++++++++++++ folly/test/DemangleTest.cpp | 38 ++++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/folly/Demangle.cpp b/folly/Demangle.cpp index 55a8f793..40187190 100644 --- a/folly/Demangle.cpp +++ b/folly/Demangle.cpp @@ -20,6 +20,7 @@ #include #include +#include #if FOLLY_HAVE_CPLUS_DEMANGLE_V3_CALLBACK # include @@ -60,6 +61,18 @@ namespace folly { #if FOLLY_HAVE_CPLUS_DEMANGLE_V3_CALLBACK fbstring demangle(const char* name) { +#ifdef FOLLY_DEMANGLE_MAX_SYMBOL_SIZE + // GCC's __cxa_demangle() uses on-stack data structures for the + // parser state which are linear in the number of components of the + // symbol. For extremely long symbols, this can cause a stack + // overflow. We set an arbitrary symbol length limit above which we + // just return the mangled name. + size_t mangledLen = strlen(name); + if (mangledLen > FOLLY_DEMANGLE_MAX_SYMBOL_SIZE) { + return fbstring(name, mangledLen); + } +#endif + int status; size_t len = 0; // malloc() memory for the demangled type name @@ -92,6 +105,18 @@ void demangleCallback(const char* str, size_t size, void* p) { } // namespace size_t demangle(const char* name, char* out, size_t outSize) { +#ifdef FOLLY_DEMANGLE_MAX_SYMBOL_SIZE + size_t mangledLen = strlen(name); + if (mangledLen > FOLLY_DEMANGLE_MAX_SYMBOL_SIZE) { + if (outSize) { + size_t n = std::min(mangledLen, outSize - 1); + memcpy(out, name, n); + out[n] = '\0'; + } + return mangledLen; + } +#endif + DemangleBuf dbuf; dbuf.dest = out; dbuf.remaining = outSize ? outSize - 1 : 0; // leave room for null term diff --git a/folly/test/DemangleTest.cpp b/folly/test/DemangleTest.cpp index 7436fff3..1316319f 100644 --- a/folly/test/DemangleTest.cpp +++ b/folly/test/DemangleTest.cpp @@ -45,7 +45,43 @@ TEST(Demangle, demangle) { EXPECT_STREQ("folly_test", buf); } } -#endif + +#if defined(FOLLY_DEMANGLE_MAX_SYMBOL_SIZE) +namespace { + +template +struct Node {}; + +template +struct LongSymbol { + using arg1 = typename LongSymbol::type; + using arg2 = typename LongSymbol::type; + using type = Node; +}; + +template +struct LongSymbol<0, I> { + using type = void; +}; + +} // namespace + +TEST(Demangle, LongSymbolFallback) { + // The symbol must be at least FOLLY_DEMANGLE_MAX_SYMBOL_SIZE long. + using Symbol = LongSymbol::type; + auto name = typeid(Symbol).name(); + + EXPECT_STREQ(name, demangle(name).c_str()); + + char buf[16]; + char expected[16]; + folly::demangle(name, buf, 16); + folly::strlcpy(expected, name, 16); + EXPECT_STREQ(expected, buf); +} +#endif // defined(FOLLY_DEMANGLE_MAX_SYMBOL_SIZE) + +#endif // FOLLY_HAVE_CPLUS_DEMANGLE_V3_CALLBACK TEST(Demangle, strlcpy) { char buf[6]; -- 2.34.1