From 93787182312884cedf0d59b4c7a2bd7639581b17 Mon Sep 17 00:00:00 2001 From: Joshua Kriegshauser Date: Mon, 23 Sep 2024 12:00:39 -0700 Subject: [PATCH] Safe copy --- public/client/TracyProfiler.cpp | 37 +++++++++++++--- public/client/TracyProfiler.hpp | 77 +++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 7 deletions(-) diff --git a/public/client/TracyProfiler.cpp b/public/client/TracyProfiler.cpp index bb0ca7c8..f7ad5c6b 100644 --- a/public/client/TracyProfiler.cpp +++ b/public/client/TracyProfiler.cpp @@ -111,6 +111,7 @@ extern "C" typedef char* (WINAPI *t_WineGetBuildId)(); #else # include # include +# include #endif #if defined __linux__ # include @@ -1462,6 +1463,22 @@ Profiler::Profiler() m_userPort = atoi( userPort ); } + m_safeSendBufferSize = 65536; + m_safeSendBuffer = (char*)tracy_malloc( m_safeSendBufferSize ); + +#ifndef _WIN32 + pipe(m_pipe); +# if defined __APPLE__ || defined BSD + // FreeBSD/XNU don't have F_SETPIPE_SZ, so use the default + m_pipeBufSize = 16384; +# else + m_pipeBufSize = (int)(ptrdiff_t)m_safeSendBufferSize; + while( fcntl( m_pipe[0], F_SETPIPE_SZ, m_pipeBufSize ) == -1 && errno == EPERM ) + m_pipeBufSize /= 2; // too big; reduce + m_pipeBufSize = fcntl( m_pipe[0], F_GETPIPE_SZ ); +# endif +#endif + #if !defined(TRACY_DELAYED_INIT) || !defined(TRACY_MANUAL_LIFETIME) SpawnWorkerThreads(); #endif @@ -1487,7 +1504,7 @@ void Profiler::InstallCrashHandler() #endif #if defined _WIN32 && !defined TRACY_UWP && !defined TRACY_NO_CRASH_HANDLER - m_exceptionHandler = AddVectoredExceptionHandler( 1, CrashFilter ); + m_exceptionHandler = AddVectoredExceptionHandler( 0, CrashFilter ); #endif #ifndef TRACY_NO_CRASH_HANDLER @@ -1600,6 +1617,12 @@ Profiler::~Profiler() tracy_free( m_kcore ); #endif +#ifndef _WIN32 + close( m_pipe[0] ); + close( m_pipe[1] ); +#endif + tracy_free( m_safeSendBuffer ); + tracy_free( m_lz4Buf ); tracy_free( m_buffer ); LZ4_freeStream( (LZ4_stream_t*)m_stream ); @@ -4017,13 +4040,13 @@ void Profiler::HandleSymbolCodeQuery( uint64_t symbol, uint32_t size ) } else { - if( !EnsureReadable( symbol ) ) - { - AckSymbolCodeNotAvailable(); + // 'symbol' may have come from a module that has since unloaded, perform a safe copy before sending + if( withSafeCopy( (const char*)symbol, size, [this, symbol]( const char* buf, size_t size ) { + SendLongString( symbol, buf, size, QueueType::SymbolCode ); + })) return; - } - - SendLongString( symbol, (const char*)symbol, size, QueueType::SymbolCode ); + + AckSymbolCodeNotAvailable(); } } diff --git a/public/client/TracyProfiler.hpp b/public/client/TracyProfiler.hpp index 46f11f3d..b8b132ea 100644 --- a/public/client/TracyProfiler.hpp +++ b/public/client/TracyProfiler.hpp @@ -833,6 +833,72 @@ private: m_bufferOffset += int( len ); } + template // must be void(const char* buf, size_t size) + bool withSafeCopy(const char* p, size_t size, Callable&& callable) + { + bool success = true, heap = false; + char* buf = m_safeSendBuffer; + +#ifndef NDEBUG + assert( !m_inUse.exchange(true) ); +#endif + + if( size > m_safeSendBufferSize ) + { + heap = true; + buf = (char*)tracy_malloc( size ); + } + +#ifdef _WIN32 + __try + { + memcpy( buf, p, size ); + } + __except( 1 /*EXCEPTION_EXECUTE_HANDLER*/ ) + { + success = false; + } +#else + // Send through the pipe to ensure safe reads + for( size_t offset = 0; offset != size; /*in loop*/ ) + { + size_t sendsize = std::min( size - offset, (size_t)(ptrdiff_t)m_pipeBufSize ); + ssize_t result1, result2; + while( ( result1 = write( m_pipe[1], p + offset, sendsize ) ) < 0 && errno == EINTR ) + /* retry */; + if( result1 < 0 ) + { + success = false; + break; + } + while( ( result2 = read( m_pipe[0], buf + offset, result1 ) ) < 0 && errno == EINTR ) + /* retry */; + if( result2 != result1 ) + { + success = false; + break; + } + offset += result1; + } +#endif + + if( success ) + { + callable( buf, size ); + } + + if( heap ) + { + tracy_free( buf ); + } + +#ifndef NDEBUG + m_inUse.store( false ); +#endif + + return success; + } + bool SendData( const char* data, size_t len ); void SendLongString( uint64_t ptr, const char* str, size_t len, QueueType type ); void SendSourceLocation( uint64_t ptr ); @@ -990,9 +1056,20 @@ private: char* m_queryData; char* m_queryDataPtr; +#ifndef NDEBUG + // m_safeSendBuffer and m_pipe should only be used by the Tracy Profiler thread; this ensures that in debug builds. + std::atomic_bool m_inUse{ false }; +#endif + char* m_safeSendBuffer; + size_t m_safeSendBufferSize; + #if defined _WIN32 void* m_exceptionHandler; +#else + int m_pipe[2]; + int m_pipeBufSize; #endif + #ifdef __linux__ struct { struct sigaction pwr, ill, fpe, segv, pipe, bus, abrt;