From 644f0e98ec68f4392ced80fad9502dbf3811c75b Mon Sep 17 00:00:00 2001 From: Zoltan Martonka Date: Wed, 30 Oct 2024 11:21:16 +0100 Subject: [PATCH] Fix null terminator in Demangle function. If the demangled name is longer than out_size, the null terminator is missing from the output. This will cause a crash in the DemangleInplace() function (symbolize.cc) when calling strlen on the buffer. --- src/demangle.cc | 8 +++++++- src/symbolize_unittest.cc | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/demangle.cc b/src/demangle.cc index 9902c1e..a0578e4 100644 --- a/src/demangle.cc +++ b/src/demangle.cc @@ -1350,7 +1350,13 @@ bool Demangle(const char* mangled, char* out, size_t out_size) { return false; } - std::copy_n(unmangled.get(), std::min(n, out_size), out); + if (out_size > 0) { + // n is the size of the allocated buffer, not the length of the string. + // Therefore, it includes the terminating zero (and possibly additional space). + std::size_t copy_size = std::min(n-1, out_size - 1); + std::copy_n(unmangled.get(), copy_size, out); + out[copy_size] = '\0'; // Ensure terminating null if n > out_size + } return status == 0; #else State state; diff --git a/src/symbolize_unittest.cc b/src/symbolize_unittest.cc index f07484e..d0e3c05 100644 --- a/src/symbolize_unittest.cc +++ b/src/symbolize_unittest.cc @@ -34,7 +34,11 @@ #include "symbolize.h" #include +#include #include +#include +#include + #include "config.h" #include "glog/logging.h" @@ -133,6 +137,18 @@ TEST(Symbolize, Symbolize) { struct Foo { static void func(int x); + static size_t longParamFunc( + std::map,std::map > p0, + std::map,std::map > p1, + std::map,std::map > p2, + std::map,std::map > p3, + std::map,std::map > p4, + std::map,std::map > p5, + std::map,std::map > p6, + std::map,std::map > p7, + std::map,std::map > p8, + std::map,std::map > p9 + ); }; void ATTRIBUTE_NOINLINE Foo::func(int x) { @@ -142,6 +158,21 @@ void ATTRIBUTE_NOINLINE Foo::func(int x) { a = a + 1; } +size_t ATTRIBUTE_NOINLINE Foo::longParamFunc( + std::map,std::map > p0, + std::map,std::map > p1, + std::map,std::map > p2, + std::map,std::map > p3, + std::map,std::map > p4, + std::map,std::map > p5, + std::map,std::map > p6, + std::map,std::map > p7, + std::map,std::map > p8, + std::map,std::map > p9 + ) { + return p0.size() + p1.size() + p2.size() + p3.size() + p4.size() + p5.size() + p6.size() + p7.size() + p8.size() + p9.size(); +} + // With a modern GCC, Symbolize() should return demangled symbol // names. Function parameters should be omitted. # ifdef TEST_WITH_MODERN_GCC @@ -150,6 +181,10 @@ TEST(Symbolize, SymbolizeWithDemangling) { # if !defined(_MSC_VER) || !defined(NDEBUG) # if defined(HAVE___CXA_DEMANGLE) EXPECT_STREQ("Foo::func(int)", TrySymbolize((void*)(&Foo::func))); + // Very long functions can be truncated, but we should not crash or return null. + // Also the result should start properly. + const char* symbol = TrySymbolize((void*)(&Foo::longParamFunc)); + EXPECT_TRUE(symbol == std::strstr(symbol, "Foo::longParamFunc(")); # else EXPECT_STREQ("Foo::func()", TrySymbolize((void*)(&Foo::func))); # endif