mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 18:23:15 +02:00
Add asan switch indicators
This commit is contained in:
parent
b207ec8817
commit
a9121d4cd1
@ -57,6 +57,36 @@
|
||||
#include <sys/mman.h> // mmap, mprotect, munmap
|
||||
#endif
|
||||
|
||||
#ifdef KICAD_SANITIZE_ADDRESS
|
||||
#include <sanitizer/asan_interface.h>
|
||||
// ASan fiber switching APIs (available since Clang 3.9/GCC 7)
|
||||
extern "C" {
|
||||
void __sanitizer_start_switch_fiber(void** fake_stack_save,
|
||||
const void* bottom, size_t size);
|
||||
void __sanitizer_finish_switch_fiber(void* fake_stack_save,
|
||||
const void** bottom_old,
|
||||
size_t* size_old);
|
||||
}
|
||||
|
||||
// Thread-local tracking of ASAN fiber switch state
|
||||
static bool& GetAsanFiberSwitchState()
|
||||
{
|
||||
thread_local bool asan_fiber_switch_active = false;
|
||||
return asan_fiber_switch_active;
|
||||
}
|
||||
|
||||
// Add runtime ASAN detection
|
||||
static bool IsASanEnabled()
|
||||
{
|
||||
static std::optional<bool> asan_enabled;
|
||||
if (!asan_enabled.has_value())
|
||||
{
|
||||
asan_enabled = (__has_feature(address_sanitizer) );
|
||||
}
|
||||
return asan_enabled.value();
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Implement a coroutine.
|
||||
*
|
||||
@ -110,12 +140,24 @@ private:
|
||||
void* tsan_fiber; // The TSAN fiber for this context
|
||||
bool own_tsan_fiber; // Do we own this TSAN fiber? (we only delete fibers we own)
|
||||
#endif
|
||||
#ifdef KICAD_SANITIZE_ADDRESS
|
||||
void* asan_fake_stack; // ASan fake stack for this context
|
||||
const void* asan_stack_bottom; // Stack bottom for ASan
|
||||
size_t asan_stack_size; // Stack size for ASan
|
||||
bool asan_stack_registered; // Track if we registered this stack
|
||||
#endif
|
||||
|
||||
CONTEXT_T() :
|
||||
ctx( nullptr )
|
||||
#ifdef KICAD_SANITIZE_THREADS
|
||||
,tsan_fiber( nullptr )
|
||||
,own_tsan_fiber( true )
|
||||
#endif
|
||||
#ifdef KICAD_SANITIZE_ADDRESS
|
||||
,asan_fake_stack( nullptr )
|
||||
,asan_stack_bottom( nullptr )
|
||||
,asan_stack_size( 0 )
|
||||
,asan_stack_registered( false )
|
||||
#endif
|
||||
{}
|
||||
|
||||
@ -125,6 +167,15 @@ private:
|
||||
// Only destroy the fiber when we own it
|
||||
if( own_tsan_fiber )
|
||||
__tsan_destroy_fiber( tsan_fiber );
|
||||
#endif
|
||||
#ifdef KICAD_SANITIZE_ADDRESS
|
||||
// Clean up ASAN registration if we registered it
|
||||
if( asan_stack_registered && IsASanEnabled() )
|
||||
{
|
||||
// Note: ASAN doesn't provide explicit stack deregistration,
|
||||
// but we should reset our tracking
|
||||
asan_stack_registered = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
@ -206,9 +257,6 @@ public:
|
||||
m_retVal( 0 )
|
||||
#ifdef KICAD_USE_VALGRIND
|
||||
,m_valgrind_stack( 0 )
|
||||
#endif
|
||||
#ifdef KICAD_SANITIZE_ADDRESS
|
||||
,asan_stack( nullptr )
|
||||
#endif
|
||||
{
|
||||
m_stacksize = ADVANCED_CFG::GetCfg().m_CoroutineStackSize;
|
||||
@ -276,12 +324,6 @@ public:
|
||||
CALL_CONTEXT ctx;
|
||||
INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROOT, this, &ctx };
|
||||
|
||||
#ifdef KICAD_SANITIZE_THREADS
|
||||
// Get the TSAN fiber for the current stack here
|
||||
m_caller.tsan_fiber = __tsan_get_current_fiber();
|
||||
m_caller.own_tsan_fiber = false;
|
||||
#endif
|
||||
|
||||
wxLogTrace( kicadTraceCoroutineStack, "COROUTINE::Call (from root)" );
|
||||
|
||||
ctx.Continue( doCall( &args, aArg ) );
|
||||
@ -322,12 +364,6 @@ public:
|
||||
CALL_CONTEXT ctx;
|
||||
INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROOT, this, &ctx };
|
||||
|
||||
#ifdef KICAD_SANITIZE_THREADS
|
||||
// Get the TSAN fiber for the current stack here
|
||||
m_caller.tsan_fiber = __tsan_get_current_fiber();
|
||||
m_caller.own_tsan_fiber = false;
|
||||
#endif
|
||||
|
||||
wxLogTrace( kicadTraceCoroutineStack, wxT( "COROUTINE::Resume (from root)" ) );
|
||||
|
||||
ctx.Continue( doResume( &args ) );
|
||||
@ -377,6 +413,22 @@ private:
|
||||
assert( m_func );
|
||||
assert( !( m_callee.ctx ) );
|
||||
|
||||
#ifdef KICAD_SANITIZE_THREADS
|
||||
// Get the TSAN fiber for the current stack here
|
||||
m_caller.tsan_fiber = __tsan_get_current_fiber();
|
||||
m_caller.own_tsan_fiber = false;
|
||||
#endif
|
||||
#ifdef KICAD_SANITIZE_ADDRESS
|
||||
if( IsASanEnabled() )
|
||||
{
|
||||
// Initialize caller's ASan context (main stack)
|
||||
m_caller.asan_fake_stack = nullptr;
|
||||
m_caller.asan_stack_bottom = nullptr; // Main stack, managed by ASan
|
||||
m_caller.asan_stack_size = 0;
|
||||
m_caller.asan_stack_registered = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_args = &aArgs;
|
||||
|
||||
std::size_t stackSize = m_stacksize;
|
||||
@ -408,6 +460,22 @@ private:
|
||||
#ifdef KICAD_USE_VALGRIND
|
||||
m_valgrind_stack = VALGRIND_STACK_REGISTER( sp, m_stack.get() );
|
||||
#endif
|
||||
#ifdef KICAD_SANITIZE_ADDRESS
|
||||
if( IsASanEnabled() )
|
||||
{
|
||||
// Register the allocated stack with ASan
|
||||
m_callee.asan_stack_bottom = m_stack.get();
|
||||
m_callee.asan_stack_size = stackSize;
|
||||
m_callee.asan_fake_stack = nullptr;
|
||||
m_callee.asan_stack_registered = true;
|
||||
|
||||
// Poison the guard page for better debugging
|
||||
if( m_stack.get() )
|
||||
{
|
||||
__asan_poison_memory_region( m_stack.get(), SystemPageSize() );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef KICAD_SANITIZE_THREADS
|
||||
@ -494,6 +562,21 @@ private:
|
||||
|
||||
INVOCATION_ARGS* doResume( INVOCATION_ARGS* args )
|
||||
{
|
||||
|
||||
#ifdef KICAD_SANITIZE_THREADS
|
||||
// Get the TSAN fiber for the current stack here
|
||||
m_caller.tsan_fiber = __tsan_get_current_fiber();
|
||||
m_caller.own_tsan_fiber = false;
|
||||
#endif
|
||||
#ifdef KICAD_SANITIZE_ADDRESS
|
||||
if( IsASanEnabled() )
|
||||
{
|
||||
// Initialize caller's ASan context for resume
|
||||
m_caller.asan_fake_stack = nullptr;
|
||||
m_caller.asan_stack_bottom = nullptr;
|
||||
m_caller.asan_stack_size = 0;
|
||||
}
|
||||
#endif
|
||||
return jumpIn( args );
|
||||
}
|
||||
|
||||
@ -519,17 +602,38 @@ private:
|
||||
|
||||
INVOCATION_ARGS* jumpIn( INVOCATION_ARGS* args )
|
||||
{
|
||||
|
||||
wxLogTrace( kicadTraceCoroutineStack, wxT( "COROUTINE::jumpIn" ) );
|
||||
#ifdef KICAD_SANITIZE_ADDRESS
|
||||
// Only use ASAN fiber switching for root-level calls to avoid nesting
|
||||
if( IsASanEnabled() && !GetAsanFiberSwitchState()
|
||||
&& ( m_callee.asan_stack_registered || m_callee.asan_stack_bottom ) )
|
||||
{
|
||||
GetAsanFiberSwitchState() = true;
|
||||
__sanitizer_start_switch_fiber( &m_caller.asan_fake_stack,
|
||||
m_callee.asan_stack_bottom,
|
||||
m_callee.asan_stack_size );
|
||||
}
|
||||
#endif
|
||||
#ifdef KICAD_SANITIZE_THREADS
|
||||
// Tell TSAN we are changing fibers to the callee
|
||||
__tsan_switch_to_fiber( m_callee.tsan_fiber, 0 );
|
||||
#endif
|
||||
|
||||
wxLogTrace( kicadTraceCoroutineStack, wxT( "COROUTINE::jumpIn" ) );
|
||||
|
||||
args = reinterpret_cast<INVOCATION_ARGS*>(
|
||||
libcontext::jump_fcontext( &( m_caller.ctx ), m_callee.ctx,
|
||||
reinterpret_cast<intptr_t>( args ) )
|
||||
);
|
||||
#ifdef KICAD_SANITIZE_ADDRESS
|
||||
// Complete fiber switch only if we started it
|
||||
if( IsASanEnabled() && GetAsanFiberSwitchState() )
|
||||
{
|
||||
__sanitizer_finish_switch_fiber( m_caller.asan_fake_stack,
|
||||
&m_caller.asan_stack_bottom,
|
||||
&m_caller.asan_stack_size );
|
||||
GetAsanFiberSwitchState() = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return args;
|
||||
}
|
||||
@ -539,6 +643,16 @@ private:
|
||||
INVOCATION_ARGS args{ INVOCATION_ARGS::FROM_ROUTINE, nullptr, nullptr };
|
||||
INVOCATION_ARGS* ret;
|
||||
|
||||
#ifdef KICAD_SANITIZE_ADDRESS
|
||||
// Only use ASAN fiber switching for root-level calls to avoid nesting
|
||||
if( IsASanEnabled() && !GetAsanFiberSwitchState() )
|
||||
{
|
||||
GetAsanFiberSwitchState() = true;
|
||||
__sanitizer_start_switch_fiber( &m_callee.asan_fake_stack,
|
||||
m_caller.asan_stack_bottom,
|
||||
m_caller.asan_stack_size );
|
||||
}
|
||||
#endif
|
||||
#ifdef KICAD_SANITIZE_THREADS
|
||||
// Tell TSAN we are changing fibers back to the caller
|
||||
__tsan_switch_to_fiber( m_caller.tsan_fiber, 0 );
|
||||
@ -551,6 +665,16 @@ private:
|
||||
reinterpret_cast<intptr_t>( &args ) )
|
||||
);
|
||||
|
||||
#ifdef KICAD_SANITIZE_ADDRESS
|
||||
// Complete fiber switch only if we started it
|
||||
if( IsASanEnabled() && GetAsanFiberSwitchState() )
|
||||
{
|
||||
__sanitizer_finish_switch_fiber( m_callee.asan_fake_stack,
|
||||
&m_callee.asan_stack_bottom,
|
||||
&m_callee.asan_stack_size );
|
||||
GetAsanFiberSwitchState() = false;
|
||||
}
|
||||
#endif
|
||||
m_callContext = ret->context;
|
||||
|
||||
if( ret->type == INVOCATION_ARGS::FROM_ROOT )
|
||||
@ -559,6 +683,24 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef KICAD_SANITIZE_ADDRESS
|
||||
// Additional helper for debugging ASAN integration
|
||||
void LogASanStatus() const
|
||||
{
|
||||
if( !IsASanEnabled() )
|
||||
return;
|
||||
|
||||
wxLogTrace( kicadTraceCoroutineStack,
|
||||
wxT("ASAN Coroutine Status: fiber_switch_active=%s, "
|
||||
"caller_bottom=%p, caller_size=%zu, "
|
||||
"callee_bottom=%p, callee_size=%zu, callee_registered=%s"),
|
||||
GetAsanFiberSwitchState() ? "yes" : "no",
|
||||
m_caller.asan_stack_bottom, m_caller.asan_stack_size,
|
||||
m_callee.asan_stack_bottom, m_callee.asan_stack_size,
|
||||
m_callee.asan_stack_registered ? "yes" : "no" );
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LIBCONTEXT_HAS_OWN_STACK
|
||||
/// Coroutine stack.
|
||||
std::unique_ptr<char[], struct STACK_DELETER> m_stack;
|
||||
@ -587,10 +729,6 @@ private:
|
||||
#ifdef KICAD_USE_VALGRIND
|
||||
uint32_t m_valgrind_stack;
|
||||
#endif
|
||||
|
||||
#ifdef KICAD_SANITIZE_ADDRESS
|
||||
void* asan_stack;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user