We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 4579

Summary: SDL_android.c s_active not being atomic
Product: SDL Reporter: Isaias Brunet <mscsirmaster>
Component: *don't know*Assignee: Ryan C. Gordon <icculus>
Status: RESOLVED FIXED QA Contact: Sam Lantinga <slouken>
Severity: critical    
Priority: P2    
Version: 2.0.9   
Hardware: All   
OS: Android (All)   

Description Isaias Brunet 2019-04-04 20:31:28 UTC
This bug cause a false assert due to multiple threads modifying the same variable without any atomic operation.

Bug lines:
SDL_android.c
static int s_active = 0;
...
static SDL_bool LocalReferenceHolder_Init(struct LocalReferenceHolder *refholder, JNIEnv *env)
{
    const int capacity = 16;
    if ((*env)->PushLocalFrame(env, capacity) < 0) {
        SDL_SetError("Failed to allocate enough JVM local references");
        return SDL_FALSE;
    }
    ++s_active;
    refholder->m_env = env;
    return SDL_TRUE;
}
...
static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder)
{
#ifdef DEBUG_JNI
    SDL_Log("Leaving function %s", refholder->m_func);
#endif
    if (refholder->m_env) {
        JNIEnv* env = refholder->m_env;
		(*env)->PopLocalFrame(env, NULL);
		--s_active;
    }
}
...
static SDL_bool LocalReferenceHolder_IsActive(void)
{
    return s_active > 0;
}

Solution:
static SDL_atomic_t s_active = { 0 };
...
static SDL_bool LocalReferenceHolder_Init(struct LocalReferenceHolder *refholder, JNIEnv *env)
{
    const int capacity = 16;
    if ((*env)->PushLocalFrame(env, capacity) < 0) {
        SDL_SetError("Failed to allocate enough JVM local references");
        return SDL_FALSE;
    }
	SDL_AtomicIncRef(&s_active);
    refholder->m_env = env;
    return SDL_TRUE;
}
...
static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder)
{
#ifdef DEBUG_JNI
    SDL_Log("Leaving function %s", refholder->m_func);
#endif
    if (refholder->m_env) {
        JNIEnv* env = refholder->m_env;
		(*env)->PopLocalFrame(env, NULL);
		SDL_AtomicDecRef(&s_active);
    }
}
...
static SDL_bool LocalReferenceHolder_IsActive(void)
{
    return SDL_AtomicGet(&s_active) > 0;
}

Extra bug lines:
In some branches and [default] there is a line modified to use directly s_active, and should instead use LocalReferenceHolder_IsActive.

SDL_assert((s_active > 0));

Solution:
SDL_assert(LocalReferenceHolder_IsActive());
Comment 1 Sam Lantinga 2019-04-05 15:15:18 UTC
Fixed, thanks!
https://hg.libsdl.org/SDL/rev/3ef8a628853d