Dissonance icon indicating copy to clipboard operation
Dissonance copied to clipboard

[bug] ArgumentException: GCHandle value belongs to a different domain

Open ximael opened this issue 10 months ago • 8 comments

I have Main Menu scene and Game scene. In the Game scene I've added Dissonance prefab (you can see its settings here)

  1. Start network game (one client is host)
  2. Host quits the game (to menu or the app itself)
  3. Clients are disconnected and are trying to load the main menu
  4. The game freezes and this error in the log.

This happens not every time, maybe 25%. I suppose, something with the GC.

Unity 2022.3.7f1 LTS Netcode for gameobjects Facepunch transport Dissonance with fmod playback and recording

Error text in the log: Unloading 5 Unused Serialized files (Serialized files now loaded: 4) ArgumentException: GCHandle value belongs to a different domain at System.Runtime.InteropServices.GCHandle.op_Explicit (System.IntPtr value) [0x00020] in :0 at System.Runtime.InteropServices.GCHandle.FromIntPtr (System.IntPtr value) [0x00000] in :0 at Dissonance.Integrations.FMOD_Playback.FMODVoicePlayback.ShouldProcessDSP (FMOD.DSP_STATE& dsp_state, System.Boolean inputsidle, System.UInt32 length, FMOD.CHANNELMASK inmask, System.Int32 inchannels, FMOD.SPEAKERMODE speakermode) [0x0003a] in F:\Git\TavernCoop\Assets\Packages\Dissonance\Integrations\FMOD_Playback\FMODVoicePlayback.cs:270 at (wrapper native-to-managed) Dissonance.Integrations.FMOD_Playback.FMODVoicePlayback.ShouldProcessDSP(FMOD.DSP_STATE&,int,uint,FMOD.CHANNELMASK,int,FMOD.SPEAKERMODE) UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object) UnityEngine.DebugLogHandler:LogException(Exception, Object) UnityEngine.Logger:LogException(Exception, Object) UnityEngine.Debug:LogException(Exception) UnityEngine.<>c:<RegisterUECatcher>b__0_0(Object, UnhandledExceptionEventArgs) (at C:\build\output\unity\unity\Runtime\Export\Scripting\UnhandledExceptionHandler.bindings.cs:46)

(Filename: F:/Git/TavernCoop/Assets/Packages/Dissonance/Integrations/FMOD_Playback/FMODVoicePlayback.cs Line: 270)

And right after the error: UnloadTime: 140.743600 ms Unloading 1632 unused Assets / (0.66 GB). Loaded Objects now: 205304. Memory consumption went from 2.24 GB to 1.58 GB. Total: 159.469400 ms (FindLiveObjects: 12.092000 ms CreateObjectMapping: 13.194300 ms MarkObjects: 32.183300 ms DeleteObjects: 101.999200 ms)

//End of the log file

FMODVoicePlayback.cs Line: 270: var ud = GCHandle.FromIntPtr(userdata);

ximael avatar Mar 25 '24 18:03 ximael

This looks like it might be an editor only issue - can you confirm if this happens in player builds?

martindevans avatar Mar 25 '24 19:03 martindevans

It happend in the player build (win, mono, .NET Framework). I'm trying to reproduce it on one pc, but no luck yet.

ximael avatar Mar 25 '24 20:03 ximael

Can confirm that this happens in build too. Exact same situation, Dissonance, Steamworks + Fmod. Host leaves, clients disconnect and try to load menu scene. Some succeed others crash and this is the last log.

alexonskull avatar Jun 11 '24 06:06 alexonskull

It looks like this might happen if the GCHandle is left set as the "user data" in FMOD. As far as I can tell FMOD makes a callback even after it has been stopped, however that callback is now trying to access resources that were disposed in the scene transition and causes this error.

To handle this, could you try making the following changes:

In Teardown() (line 99):

if (_channel.hasHandle())
{
    _channel.stop();
    _channel.setUserData(IntPtr.Zero); // <---- Add this
    _channel.removeDSP(_dsp);
    _channel.clearHandle();
}

 if (_dsp.hasHandle())
{
    _dsp.setUserData(IntPtr.Zero); // <---- Add this
    _dsp.release();
    _dsp.clearHandle();
}

In ChannelEventCallback (line 217):

if (!Check(channel.getUserData(out var userdata), "Failed to getUserData from channel"))
    return RESULT.OK;

if (userdata == IntPtr.Zero)
    return RESULT.OK; // <---- Add this

In ReadDSP (line 242):

if (gudResult != RESULT.OK || userdata == IntPtr.Zero) // <---- Add this final check into existing if statement
{

In ShouldProcessDSP (line 261):

if (gudResult != RESULT.OK || userdata == IntPtr.Zero) // <---- Add this final check into existing if statement
    return RESULT.OK;

The first change should clear the invalid GCHandle from FMOD when it is destroyed. The rest of the changes add checks in everywhere that FMOD might try to use that invalid value, simply early exiting from the callback.

martindevans avatar Jun 11 '24 13:06 martindevans

Note: If these changes work for you please tell me and I will incorporate them into the package :)

martindevans avatar Jun 11 '24 13:06 martindevans

Thank you! Implemented them now, I will run a few tests and let you know!

alexonskull avatar Jun 12 '24 17:06 alexonskull

Crash hasn't happened since, I did a bit of forced testing, loading and unloading the same game instance, as well as a lot of regular game testing we did. Seems to have been fixed.

alexonskull avatar Jun 18 '24 07:06 alexonskull

Thanks for testing that. I'll include these changes in an update to the main package soon.

martindevans avatar Jun 18 '24 12:06 martindevans