Curious dll problem

BlitzMax Forums/BlitzMax Programming/Curious dll problem

JoshK(Posted 2006) [#1]
First, I realize BlitzMax dlls are uncharted territory, so I may be dealing with a totally unknown problem.

I compiled my 3D engine into a dll, and am calling it from BlitzPlus. I wrote a BlitzPlus program to load a scene and render it in a loop. After about 5 minutes of running, the program suddenly quits with no error message and no explanation.

By commenting out lines of code, I determined that my MoveEntity() command will cause the program to quit, after a few minutes of running. With the command commented out, the program does not quit unexpectedly. I tested this many times over more than one day.

The decls entry for the function looks like this:
MoveEntity(entity%,x#,y#,z#)

and the function source code looks like this:
Function dll_MoveEntity(HEntity,x#,y#,z#)
	GCEnter()
	entity:TEntity=TEntity(HandleToObject(HEntity))
	If entity
		entity.move(x,y,z)
	Else
		Notify "Entity does not exist."
	EndIf
EndFunction

I'm rather baffled by this behavior. My best guess is there is an issue with memory allocation or function return values, since the error is inconsistent.

Any ideas?


JoshK(Posted 2006) [#2]
I tried commenting out almost the entire MoveEntity() command and recompiling the dll. The program still quits unexpectedly after several minutes:
Function dll_MoveEntity(HEntity,x#,y#,z#)
	GCEnter()
	Rem
	entity:TEntity=TEntity(HandleToObject(HEntity))
	If entity
		entity.move(x,y,z)
	Else
		Notify "Entity does not exist."
	EndIf
	EndRem
EndFunction


Maybe it has something to do with the passing of variables. I thought maybe it crashed because this function has no return value, but I have other functions that have no return value.


Perturbatio(Posted 2006) [#3]
GCEnter?


JoshK(Posted 2006) [#4]
It's required at the beginning of any exposed function, for memory management.


Perturbatio(Posted 2006) [#5]
I presume you've tried just adding a return value to see if it is that? (i.e. return true)


JoshK(Posted 2006) [#6]
No, but I have other functions in the loop that do not return any value, and they do not cause a crash.


Perturbatio(Posted 2006) [#7]
I notice that you haven't set a variable type for HEntity, could this be affecting anything?


DStastny(Posted 2006) [#8]
What is the calling convention you have specified for the DLL vs the BlitzPlus DECL? They both need to be the same.

BMax default Calling convention is "C" not sure if I rember what Blitz Plus is.

Try changing
Function dll_MoveEntity(HEntity,x#,y#,z#) "win32"
	GCEnter()
	Rem
	entity:TEntity=TEntity(HandleToObject(HEntity))
	If entity
		entity.move(x,y,z)
	Else
		Notify "Entity does not exist."
	EndIf
	EndRem
EndFunction


Doug Stastny


TartanTangerine (was Indiepath)(Posted 2006) [#9]
I'd tread very carefully when you don't have control over the memory management functions yourself. If you want to make this solid then code your own and do not rely on BMAX having a handle on and freeing the memory when it should.

For example, you never declared TEntity as a new handle in memory space and you did not free that memory when the function completed. You still need to free handles since they do require a memory location.


JoshK(Posted 2006) [#10]
HEntity is just an integer, so it shouldn't need to be freed, right?


Perturbatio(Posted 2006) [#11]
From the docs:
After converting an object to an integer handle, you must later release it using the Release command.



JoshK(Posted 2006) [#12]
Yes, but I never converted an object to an integer handle in this function. The object handle gets retrieved when it is created, and freed when it is destroyed.


Perturbatio(Posted 2006) [#13]
meh, I dunno then


Regular K(Posted 2006) [#14]
Why dont you try to narrow it down to what line exactly by doing something like this:

Function dll_MoveEntity(HEntity,x#,y#,z#)
	Notify("1")
	GCEnter()
	Notify("2")
	entity:TEntity=TEntity(HandleToObject(HEntity))
	Notify("3")
	If entity
		Notify("4")
		entity.move(x,y,z)
	Else
		Notify "Entity does not exist."
	EndIf
	Notify("5")
EndFunction



JoshK(Posted 2006) [#15]
Because the function has to run for about 5 minutes before anything goes wrong. That's why this problem is hard to track down; it isn't consistent.


Gabriel(Posted 2006) [#16]
Have you confirmed that Budman's suggestion that the calling convention may be incorrect is not the problem? That has - in the past - given me inconsistent errors like this.


AlexO(Posted 2006) [#17]

Because the function has to run for about 5 minutes before anything goes wrong. That's why this problem is hard to track down; it isn't consistent.



you could do actual prints for each line or write to a file and let it run for as long as it can.


Dreamora(Posted 2006) [#18]
Did you try to add GCLeave() to the end. As you mentioned, GCEnter is needed to have GC working correctly, so I would silently assume that the Leave is needed as well to prevent "interesting aspects"


Koriolis(Posted 2006) [#19]
As suggested this sounds like a calling convention mismatch. If the called function (in the dll) expects the caller (exe) to clean up the stack after the call, but the caller (exe) expects the dll to do so, you'll very soon have a stack overflow. Normally with such a mismatch, only functions with no parameters are likely to work as expected.


JoshK(Posted 2006) [#20]
I have made the following changes:

-Added "win32" to the end of each dll function.

-Fixed the framework/import stuff at the beginning of the file (wasn't using "Framework" before, just "Import").

Dreamora, I have not used the GCLeave() command anywhere, nor has anyone told me I need to, so I don't know.

Koriolis, I agree. I have seen similar errors with calling convention mismatches in a PureBasic dll, causing a stack overflow error.

I am testing the dll now. It appears to be working so far. Will post my results later.


JoshK(Posted 2006) [#21]
Judging from my test, it appears that the "win32" tag
fixes the problem. It takes me about ten minutes to verify whether a dll is bugged or not, but this seems to be the issue.