Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

ExternalCallback crashes image

57 views
Skip to first unread message

Joe Betz

unread,
Dec 1, 2022, 9:55:32 AM12/1/22
to
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.

Blair McGlashan

unread,
Dec 31, 2022, 8:20:30 AM12/31/22
to
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.

Joe Betz

unread,
Dec 31, 2022, 4:56:25 PM12/31/22
to
> 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 *****

Joe Betz

unread,
Dec 31, 2022, 5:12:24 PM12/31/22
to
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?
0 new messages