Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash on shutdown if rmt_DestroyGlobalInstance is called right after initialization without delay. #252

Open
ruifig opened this issue Nov 21, 2023 · 2 comments

Comments

@ruifig
Copy link
Contributor

ruifig commented Nov 21, 2023

I'm adding Remotery in an SDK I'm working on, and I found out that Remotery crashes if I don't have a delay after initialization.

This is the callstack:

>	LudeoSDK-Win64-Debug.dll!AtomicAddS32(volatile int * value, int add) Line 728	C
 	LudeoSDK-Win64-Debug.dll!rmtGetThreadNameFallback(char * out_thread_name, unsigned int thread_name_size) Line 6256	C
 	LudeoSDK-Win64-Debug.dll!rmtGetThreadName(unsigned long thread_id, void * thread_handle, char * out_thread_name, unsigned int thread_name_size) Line 2163	C
 	LudeoSDK-Win64-Debug.dll!ThreadProfiler_Constructor(rmtMessageQueue * mq_to_rmt, ThreadProfiler * thread_profiler, unsigned long thread_id) Line 5224	C
 	LudeoSDK-Win64-Debug.dll!ThreadProfilers_GetThreadProfiler(ThreadProfilers * thread_profilers, unsigned long thread_id, ThreadProfiler * * out_thread_profiler) Line 5520	C
 	LudeoSDK-Win64-Debug.dll!GatherThreads(ThreadProfilers * thread_profilers) Line 5608	C
 	LudeoSDK-Win64-Debug.dll!InitThreadSampling(ThreadProfilers * thread_profilers) Line 5874	C
 	LudeoSDK-Win64-Debug.dll!SampleThreadsLoop(Thread_t * rmt_thread) Line 5907	C
 	LudeoSDK-Win64-Debug.dll!ThreadProcWindows(void * lpParameter) Line 2228	C

It seems to me that if rmt_DestroyGlobalInstance is called fast enough, it catches some threads still initializing, which end up trying to use g_Remotery after it is set to NULL.

Not sure if there are any other implications, but maybe the fix is just changing some things in Remotery_Destructor ?

static void Remotery_Destructor(Remotery* rmt)
{
    assert(rmt != NULL);

    // Join the remotery thread before clearing the global object as the thread is profiling itself
    rmtDelete(rmtThread, rmt->thread);

    if (g_RemoteryCreated)
    {
        g_Remotery = NULL;
        g_RemoteryCreated = RMT_FALSE;
    }

    rmtDelete(ObjectAllocator, rmt->propertyAllocator);

    rmtDelete(ThreadProfilers, rmt->threadProfilers); <<< Crashing while waiting for this, because g_Remotery is NULL.

Moving the ThreadProfilers destruction to right after the rmtThread destruction seems to fix the issue. E.g:

static void Remotery_Destructor(Remotery* rmt)
{
    assert(rmt != NULL);

    // Join the remotery thread before clearing the global object as the thread is profiling itself
    rmtDelete(rmtThread, rmt->thread);
    rmtDelete(ThreadProfilers, rmt->threadProfilers);  <<<< Causes these ones to join before we reset g_RemoteryCreated
@dwilliamson
Copy link
Collaborator

I will look at this in more detail tomorrow, but if you have a head start, I seem to recall a previous issue that had a problem similar to this.

@dwilliamson
Copy link
Collaborator

Issues #214 and #208

dwilliamson added a commit that referenced this issue Dec 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants