Menu

#30 wasapi driver segfault upon MikMod_Reset()

next release
closed
None
5
2026-05-10
2026-05-07
Ozkan Sezer
No

Using WASAPI driver:

  • run mikmod,
  • hit 'c' for configuration menu
  • for e.g.: change 'loops' option
  • hit 'Use Config'

Result: SIGSEGV

Backtrace from gdb:

Program received signal SIGSEGV, Segmentation fault.
0x62bb4c04 in VC1_VoiceSetVolume (voice=0 '\000', vol=68) at ../playercode/virtch_common.c:343
343     ../playercode/virtch_common.c: No such file or directory.
        in ../playercode/virtch_common.c
(gdb) bt
#0  0x62bb4c04 in VC1_VoiceSetVolume (voice=0 '\000', vol=68) at ../playercode/virtch_common.c:343
#1  0x62bb9df1 in VC_VoiceSetVolume (a=0 '\000', b=68) at ../playercode/virtch_common.c:161
#2  0x62ba0ed5 in Voice_SetVolume_internal (voice=0 '\000', vol=68) at ../playercode/mdriver.c:333
#3  0x62bac9d1 in pt_UpdateVoices (mod=0x29c4bd0, max_volume=128) at ../playercode/mplayer.c:2862
#4  0x62bae440 in Player_HandleTick () at ../playercode/mplayer.c:3416
#5  0x62bb51a5 in VC1_WriteSamples (
    buf=0x281a310 "\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º"..., todo=1056) at ../playercode/virtch.c:1157
#6  0x62bb495f in VC1_WriteBytes (
    buf=0x281a310 "\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º"..., todo=1056) at ../playercode/virtch_common.c:276
#7  0x62bb9daa in VC_WriteBytes (
    a=0x281a310 "\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º"..., b=4224) at ../playercode/virtch_common.c:159
#8  0x62b832e3 in wasapi_render_cb (user=0x0,
    dst=0x281a310 "\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º\rd-º"..., framesAvail=1056) at ../drivers/drv_wasapi.c:661
#9  0x62b83073 in audio_device_render (dev=0x2907918, pData=0x899dd8 "", framesAvail=1056)
    at ../drivers/drv_wasapi.c:589
#10 0x62b82d26 in audio_device_start (dev=0x2907918) at ../drivers/drv_wasapi.c:504
#11 0x62b8356d in WASAPI_PlayStart () at ../drivers/drv_wasapi.c:755
#12 0x62ba1afb in _mm_reset (cmdline=0x29c23c0 "") at ../playercode/mdriver.c:635
#13 0x62ba1b5b in MikMod_Reset (cmdline=0x29c23c0 "") at ../playercode/mdriver.c:645
#14 0x0040ad7b in Player_SetConfig (cfg=0x435980) at ../src/mikmod.c:440
#15 0x004070dc in handle_menu (mn=0x429480) at ../src/mconfedit.c:750
#16 0x00411b98 in menu_handle_key (win=0x29c5008, ch=13) at ../src/mmenu.c:454
#17 0x0041926a in win_handle_key (ch=13) at ../src/mwindow.c:967
#18 0x00419645 in win_main_iteration () at ../src/mwindow.c:1065
#19 0x0041966a in win_run () at ../src/mwindow.c:1078
#20 0x0040c40e in main (argc=1, argv=0x29c2340) at ../src/mikmod.c:1079
(gdb)

/cc @realtech (Stephane Denis)

Discussion

  • Stephane Denis

    Stephane Denis - 2026-05-07
    • assigned_to: Stephane Denis
     
  • Stephane Denis

    Stephane Denis - 2026-05-07

    Problem is in WASAPI_Exit
    VC1_Exit clear the voices but doesn't re-create them. needs to be removed

     
  • Stephane Denis

    Stephane Denis - 2026-05-07

    Fixed in commit 099b986137b115f16821ce341048a5de1e331ce1
    Removed VC1_Exit on DirectSound and Wasapi.
    Tested with mikmod app

    • open mikmod with a module as parameter
    • change configuration (Loops)
    • use configuration

    -> No more crash (vinf is not deleted in virtch code).

     
  • Stephane Denis

    Stephane Denis - 2026-05-07
    • status: open --> closed
     
  • Ozkan Sezer

    Ozkan Sezer - 2026-05-07

    Every driver calls VC_Exit() in their Exit() procedure, none does segfault. drv_ds didn't used to crash either. Why is this a problem with drv_wasapi?

     
  • Stephane Denis

    Stephane Denis - 2026-05-07

    the issue is MikMod_Reset, reset (with WASAPI_PlayStart) but the voice are not recreated.
    on better fix is to do
    md_driver->Exit();
    md_driver->SetNumVoices();

    because if the music is played and mikmod is reset, then you need to recreate the voices else it will continue to write to vinf.

    tell me if it better and will revert and use that better fix instead

     
  • Ozkan Sezer

    Ozkan Sezer - 2026-05-07

    Sounds logical. But what I do not understand is why is it a problem only with drv_wasapi? And drv_ds did not crash before either.. Thinking about it, drv_ds leaves first update to MiMod_Update() via DS_Update(): see do_update in there.

    tell me if it better and will revert and use that better fix instead

    Maybe?. I'm still trying to understand things, though..

     
  • Stephane Denis

    Stephane Denis - 2026-05-08

    the gap is mmreset exit the driver and immediately call mddriver->PlayStart() and wasapi audiodevicestart immediately start to produce audiodevicerender. there is no latency, that's why the voice need to be reset before voice start.

    that's the difference from other driver.

    The real fix is that voice needs to be recreated because calling playstart. ( SetNumVoices)

    it didn't crash for other driver, but this is definitely something was omitted.

    Note that is happens only the the music is playing, technically with the fix you don't need to have mikmod to reload the music, you can keep the current music position

    Here the callstack

    audio_device_render(AudioDevice , unsigned char , unsigned int) << Call VC1_Volume and crash because vinf not yet recreated (VC1_SetNumVoices not called until music is reloaded by mikmod)
    audio_device_start(AudioDevice )
    WASAPI_PlayStart() << Audio is restarting
    _mm_reset(const char
    )
    MikMod_Reset(const char ) << Reset config
    Player_SetConfig(CONFIG
    )
    handle_menu(MMENU )
    menu_handle_key(MWINDOW
    , int)
    win_handle_key(int)
    win_main_iteration()
    win_run()
    main(int, char * *)

    technically you can remove also the

    framesAvail = dev->bufferFrames - padding;
    if (framesAvail > 0) {
    hr = IAudioRenderClient_GetBuffer(dev->renderClient, framesAvail, &pData);
    if (FAILED(hr)) return FALSE;
    if (pData) {
    BOOL produced = audio_device_render(dev, pData, framesAvail);
    if (!produced)
    memset(pData, 0, (size_t)framesAvail * bytes_per_frame(dev->mixFormat));
    }
    IAudioRenderClient_ReleaseBuffer(dev->renderClient, framesAvail, 0);
    }

    this the part that 'calls player tick to honor pending frames' at start of the driver start

     

    Last edit: Stephane Denis 2026-05-08
  • Ozkan Sezer

    Ozkan Sezer - 2026-05-09

    I tested the following patch which (after reverting the previous fix),
    out-sources device-start to MikMod_Update(), like it is done in drv_ds
    and dr_xaudio. Tested on a windows-11 setup.

    What do you think?

    (And I can't think of any app that uses these drivers and also not call
    MikMod_Update: Can I be mistaken?)

    diff --git a/libmikmod/drivers/drv_ds.c b/libmikmod/drivers/drv_ds.c
    index f5977dd..9ec638f 100644
    --- a/libmikmod/drivers/drv_ds.c
    +++ b/libmikmod/drivers/drv_ds.c
    @@ -328,6 +328,8 @@ static void DS_Exit(void)
            IDirectSound_Release(pSoundCard);
            pSoundCard = NULL;
        }
    +
    
    +   VC_Exit();
     }
    
     static BOOL do_update = 0;
    diff --git a/libmikmod/drivers/drv_wasapi.c b/libmikmod/drivers/drv_wasapi.c
    index 642eaba..160f7e0 100644
    --- a/libmikmod/drivers/drv_wasapi.c
    +++ b/libmikmod/drivers/drv_wasapi.c
    @@ -745,24 +745,22 @@ static void WASAPI_Exit(void)
             g_wasapi = NULL;
         }
         g_started = FALSE;
    
    +    VC_Exit();
     }
    
    +static BOOL do_update = 0;
    +
     static int WASAPI_PlayStart(void)
     {
         if (VC_PlayStart()) return 1;
    
    
    -    if (g_wasapi && !audio_device_start(g_wasapi)) {
    -        VC_PlayStop();
    -        _mm_errno = MMERR_OPENING_AUDIO;
    -        return 1;
    -    }
    -
    -    g_started = TRUE;
    +    do_update = 1;
         return 0;
     }
    
     static void WASAPI_PlayStop(void)
     {
    
    +    do_update = 0;
         if (g_wasapi && g_started)
             audio_device_stop(g_wasapi);
         g_started = FALSE;
    @@ -770,7 +768,21 @@ static void WASAPI_PlayStop(void)
     }
    
     /* Event-driven backend: no polling needed */
    -static void WASAPI_Update(void) {}
    +static void WASAPI_Update(void)
    +{
    
    +    if (!do_update)
    +        return;
    +    do_update = 0;
    +
    +    if (g_wasapi && !audio_device_start(g_wasapi)) {
    +        VC_PlayStop();
    +        _mm_errno = MMERR_OPENING_AUDIO;
    +        WASAPI_Exit();
    +        return;
    +    }
    +
    +    g_started = TRUE;
    +}
    
     MIKMODAPI MDRIVER drv_wasapi = {
         NULL,
    diff --git a/libmikmod/drivers/drv_sdl.c b/libmikmod/drivers/drv_sdl.c
    index e5a1ba2..4fc6a0d 100644
    --- a/libmikmod/drivers/drv_sdl.c
    +++ b/libmikmod/drivers/drv_sdl.c
    @@ -47,19 +47,15 @@ static int enabled = 0;
    
     static void SDLSoundCallback(void *userdata, Uint8 *stream, int len)
     {
    
    -    if (!enabled) return;
    -    if (enabled < 0) {
    -        if (++enabled == 0)
    -            enabled = 1;
    +    if (enabled <= 0) {
    +        VC_SilenceBytes((SBYTE *) stream, (ULONG)len);
             return;
         }
    -
         MUTEX_LOCK(vars);
         if (Player_Paused_internal()) {
             VC_SilenceBytes((SBYTE *) stream, (ULONG)len);
         }
    -    else
    -    {
    +    else {
             int got = (int) VC_WriteBytes((SBYTE *) stream, (ULONG)len);
             if (got < len) {   /* fill the rest with silence, then */
                 VC_SilenceBytes((SBYTE *) &stream[got], (ULONG)(len-got));
    @@ -124,7 +120,9 @@ static int SDLDrv_Init(void)
         if (VC_Init())
             return 1;
    
    
    -    enabled = -2; /* delay the callback 2 frames */
    +    enabled = -1;
    +    SDL_PauseAudio(0);
    +
         return 0;
     }
    
    @@ -145,7 +143,9 @@ static int SDLDrv_Reset(void)
    
     static void SDLDrv_Update( void )
     {
    -/* do nothing */
    
    +    if (enabled < 0) {
    +        enabled = 1;
    +    }
     }
    
     static void SDLDrv_PlayStop(void)
    
     
  • Ozkan Sezer

    Ozkan Sezer - 2026-05-10

    Tested the patch on windows-10 too, and applied as b8e3709ebf58ac4d28479bfaec33b9499dcc598c

     
  • Stephane Denis

    Stephane Denis - 2026-05-10

    Yes that's a good approach. i approve.

     

Log in to post a comment.

MongoDB Logo MongoDB