2 registered members (AndrewAMD, NeoDumont),
761
guests, and 1
spider. |
Key:
Admin,
Global Mod,
Mod
|
|
|
Crash on removing locally created panels using ptr_remove
#473390
07/02/18 15:58
07/02/18 15:58
|
Joined: Apr 2002
Posts: 680 Germany
Turrican
OP
User
|
OP
User
Joined: Apr 2002
Posts: 680
Germany
|
Our game crashes on certain occasions with varying probability (about 50-75% of all cases on affected systems). We collected data from more than 20 test participants – all affected systems run Windows 10, no crashes under Windows 7. Description: All crashes occur while removing locally created panels. Some of these panels consist of one or more panel elements created at runtime, others have no special elements assigned (see examples below). Crash reproduction failed in dev version; it can only be reproduced in the published version. We are using a lot of both globally and locally created objects (panels, entities, texts, strings) in our code and so far only removal of local panels seems to lead to crashes. Could you please give us a hint on how can we debug and fix this? What happens internally during the removal of (local) panels? Does 3DGS support have suitable tools or better ways to analyze these crashes in the published version more precisely? On a side-note, we have already tried analyzing panel objects using sys_markers and found out that these instructions – unlike others we checked – don’t carry a control byte. How are these handled internally? Do panels allocate memory using sys_malloc? How/where are panels and panel elements stored internally? Examples1. Simple fadescreen
// Simple: We create a fullscreen, plain color panel as fade screen during a cutscene.
// Game crashes [sometimes] after cutscene finished and fadescreen panel is removed.
function intro_sequence()
{
// ...
PANEL* _pan_fadescreen = pan_create("red=0; green=0; blue=25; alpha = 100; flags = SHOW | LIGHT | TRANSLUCENT | UNTOUCHABLE;",89);
_pan_fadescreen.size_x=1920;
_pan_fadescreen.size_y=1080;
_pan_fadescreen.scale_x=screen_size.x/1920;
_pan_fadescreen.scale_y=screen_size.y/1080;
// ...
while(SEQUENCE_RUNNING)
{
if(SCENE==FIRST_SCENE)
{
// ...
_pan_fadescreen.alpha-=10*time_step;
_pan_fadescreen.alpha=clamp(_pan_fadescreen_alpha,0,100);
// ...
}
// ...
if(SCENE==LAST_SCENE)
{
// ...
_pan_fadescreen.alpha+=10*time_step;
_pan_fadescreen.alpha=clamp(_pan_fadescreen_alpha,0,100);
// ...
}
// ...
wait(1);
}
// ...
diag("n Removing panel..."); // this is the final line in acklog.txt
ptr_remove(_pan_fadescreen);
_pan_fadescreen=NULL;
diag("OK!"); // does not appear in acklog
// ...
}
2. „Abort Cutscene“ panel
// This one is a bit more complex and also uses additional panel elements instructions, like
// pan_setstring and pan_setcolor.
// Game crashes [sometimes] after cutscene finished/has been cancelled and message panel is removed.
function cancel_cutscene_message()
{
// create panel
PANEL* _pan_skip = pan_create("alpha = 0; flags = ARIGHT | SHOW | TRANSLUCENT | FILTER | SHADOW;",9999);
_pan_skip.scale_x = screen_size.x/1920;
_pan_skip.scale_y = screen_size.y/1080;
// create panel elements
temp=pan_setstring(_pan_skip,0,1900,20,fnt_button_tiny,label_mm_skip);
pan_setcolor(_pan_skip,1,temp,FONT_COLOR_MM_SKIP);
// fnt_button_tiny: truetype font
// label_mm_skip: unicode (!) string contained in global text object
// FONT_COLOR_MM_SKIP: globally defined vector
while(cutscene_active)
{
// ...
// ...
// wait for end of cutscene or player input
// ...
// ...
wait(1);
}
diag("removing panel..."); // this is the final line in acklog.txt
ptr_remove(_pan_skip);
diag("OK"); // does not appear in acklog
}
|
|
|
Re: Crash on removing locally created panels using ptr_remove
[Re: Ezzett]
#473397
07/02/18 20:34
07/02/18 20:34
|
Joined: Oct 2007
Posts: 5,210 Ä°stanbul, Turkey
Quad
Senior Expert
|
Senior Expert
Joined: Oct 2007
Posts: 5,210
Ä°stanbul, Turkey
|
wait and local pointers are bad news, try tracking those and Ezzett says do a null check if you can't figure it out try storing them on a temporary global variable.
3333333333
|
|
|
Re: Crash on removing locally created panels using ptr_remove
[Re: Ezzett]
#473402
07/03/18 11:54
07/03/18 11:54
|
Joined: Apr 2002
Posts: 680 Germany
Turrican
OP
User
|
OP
User
Joined: Apr 2002
Posts: 680
Germany
|
What happens if you add a check for null before using pointer remove? You can also debug your code with the help of the Visual Studio debugger. You just need to convert the code to an engine SDK project. But I don't know how helpful this will be because you can't inspect what happens internally in Acknex and it's not possible to use wait-instructions. So you need to rewrite all functions that use wait. Quite frankly, I can't imagine why the pointer should be NULLed during the execution of the script - unless Quad is right and wait commands allow for random/unwanted modification of pointer contents. Anyway, I will give it a try later. Concerning the Visual Studio hint: I'm sure it's well-intentioned, but I would like to refrain from that - the project has grown really large at this point and there are quite a lot of wait loops in it. Rewriting all of this would really exceed my time budget. And as you said: You can't inspect what happens internally, anyway. wait and local pointers are bad news, try tracking those and Ezzett says do a null check if you can't figure it out try storing them on a temporary global variable. Quad, do you have any examples that show how wait commands can break/overwrite contents of a local pointer...? Never heard of that before, and it would be really critical, since we're using them all over the place.
|
|
|
Re: Crash on removing locally created panels using ptr_remove
[Re: Ezzett]
#473411
07/03/18 15:41
07/03/18 15:41
|
Joined: Sep 2003
Posts: 6,861 Kiel (Germany)
Superku
Senior Expert
|
Senior Expert
Joined: Sep 2003
Posts: 6,861
Kiel (Germany)
|
While the content of local variables is preserved, their addresses change after every wait() because the function runs every time in a different stack frame. He is not using pointers to local variables, just saving the results of create or memory allocations in local variables (pointers). Those memory addresses are the *content* in the context of the quote and thus are preserved during wait, not the addresses of the actual local variables themselves.
"Falls das Resultat nicht einfach nur dermassen gut aussieht, sollten Sie nochmal von vorn anfangen..." - Manual Check out my new game: Pogostuck: Rage With Your Friends
|
|
|
Re: Crash on removing locally created panels using ptr_remove
[Re: Superku]
#473416
07/03/18 19:57
07/03/18 19:57
|
Joined: Oct 2007
Posts: 5,210 Ä°stanbul, Turkey
Quad
Senior Expert
|
Senior Expert
Joined: Oct 2007
Posts: 5,210
Ä°stanbul, Turkey
|
I do not know how lite-c compiles code or wait works internally but yes, Doing stuff like below sometimes resulted in random crashes:
void someAction(ENTITY* e){
....
PANEL* a = pan_create(...)
....
while(something){
//using a/e here sometimes causes strange behaviour, mostly crash
wait(1);
}
//also here
}
I say "sometimes", mostly it works as intended. I encountered it several times to remember it happening, when you mix wait_for and ptr_remove and juggle pointers around you encounter it at some point. Reducing number of wait/wait_for's or moving things to global scope gets rid of the issue. I only use one wait in main loop and PRAGMA_POINTER since a loong time but: One workaround was this (apart from moving to global scope):
void someAction(){
....
PANEL* a = pan_create(...)
me.skill15 = (var)a;
....
while(something){
a = (PANEL*) me.skill15;
//no crash anymore when using a
wait(1);
}
}
Think of the above code as a healthbar panel code for a couple of rts character like entities, just before crash you would see healthbars start positioning incorrectly, then you get the crash. Mostly while trying to remove some of them. It could be unrelated or related to something else(can't guess what lite-c compiler does) but because of the fix above and moving to global fixing the issue, i always had the impression that somehow pointer the "a" loses it's value. (it could not have been moved around because me.skill15 points to same address, it can only mean "a" loses the address), when a loses the address ptr_remove crashes. I could not reproduce the "sometimes" scenario in latest A8 but, it could be that it's fixed since then or my test code is not complex enough to confuse lite-c compiler. I am not doing anything complex with lite-c since a long time, and using only one wait even longer than that, so it's most likely fixed in early versions of A7.
Last edited by Quad; 07/03/18 19:58.
3333333333
|
|
|
Re: Crash on removing locally created panels using ptr_remove
[Re: Quad]
#473417
07/03/18 20:12
07/03/18 20:12
|
Joined: Feb 2006
Posts: 1,011 Germany
pegamode
Serious User
|
Serious User
Joined: Feb 2006
Posts: 1,011
Germany
|
I usually use some defines like that:
#define _pan_remove(pan) if(pan != NULL) { if(pan->bmap != NULL) { bmap_purge(pan->bmap); ptr_remove(pan->bmap); pan->bmap = NULL; } if(pan->mouse_map != NULL) { bmap_purge(pan->mouse_map); ptr_remove(pan->mouse_map); pan->mouse_map = NULL; } if(pan->target_map != NULL) { bmap_purge(pan->target_map); ptr_remove(pan->target_map); pan->target_map = NULL; } ptr_remove(pan); } pan = NULL
#define _bmap_remove(bmap) if(bmap != NULL) { bmap_purge(bmap); ptr_remove(bmap); } bmap = NULL
#define _ptr_remove(ptr) ptr_remove(ptr); ptr=NULL
So I can do some NULL checks later.
|
|
|
Re: Crash on removing locally created panels using ptr_remove
[Re: pegamode]
#473423
07/04/18 13:50
07/04/18 13:50
|
Joined: Jul 2000
Posts: 27,986 Frankfurt
jcl
Chief Engineer
|
Chief Engineer
Joined: Jul 2000
Posts: 27,986
Frankfurt
|
It's clear that when you use a local panel pointer, and something happens to that panel while the function is still running, it will crash. Such a crash happens randomly, since you're accessing memory with random content. Storing the pointer in a skill is placebo coding, technically it makes no difference.
Such a crash is caused of course by removing the panel, but also by more innocent operations such as removing a bitmap, removing a different panel that shares a bitmap, or saving and loading the game.
If I would design the acknex engine today, I would implement a different allocation and release mechanism. But as it is, ptr_remove just releases the memory of the panel and all its bitmaps. There is no simple way to check if an object pointer is valid or not. The only way is to go through the list of all objects with ptr_first(), and check if the pointer is still in the list.
|
|
|
|