Skip to content

Commit

Permalink
Safe copy
Browse files Browse the repository at this point in the history
  • Loading branch information
jkriegshauser committed Sep 23, 2024
1 parent f6882e2 commit b66b18f
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 7 deletions.
37 changes: 30 additions & 7 deletions public/client/TracyProfiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ extern "C" typedef char* (WINAPI *t_WineGetBuildId)();
#else
# include <unistd.h>
# include <limits.h>
# include <fcntl.h>
#endif
#if defined __linux__
# include <sys/sysinfo.h>
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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 );
Expand Down Expand Up @@ -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();
}
}

Expand Down
77 changes: 77 additions & 0 deletions public/client/TracyProfiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,72 @@ class Profiler
m_bufferOffset += int( len );
}

template<class Callable> // 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 );
Expand Down Expand Up @@ -990,9 +1056,20 @@ class Profiler
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;
Expand Down

0 comments on commit b66b18f

Please sign in to comment.