mirror of
https://github.com/wolfpld/tracy.git
synced 2024-11-25 23:44:35 +00:00
Merge pull request #889 from jkriegshauser/fix-long-string-crash
Safe copy to fix issue #888
This commit is contained in:
commit
13d9ed7e87
@ -111,6 +111,7 @@ extern "C" typedef char* (WINAPI *t_WineGetBuildId)();
|
|||||||
#else
|
#else
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
# include <limits.h>
|
# include <limits.h>
|
||||||
|
# include <fcntl.h>
|
||||||
#endif
|
#endif
|
||||||
#if defined __linux__
|
#if defined __linux__
|
||||||
# include <sys/sysinfo.h>
|
# include <sys/sysinfo.h>
|
||||||
@ -1389,6 +1390,8 @@ TRACY_API LuaZoneState& GetLuaZoneState() { return s_luaZoneState; }
|
|||||||
TRACY_API bool ProfilerAvailable() { return s_instance != nullptr; }
|
TRACY_API bool ProfilerAvailable() { return s_instance != nullptr; }
|
||||||
TRACY_API bool ProfilerAllocatorAvailable() { return !RpThreadShutdown; }
|
TRACY_API bool ProfilerAllocatorAvailable() { return !RpThreadShutdown; }
|
||||||
|
|
||||||
|
constexpr static size_t SafeSendBufferSize = 65536;
|
||||||
|
|
||||||
Profiler::Profiler()
|
Profiler::Profiler()
|
||||||
: m_timeBegin( 0 )
|
: m_timeBegin( 0 )
|
||||||
, m_mainThread( detail::GetThreadHandleImpl() )
|
, m_mainThread( detail::GetThreadHandleImpl() )
|
||||||
@ -1462,6 +1465,21 @@ Profiler::Profiler()
|
|||||||
m_userPort = atoi( userPort );
|
m_userPort = atoi( userPort );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_safeSendBuffer = (char*)tracy_malloc( 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)SafeSendBufferSize;
|
||||||
|
while( fcntl( m_pipe[0], F_SETPIPE_SZ, m_pipeBufSize ) < 0 && errno == EPERM ) m_pipeBufSize /= 2; // too big; reduce
|
||||||
|
m_pipeBufSize = fcntl( m_pipe[0], F_GETPIPE_SZ );
|
||||||
|
# endif
|
||||||
|
fcntl( m_pipe[1], F_SETFL, O_NONBLOCK );
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(TRACY_DELAYED_INIT) || !defined(TRACY_MANUAL_LIFETIME)
|
#if !defined(TRACY_DELAYED_INIT) || !defined(TRACY_MANUAL_LIFETIME)
|
||||||
SpawnWorkerThreads();
|
SpawnWorkerThreads();
|
||||||
#endif
|
#endif
|
||||||
@ -1487,7 +1505,9 @@ void Profiler::InstallCrashHandler()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined _WIN32 && !defined TRACY_UWP && !defined TRACY_NO_CRASH_HANDLER
|
#if defined _WIN32 && !defined TRACY_UWP && !defined TRACY_NO_CRASH_HANDLER
|
||||||
m_exceptionHandler = AddVectoredExceptionHandler( 1, CrashFilter );
|
// We cannot use Vectored Exception handling because it catches application-wide frame-based SEH blocks. We only
|
||||||
|
// want to catch unhandled exceptions.
|
||||||
|
m_prevHandler = SetUnhandledExceptionFilter( CrashFilter );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TRACY_NO_CRASH_HANDLER
|
#ifndef TRACY_NO_CRASH_HANDLER
|
||||||
@ -1498,20 +1518,29 @@ void Profiler::InstallCrashHandler()
|
|||||||
|
|
||||||
void Profiler::RemoveCrashHandler()
|
void Profiler::RemoveCrashHandler()
|
||||||
{
|
{
|
||||||
#if defined _WIN32 && !defined TRACY_UWP
|
#if defined _WIN32 && !defined TRACY_UWP && !defined TRACY_NO_CRASH_HANDLER
|
||||||
if( m_crashHandlerInstalled ) RemoveVectoredExceptionHandler( m_exceptionHandler );
|
if( m_crashHandlerInstalled )
|
||||||
|
{
|
||||||
|
auto prev = SetUnhandledExceptionFilter( (LPTOP_LEVEL_EXCEPTION_FILTER)m_prevHandler );
|
||||||
|
if( prev != CrashFilter ) SetUnhandledExceptionFilter( prev ); // A different exception filter was installed over ours => put it back
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined __linux__ && !defined TRACY_NO_CRASH_HANDLER
|
#if defined __linux__ && !defined TRACY_NO_CRASH_HANDLER
|
||||||
if( m_crashHandlerInstalled )
|
if( m_crashHandlerInstalled )
|
||||||
{
|
{
|
||||||
sigaction( TRACY_CRASH_SIGNAL, &m_prevSignal.pwr, nullptr );
|
auto restore = []( int signum, struct sigaction* prev ) {
|
||||||
sigaction( SIGILL, &m_prevSignal.ill, nullptr );
|
struct sigaction old;
|
||||||
sigaction( SIGFPE, &m_prevSignal.fpe, nullptr );
|
sigaction( signum, prev, &old );
|
||||||
sigaction( SIGSEGV, &m_prevSignal.segv, nullptr );
|
if( old.sa_sigaction != CrashHandler ) sigaction( signum, &old, nullptr ); // A different signal handler was installed over ours => put it back
|
||||||
sigaction( SIGPIPE, &m_prevSignal.pipe, nullptr );
|
};
|
||||||
sigaction( SIGBUS, &m_prevSignal.bus, nullptr );
|
restore( TRACY_CRASH_SIGNAL, &m_prevSignal.pwr );
|
||||||
sigaction( SIGABRT, &m_prevSignal.abrt, nullptr );
|
restore( SIGILL, &m_prevSignal.ill );
|
||||||
|
restore( SIGFPE, &m_prevSignal.fpe );
|
||||||
|
restore( SIGSEGV, &m_prevSignal.segv );
|
||||||
|
restore( SIGPIPE, &m_prevSignal.pipe );
|
||||||
|
restore( SIGBUS, &m_prevSignal.bus );
|
||||||
|
restore( SIGABRT, &m_prevSignal.abrt );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
m_crashHandlerInstalled = false;
|
m_crashHandlerInstalled = false;
|
||||||
@ -1600,6 +1629,12 @@ Profiler::~Profiler()
|
|||||||
tracy_free( m_kcore );
|
tracy_free( m_kcore );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
close( m_pipe[0] );
|
||||||
|
close( m_pipe[1] );
|
||||||
|
#endif
|
||||||
|
tracy_free( m_safeSendBuffer );
|
||||||
|
|
||||||
tracy_free( m_lz4Buf );
|
tracy_free( m_lz4Buf );
|
||||||
tracy_free( m_buffer );
|
tracy_free( m_buffer );
|
||||||
LZ4_freeStream( (LZ4_stream_t*)m_stream );
|
LZ4_freeStream( (LZ4_stream_t*)m_stream );
|
||||||
@ -3063,6 +3098,62 @@ bool Profiler::CommitData()
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* Profiler::SafeCopyProlog( const char* data, size_t size )
|
||||||
|
{
|
||||||
|
bool success = true;
|
||||||
|
char* buf = m_safeSendBuffer;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
assert( !m_inUse.exchange(true) );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( size > SafeSendBufferSize ) buf = (char*)tracy_malloc( size );
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
memcpy( buf, data, 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 = size - offset;
|
||||||
|
ssize_t result1, result2;
|
||||||
|
while( ( result1 = write( m_pipe[1], data + 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 ) return buf;
|
||||||
|
|
||||||
|
SafeCopyEpilog( buf );
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Profiler::SafeCopyEpilog( char* buf )
|
||||||
|
{
|
||||||
|
if( buf != m_safeSendBuffer ) tracy_free( buf );
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
m_inUse.store( false );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool Profiler::SendData( const char* data, size_t len )
|
bool Profiler::SendData( const char* data, size_t len )
|
||||||
{
|
{
|
||||||
const lz4sz_t lz4sz = LZ4_compress_fast_continue( (LZ4_stream_t*)m_stream, data, m_lz4Buf + sizeof( lz4sz_t ), (int)len, LZ4Size, 1 );
|
const lz4sz_t lz4sz = LZ4_compress_fast_continue( (LZ4_stream_t*)m_stream, data, m_lz4Buf + sizeof( lz4sz_t ), (int)len, LZ4Size, 1 );
|
||||||
@ -4017,13 +4108,12 @@ void Profiler::HandleSymbolCodeQuery( uint64_t symbol, uint32_t size )
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( !EnsureReadable( symbol ) )
|
auto&& lambda = [ this, symbol ]( const char* buf, size_t size ) {
|
||||||
{
|
SendLongString( symbol, buf, size, QueueType::SymbolCode );
|
||||||
AckSymbolCodeNotAvailable();
|
};
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SendLongString( symbol, (const char*)symbol, size, QueueType::SymbolCode );
|
// 'symbol' may have come from a module that has since unloaded, perform a safe copy before sending
|
||||||
|
if( !WithSafeCopy( (const char*)symbol, size, lambda ) ) AckSymbolCodeNotAvailable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -833,6 +833,21 @@ private:
|
|||||||
m_bufferOffset += int( len );
|
m_bufferOffset += int( len );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* SafeCopyProlog( const char* p, size_t size );
|
||||||
|
void SafeCopyEpilog( char* buf );
|
||||||
|
|
||||||
|
template<class Callable> // must be void( const char* buf, size_t size )
|
||||||
|
bool WithSafeCopy( const char* p, size_t size, Callable&& callable )
|
||||||
|
{
|
||||||
|
if( char* buf = SafeCopyProlog( p, size ) )
|
||||||
|
{
|
||||||
|
callable( buf, size );
|
||||||
|
SafeCopyEpilog( buf );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool SendData( const char* data, size_t len );
|
bool SendData( const char* data, size_t len );
|
||||||
void SendLongString( uint64_t ptr, const char* str, size_t len, QueueType type );
|
void SendLongString( uint64_t ptr, const char* str, size_t len, QueueType type );
|
||||||
void SendSourceLocation( uint64_t ptr );
|
void SendSourceLocation( uint64_t ptr );
|
||||||
@ -990,9 +1005,19 @@ private:
|
|||||||
char* m_queryData;
|
char* m_queryData;
|
||||||
char* m_queryDataPtr;
|
char* m_queryDataPtr;
|
||||||
|
|
||||||
#if defined _WIN32
|
#ifndef NDEBUG
|
||||||
void* m_exceptionHandler;
|
// 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
|
#endif
|
||||||
|
char* m_safeSendBuffer;
|
||||||
|
|
||||||
|
#if defined _WIN32
|
||||||
|
void* m_prevHandler;
|
||||||
|
#else
|
||||||
|
int m_pipe[2];
|
||||||
|
int m_pipeBufSize;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
struct {
|
struct {
|
||||||
struct sigaction pwr, ill, fpe, segv, pipe, bus, abrt;
|
struct sigaction pwr, ill, fpe, segv, pipe, bus, abrt;
|
||||||
|
Loading…
Reference in New Issue
Block a user