diff options
author | Benjamin Kramer <benny.kra@googlemail.com> | 2010-06-22 15:28:29 +0000 |
---|---|---|
committer | Benjamin Kramer <benny.kra@googlemail.com> | 2010-06-22 15:28:29 +0000 |
commit | 53a61dc531d19ff4576e4933f96da6478d417b36 (patch) | |
tree | e3bad5543f1562855ab17d369b0ecad87dd565dd /lldb/source/Core/Mangled.cpp | |
parent | 3986af0c5a09d7daa9b4dad537832cc627ef4c2b (diff) | |
download | bcm5719-llvm-53a61dc531d19ff4576e4933f96da6478d417b36.tar.gz bcm5719-llvm-53a61dc531d19ff4576e4933f96da6478d417b36.zip |
Ensure GetDemangledName's thread safety by making the demangle buffer thread specific.
I'm not sure when multiple threads enter this method but a race-condition
causing a crash in malloc can be reproduced with this little script:
echo file $(which lldb) > cmd
echo "run\nbreak set -n main\nrun\nexit" >> cmd
lldb -s cmd
It may need a few runs before it crashes though.
llvm-svn: 106544
Diffstat (limited to 'lldb/source/Core/Mangled.cpp')
-rw-r--r-- | lldb/source/Core/Mangled.cpp | 66 |
1 files changed, 54 insertions, 12 deletions
diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp index 95cbe382892..cb4335bb6aa 100644 --- a/lldb/source/Core/Mangled.cpp +++ b/lldb/source/Core/Mangled.cpp @@ -118,6 +118,40 @@ Mangled::SetValue (const char *s, bool mangled) } } +namespace +{ + //------------------------------------------------------------------ + // Convenience wrapper for __cxa_demangle. + //------------------------------------------------------------------ + class DemangleBuffer + { + char *m_demangle_buf; + size_t m_demangle_buf_len; + public: + DemangleBuffer () : m_demangle_buf (NULL), m_demangle_buf_len (0) {} + ~DemangleBuffer () + { + free (m_demangle_buf); + } + int Demangle (const char *mangled) + { + int status = 0; + m_demangle_buf = abi::__cxa_demangle(mangled, m_demangle_buf, + &m_demangle_buf_len, &status); + return status; + } + const char *GetBuffer () const { return m_demangle_buf; } + size_t GetLength () const { return m_demangle_buf_len; } + }; +} + +//---------------------------------------------------------------------- +// Used to delete the thread specific buffer when the thread exits. +//---------------------------------------------------------------------- +static void FreeDemangleBuffer (void *buf) +{ + delete static_cast<DemangleBuffer*> (buf); +} //---------------------------------------------------------------------- // Generate the demangled name on demand using this accessor. Code in @@ -147,19 +181,27 @@ Mangled::GetDemangledName () const // return a buffer value and length and we will continue to // re-use that buffer so we don't always have to malloc/free // a buffer for each demangle. The buffer can be realloc'ed - // by abi::__cxa_demangle, so we may need to make it thread - // specific if we ever start doing multi-threaded calls to - // this function. g_demangle_buf will currently leak one - // malloc entry that can vary in size. If we need to reclaim - // this memory, we will need to add some code to free this - // buffer at exit time. - static char *g_demangle_buf = NULL; - static size_t g_demangle_buf_len = 0; - int status = 0; - g_demangle_buf = abi::__cxa_demangle(mangled, g_demangle_buf, &g_demangle_buf_len, &status); - if (g_demangle_buf != NULL) + // by abi::__cxa_demangle, so we need to make it thread + // specific. + + // Set up thread specific storage. + static pthread_key_t g_demangle_key = 0; + if (!g_demangle_key) + ::pthread_key_create (&g_demangle_key, FreeDemangleBuffer); + + DemangleBuffer *buf = static_cast<DemangleBuffer*> ( + ::pthread_getspecific (g_demangle_key)); + if (!buf) // No buffer for this thread, create a new one. + { + buf = new DemangleBuffer (); + ::pthread_setspecific (g_demangle_key, buf); + } + + int status = buf->Demangle (mangled); + if (status == 0) { - m_demangled.SetCString(g_demangle_buf); + m_demangled.SetCStringWithLength(buf->GetBuffer(), + buf->GetLength()); } else { |