• ExternalCallback crashes image

    From Joe Betz@21:1/5 to All on Thu Dec 1 06:55:30 2022
    How do I debug an ExternalCallback that crashes the image?

    The callback is defined as:

    ExternalCallback
    block: [ :time :event :sequencer :data | Transcript display: time; cr. nil ]
    descriptor: (ExternalDescriptor
    callingConvention: 'stdcall:'
    returnType: 'void'
    argumentTypes: 'word FluidEvent* FluidSequencer* lpvoid').

    Based on this definition (from https://www.fluidsynth.org/api/group__sequencer.html#gae6bb99d73ba67f0b7e15883b78bfae85):

    typedef void(* fluid_event_callback_t) (unsigned int time, fluid_event_t *event, fluid_sequencer_t *seq, void *data)




    Every time the callback gets invoked, the body gets executed and then the image crashes. I suspect it has to do with the return type, but I've tried returning nil, 0, 1, true, false, and self all to no avail.

    DPRO.ERRORS just has some gobbledygook about an unhandled Win32 exception, and if I put a halt statement in the callback, the crash seems to somewhere around a call to ProcessScheduler>>callback:return:, which again points to an issue with the return
    type.

    From searching this group, the problem seems to recur over and over again and there don't seem to be any general solutions.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Blair McGlashan@21:1/5 to joeb...@gmail.com on Sat Dec 31 05:20:29 2022
    On Thursday, December 1, 2022 at 2:55:32 PM UTC, joeb...@gmail.com wrote:
    How do I debug an ExternalCallback that crashes the image?


    Using the VisualStudio debugger open on the dolphin project attached to the Dolphin process. However, if you are not familiar with debugging at an assembler level, you may find the learning curve steep. Generally it is not necessary anyway. I'd start by
    googling the Win32 error code "gobbledygook" in the errors file to understand the class of problem (stack fault or other access violation), and then carefully check my callback descriptor against the API documentation and (if necessary and available) the
    source. I'd probably only crack open the VS debugger for this in the absence of complete documentation and/or source.

    The callback is defined as:

    ExternalCallback
    block: [ :time :event :sequencer :data | Transcript display: time; cr. nil ] descriptor: (ExternalDescriptor
    callingConvention: 'stdcall:'
    returnType: 'void'
    argumentTypes: 'word FluidEvent* FluidSequencer* lpvoid').

    Based on this definition (from https://www.fluidsynth.org/api/group__sequencer.html#gae6bb99d73ba67f0b7e15883b78bfae85):

    typedef void(* fluid_event_callback_t) (unsigned int time, fluid_event_t *event, fluid_sequencer_t *seq, void *data)



    I can see that the callback descriptor is incorrect - the first argument is an unsigned int, so would be 32-bits not 16, i.e. `dword` not `word`. This would cause you other problems than the crash you describe, however.



    Every time the callback gets invoked, the body gets executed and then the image crashes. I suspect it has to do with the return type, but I've tried returning nil, 0, 1, true, false, and self all to no avail.

    Returning the wrong type of object from the block will not cause the behaviour you see. In this case the return value will be totally ignored because the callback has no return value (it is `void`). If it did have a return value, then returning a type of
    object that cannot be coerced to the return type might result in Dolphin reporting an error, or it might cause a subsequent access violation if the return type is a pointer and you return nil/zero or the address of some object that goes out of scope and
    gets GC'd. None of that can possibly apply here.


    DPRO.ERRORS just has some gobbledygook about an unhandled Win32 exception, ...

    Which you are choosing to disparage because you don't understand it? It is likely that the details require to diagnose the fault are in that gobbledygook. I'd imagine the exception code is one of the stack fault codes.

    and if I put a halt statement in the callback, the crash seems to somewhere around a call to ProcessScheduler>>callback:return:, which again points to an issue with the return type.

    No, it doesn't. It suggests you have got the calling convention wrong. To be sure you'd have to examine the original source and build definition (if not documented), but the chances are that it is using the default C calling convention, so cdecl, not
    stdcall. Using the wrong one of these would certainly result in a crash on return, because these employ different conventions at to whether caller or callee is responsible for adjusting the stack pointer.


    From searching this group, the problem seems to recur over and over again and there don't seem to be any general solutions.

    The general solution is to take care to define the callback correctly. You are describing a machine level interaction, so there is almost no margin for error. If you are familiar with development at assembly level, then this requires the same level of
    precision. Many developers do not have a grounding in assembler these days (it is rather old hat), hence it is not uncommon to run into problems with describing callbacks correctly. If you do not use the correct calling convention, or you get the
    arguments or return type wrong, then the machine stack will likely be corrupted and the process will crash very directly. If you get an immediate crash, often without seeing the Windows crash report dialog, then you can safely assume you have corrupted
    the stack due to defining the callback incorrectly.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Joe Betz@21:1/5 to All on Sat Dec 31 14:12:23 2022
    Well, this is interesting. If shove the FluidEvent arguments in the callback into a local variable, the image doesn't crash. Which makes me think that the FluidEvent object was somehow garbage collected before the callback returned. And if this means
    that Dolphin releases the memory allocated to it then the external library would no longer have access to it for any post-processing or cleanup it might be doing, hence the access violation error.

    Does this make sense?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Joe Betz@21:1/5 to All on Sat Dec 31 13:56:24 2022
    I can see that the callback descriptor is incorrect - the first argument is an unsigned int, so would be 32-bits not 16, i.e. `dword` not `word`. This would cause you other problems than the crash you describe, however.

    Thanks for taking a look.

    It suggests you have got the calling convention wrong. To be sure you'd have to examine the original source and build definition (if not documented), but the chances are that it is using the default C calling convention, so cdecl, not stdcall. Using
    the wrong one of these would certainly result in a crash on return, because these employ different conventions at to whether caller or callee is responsible for adjusting the stack pointer.

    I did try both cdecl and stdcall but got the same exception type (C0000005) in each case. I'm not sure what's left at this point other than something being wrong with the FluidEvent and FluidSequencer arguments. There's nothing wrong with the values of
    the arguments in the callback body, however, so I'm at a loss.

    Which you are choosing to disparage because you don't understand it? It is likely that the details require to diagnose the fault are in that gobbledygook. I'd imagine the exception code is one of the stack fault codes.

    I looked up the exception code and what I understand is that it's throwing an access violation error after trying to execute an invalid memory address. I don't know if there is anything else to glean from it, but I've attached the full crash report below.




    ********************************************************************************
    ************************** Dolphin Crash Dump Report ***************************
    *********************** VM version: 7.1.24-0-g1bb62dcfa ************************

    22:36:32, 31/12/2022: Dolphin7.exe caused an unhandled Win32 Exception C0000005 at 34DDFD8C in module 345E0000 ()

    *----> Exception Parameters <----*
    00000008
    34DDFD8C

    *----> CPU Context for thread 0x234c <----*
    EAX = 00000000 EBX = 34DDFE0C ECX = 08A20000
    ESI = 34DDFDC4 EDI = 73BC806A EIP = 34DDFD8C
    ESP = 34DDFD80 EBP = 2D07FE30 EFL = 00010206
    CS = 0023 SS = 002B DS = 002B
    ES = 002B FS = 0053 GS = 002B

    *----> Memory Statistics <----*
    Virtual memory used: 1038Mb
    Virtual memory available: 3057Mb

    ****N.B. This exception did NOT occur in the main Dolphin execution thread ****

    *----> CPU Context for main thread 0x3404 <----*
    EAX = 00000000 EBX = 00000002 ECX = 00000000
    ESI = 00000000 EDI = 00000001 EIP = 7706586C
    ESP = 00C0F9B4 EBP = 00C0FA24 EFL = 00000206
    CS = 0023 SS = 002B DS = 002B
    ES = 002B FS = 0053 GS = 002B

    In module 77060000 (C:\WINDOWS\System32\win32u.dll)


    ***** End of crash report *****

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)