Debugger error - scope stack underflow

BlitzMax Forums/BlitzMax Programming/Debugger error - scope stack underflow

Who was John Galt?(Posted 2008) [#1]
I have a piece of code that seems to run fine without debug on, but with debug it gives 'Scope stack underflow'. Any ideas? The code is large...


Azathoth(Posted 2008) [#2]
You're doing something you shouldn't be doing? Without some kind of mind reading abilities (or the source code) no one can give you an accurate answer.


Who was John Galt?(Posted 2008) [#3]
Usually I would agree with you, but as this is an unusual error that doesn't seem to pinpoint where it's coming from. I thought someone may come up with something like 'I had this error... turned out to be I was doing <whatever>'. This could give me a clue before I have to spend ages stripping the example down to something postable.


GfK(Posted 2008) [#4]
http://www.blitzbasic.com/Community/posts.php?topic=63181

Any help?


tonyg(Posted 2008) [#5]
From debugger.stdio.bmx :
Function OnDebugLeaveScope()
	GCSuspend

	If Not scopeStackTop DebugError "scope stack underflow"

	If currentScope.scope[DEBUGSCOPE_KIND]=DEBUGSCOPEKIND_FUNCTION funcLevel:-1
	
	scopeStackTop:-1

	If scopeStackTop
		currentScope=scopeStack[scopeStackTop-1]
	Else
		currentScope=New TScope
	EndIf

	GCResume	
End Function

Scopestacktop seems to be a private global. I have no idea what its for so would really need Mark to explain what's happening. From the link Gfk posted, Mark needs sample code.
I would suggest adding profile information to output enter/exit functions to narrow down where the problem is.


Who was John Galt?(Posted 2008) [#6]
Thanks, fellows.

I'm not really any the wiser, so I guess it will be a complete strip required. I am using callbacks with an external dll, though, so maybe that's something to do with it.


Difference(Posted 2008) [#7]
I am using callbacks with an external dll, though, so maybe that's something to do with it.

I *think* (somebody correct me if this is wrong) I remember having to write "win32" after a certain callback procedure declaration?
Like this:
Function MycallBack(param:int) "win32"


Who was John Galt?(Posted 2008) [#8]
I'll give it a whirl, Peter. The funny thing is, all the dll interaction was up and working fine. I made a bunch of changes and the errors started, but none of that was code interacting with the dll.

Are function pointers allowed to point to functions declared within a type?


Dreamora(Posted 2008) [#9]
BM is not callback safe. The GC will bomb out when you use Callbacks that can be called asyncronous through an outside application / DLL.
But that normally results in a different error and happens in release and debug.


Who was John Galt?(Posted 2008) [#10]
Is there a way around that, Dreamora? Will disabling the GC in the callback sort it?


Dreamora(Posted 2008) [#11]
You could try if GCSuspend / GCResume work (they seem to be mainly have been added for a potential addition of DLL compile capability).
But I wouldn't bet it does, GC driven environments are not meant to be influenced by non managed stuff outside their scope.


Who was John Galt?(Posted 2008) [#12]
Arse.

Replacing that callback with an empty function stops the crash. Is there any way to implement a callback in Max that plays nice? This is a real pain in the nether regions.

Mark....Skid....?


Dreamora(Posted 2008) [#13]
Nope there isn't

As mentioned, the GC is not callback / thread safe.

Just don't do it ...

What exactly are you trying to achieve? Depending on that there might be a different way to do it thats more appropriate.


skidracer(Posted 2008) [#14]
It's more likely the stack is being corrupted due to incorrect calling conventions or object corruption.

If Blitzmax wasn't callback safe it would be more useless than a useless thing, I certainly wouldn't have got hooked on it.

If the dll invokes callbacks from threads other than the original caller (audio engines would possibly prefer it) then it should be specifically documented as such as it will trip up any non threaded environment not just max.


Gabriel(Posted 2008) [#15]
I agree with Skid. If I get bizarre errors like this, incorrect calling conventions or incorrectly passed pointers are always the first thing I look for.


Who was John Galt?(Posted 2008) [#16]
I'm trying to do some 'on the fly' audio creation using fmod streaming. Thanks for the suggestions. I'll just have to keep on digging.


Dreamora(Posted 2008) [#17]
Well on a single core you might not run into problems or if your DLL doesn't run in its own thread (defeats the point of using a DLL that is meant to bypass BMs incapability of asyncron / streaming handling of data / streams), then the callbacks might not be a problem.

But I would guess the chances are dropping drastically that you'll find enough single cores in the future to please this requirement.

It would be simpler if there was a NoGC flag for functions which tell the GC not to touch it at all unless GCCollect is called.

Some of that might somewhere in the future be solved when a multi process system or alike is present.


Who was John Galt?(Posted 2008) [#18]
Okay... managed to cut out a lot of the rubbish and produce a small example.

Graphics 800,600,32,0

Global tonelisthead:tone=Null
Global tonelisttail:tone=Null

Type tone
	Const slider_width=700
	Global n_tones=0
	Const dt#=1.0/44100.0
	Field channel=0
	Field amp#=0
	Field freq#=0
	Field phi#
	Field dphi#
	'Field amp_slider:sg_slider
	'Field freq_slider:sg_slider
	Field _next:tone=Null
		
	Function Create:tone()
		newtone:tone=New tone

		n_tones:+1
		
		If tonelisthead
			tonelisttail._next=newtone
			tonelisttail=newtone
		Else
			tonelisthead=newtone
			tonelisttail=newtone
		EndIf
		
		Return newtone
	End Function
	
	Method setfreq(freq#)
		Self.freq=freq
		Self.dphi=360.0*Self.freq*dt
	End Method
End Type

Const tonesmax=2
For n=1 To tonesmax
	mytone:tone=tone.Create()
	mytone.setfreq(60.0)
	mytone.amp=30000.0
	mytone.channel=(n-1) Mod 2
Next


Function makesignedshort:Short(float_num#)
	x=Long(float_num)
	val_bits:Short=Short(x&%0111111111111111)
	sign_bit:Short=Short((x Shr 16)&%1000000000000000)
	short_val:Short=Short(sign_bit|val_bits)
	Return short_val
End Function
	
Function FMOD_Stream_Callback(stream:Byte Ptr, buff:Byte Ptr, length:Int, userdata:Byte Ptr) "Win32"
	tonal:tone=tonelisthead
	While tonal
		tonal.setfreq(60.0)
		tonal=tonal._next
	Wend
	
	Local snd_ptr:Short Ptr=Short Ptr(buff)
		
	For n=0 To (length/4)-1
		Local left_float#=0.0
		Local right_float#=0.0
		
		tonal:tone=tonelisthead
	
		While tonal
			If tonal.channel=0
				left_float:+tonal.amp*Sin(tonal.phi)
			Else
				right_float:+tonal.amp*Sin(tonal.phi)
			EndIf
			tonal.phi:+tonal.dphi
			
			tonal=tonal._next
		Wend		
				
		'32767
		snd_ptr[0]=makesignedshort(left_float)		'Left speaker
		snd_ptr[1]=makesignedshort(right_float)		'Right speaker
		snd_ptr:+2
	Next
	
	tonal:tone=tonelisthead
	
	While tonal	
		tonal.phi:Mod 360.0			
		tonal=tonal._next
	Wend

	Return 1
End Function

Local CallbackPtr=Int(Byte Ptr(FMOD_Stream_Callback))

?Mac
FSOUND_SetOutput(FSOUND_OUTPUT_MAC)
?

FSOUND_SetDriver(0)
If Not FSOUND_Init(44100, 16, 0)
	Print "error"
EndIf

Local stream= FSOUND_Stream_Create(CallbackPtr, 6*2048, FSOUND_NORMAL|FSOUND_16BITS|FSOUND_STEREO, 44100, Null)
FSOUND_Stream_Play(FSOUND_FREE, stream)

If (FSOUND_Stream_Play(FSOUND_FREE, NSFStream) = -1)
	Print("Error!")
EndIf

finished=0
Repeat
	Cls
	DrawText "test",100,100
	Flip
Until KeyHit(KEY_ESCAPE)


FSOUND_Stream_Close(stream)
FSOUND_Close()

End


I would really appreciate if anyone can come up with any suggestions, or better still, if you have fmod installed or are prepared to install it, give it a run. This should produce a continuous 60Hz tone generated on the fly. With debug switched on I'm getting the dreaded scope stack error. This is stumping me, because as I said, this was up and working before I added some unrelated stuff to the project (working on the gui), now even this short example seems fragged. From what I read, FMOD is only single threaded, so there shouldn't be a problem there.


grable(Posted 2008) [#19]
Hmm, im using fmod 3.74 (the only one i could find) so this might be because of that.

For me it just exits after 1/2 second without making a sound. No debug error.
Then again, without debug i get no sound either. sooo..

But when adding a debuglog on enter/exit i get : setMemBit error: membit already set
on this line:
		While tonal
			If tonal.channel=0   <------
				left_float:+tonal.amp*Sin(tonal.phi)
			Else


If there is a newer module, could someone point me in the right direction?

EDIT: if i add the NoDebug directive to the callback, i get the stack underflow error after a few runs of the function.


Who was John Galt?(Posted 2008) [#20]
Hey thanks a lot for your help, Grable. I'm not sure what's going on here. fmod 3.74 is what I'm using, but I do get a sound played, and it doesn't seem to crash with debug off.

Is your setup of fmod definitely calling the callback? Stick a drawtext in the fmod_stream_callback function if you're not sure. This would give some confidence that fmod is at least partially doing what it should. I'm assuming you're on XP (as I am)?

The setmembit error could be a lead although I don't get that. I'm guessing its something to do with the garbage collector.


grable(Posted 2008) [#21]
It is called, as the DebugLogs at enter/exit prints what they should.

Changing code and calling other functions from within the callback causes random crashes and errors.
This is usually how i know i have messed up calling conventions, ie the stack is totaly screwed or the GC is misbehaving.

But it might also be my version of the module is somehow trashed, as i should be able to get sound in non debug mode like you.
I have tested it with other minor examples without trouble though :/

Oh, yeah im on XP as well.


Who was John Galt?(Posted 2008) [#22]
If you only have headphones or a small speaker, try upping the frequency from 60.0<tonal.setfreq(60.0)> as maybe you won't hear something that low. No idea regarding the crashes you are seeing though. I think it's unlikely your module is trashed if you've had working examples.


grable(Posted 2008) [#23]
If you only have headphones or a small speaker, try upping the frequency from 60.0<tonal.setfreq(60.0)> as maybe you won't hear something that low

Yeah, i have some cheap'o mini speakers so that did it ;)


Damien Sturdy(Posted 2008) [#24]
I don't have any of the modules required, but i'll take a look on the weekend if I can. We are using callbacks heavily in Flow and are not suffering problems, literally thousands of times a seconds sometimes.

One thing that DOES give us headaches are casting pointers, so that's where i'd look first. I do not like seeing code like

"Short Ptr(etcptr)"

Because I do not trust them, they've always caused problems for us! I'm not saying not to use, but those are the lines i'd be suspicious of.


Who was John Galt?(Posted 2008) [#25]
Dude, I really appreciate your efforts. I promise to Pimp Flow whenever the chance arises! I will go back and take a look myself.