libsdl-org / SDL

Simple Directmedia Layer
https://libsdl.org
zlib License
9.79k stars 1.82k forks source link

Endless loop in WGI_JoystickQuit #6837

Closed Zalunda closed 11 months ago

Zalunda commented 1 year ago

I'm using Windows 10.

The application that I'm using just updated from version 2.0.23 to 2.26.1

With version 2.0.23, the application closed correctly. With version 2.26.1, the application never ends. It loop in WGI_JoystickQuit.

While debugging the application, I'm not sure how a WGI joystick driver could ever be closed correctly.

It starts with (Important line: SDL_joysticks_quitting = SDL_TRUE):

void
SDL_JoystickQuit(void)
{
    int i;

    SDL_LockJoysticks();

    SDL_joysticks_quitting = SDL_TRUE;

    /* Stop the event polling */
    while (SDL_joysticks) {
        SDL_joysticks->ref_count = 1;
        SDL_JoystickClose(SDL_joysticks);
    }

    /* Quit drivers in reverse order to avoid breaking dependencies between drivers */
    for (i = SDL_arraysize(SDL_joystick_drivers) - 1; i >= 0; --i) {
       SDL_joystick_drivers[i]->Quit();
    }

And then, for a WGI joystick driver, it call InvokeRemoved until wgi.controller_count is 0:

static void
WGI_JoystickQuit(void)
{
    if (wgi.statics) {
        while (wgi.controller_count > 0) {
            IEventHandler_CRawGameControllerVtbl_InvokeRemoved(&controller_removed.iface, NULL, wgi.controllers[wgi.controller_count - 1].controller);
        }
     ...   

But it's impossible to get to the "--wgi.controller_count" line that would end the loop because SDL_JoysticksQuitting() is always true (i.e. SDL_joysticks_quitting = SDL_TRUE line from the start)

static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeRemoved(__FIEventHandler_1_Windows__CGaming__CInput__CRawGameController * This, IInspectable *sender, __x_ABI_CWindows_CGaming_CInput_CIRawGameController *e)
{
    HRESULT hr;
    __x_ABI_CWindows_CGaming_CInput_CIRawGameController *controller = NULL;

    SDL_LockJoysticks();

    /* Can we get delayed calls to InvokeRemoved() after WGI_JoystickQuit()? */
    if (SDL_JoysticksQuitting() || !SDL_JoysticksInitialized()) {
        SDL_UnlockJoysticks();
        return S_OK;
    }

    ...
    --wgi.controller_count;
    ...

My guess is that this commit is involved in some way: https://github.com/libsdl-org/SDL/commit/40bd4feedcca779a4600743c27a786b436edc8f7#diff-1e92289df6a025c21fcb6e1af73e63bec8606093686f506aa78773e8409b94e9

slouken commented 11 months ago

This is fixed in the latest SDL release.