Curious dll problem
BlitzMax Forums/BlitzMax Programming/Curious dll problem
| ||
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? |
| ||
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. |
| ||
GCEnter? |
| ||
It's required at the beginning of any exposed function, for memory management. |
| ||
I presume you've tried just adding a return value to see if it is that? (i.e. return true) |
| ||
No, but I have other functions in the loop that do not return any value, and they do not cause a crash. |
| ||
I notice that you haven't set a variable type for HEntity, could this be affecting anything? |
| ||
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 |
| ||
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. |
| ||
HEntity is just an integer, so it shouldn't need to be freed, right? |
| ||
From the docs: After converting an object to an integer handle, you must later release it using the Release command. |
| ||
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. |
| ||
meh, I dunno then |
| ||
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 |
| ||
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. |
| ||
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. |
| ||
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. |
| ||
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" |
| ||
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. |
| ||
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. |
| ||
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. |