Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: SFML game engine crashes on exit  (Read 7926 times)

0 Members and 1 Guest are viewing this topic.

nomonkeybusiness

  • Newbie
  • *
  • Posts: 11
    • View Profile
SFML game engine crashes on exit
« on: October 22, 2009, 11:32:20 pm »
Hi all!
I've been building a simple game engine the last 5-6 weeks using sfml for rendering and input. I've had no problems at all, until just this morning. All of a sudden, the program crashes when I destroy all my managers, specifically, when destroying cRenderManager.
I can see from the callstack in debug, that the problem arises in ~cRenderManager() and all that happens there is this simple line of code:
"SAFE_DELETE(m_pMainRenderWindow);"
with the macro-definition as follows:
"
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) if(p) { delete p; } p = NULL;
#endif // SAFE_DELETE
"
I can also see from the callstack that it involves functions from the files free.c, dbgdel.c and dbgheap.c, from msvcr90d.dll.
It definitly seems like there is some sort of memory proplem, but I have no idea how to solve it. Do anybody know?

Edit: It does not matter if I delete m_pMainRenderWindow in the destructor or anywhere else. As soon as I try to delete it, the error arises.

Edit 2: I just noticed that If I do not delete the renderwindow, an error arises in the cGraphicalEntitys destructor, where I try to delete their sf::Sprite membervariables.
If I do NOT delete any of them, an error arises anyway in free.c, on line 109:
"retval = HeapFree(_crtheap, 0, pBlock);
 if (retval == 0)
 {
       errno = _get_errno_from_oserr(GetLastError());
 }"

Please help me, I'm really no expert on memory allocations.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
SFML game engine crashes on exit
« Reply #1 on: October 24, 2009, 12:07:19 pm »
Do you link to SFML debug libraries ("-d" suffix) when you compile in debug mode?

You should avoid using your SAFE_DELETE macro: there's no need to test the pointer to delete (delete NULL works fine), and hiding "p = NULL" inside a macro is not a good idea, it's better to show it explicitely.
Laurent Gomila - SFML developer

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
SFML game engine crashes on exit
« Reply #2 on: October 24, 2009, 02:55:46 pm »
Check the pointers with the debugger, make sure their target is a valid object when the memory is deallocated. Compare the addresses you get by new to the ones you pass to delete.

Concerning SAFE_DELETE, I don't recommend this, either. Not at least because a function were much more appropriate. But I wonder how often you delete and need to set the pointer to zero? It's useless if you don't access the pointer any further (as in the destructor). Too many raw memory management should be avoided in the code, anyway. Try to encapsulate the places where you get in contact with low-level things.

Maybe you could post some code...
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

nomonkeybusiness

  • Newbie
  • *
  • Posts: 11
    • View Profile
SFML game engine crashes on exit
« Reply #3 on: October 24, 2009, 08:15:35 pm »
I do indeed use the debug-libraries. Is there anything else I should know? Like use of MFC etc.

And the pointer I delete is the same that I new.
Anyway, the engine is built so that it should be easy to create and destroy entities, which means that there are indeed some memory-allocation/deallocation going on, both for sf::Sprites and iGameEntities(or rather it's different children classes). I use my SAFE_DELETE macro pretty much anywhere I destroy stuff. So tell me, why is it wrong to use this macro?

l0calh05t

  • Full Member
  • ***
  • Posts: 200
    • View Profile
SFML game engine crashes on exit
« Reply #4 on: October 24, 2009, 08:59:03 pm »
1. deleting a null pointer is perfectly legal and safe in c++, so the check is unnecessary
2. the actual setting to NULL is hidden by the macro, which is always bad

nomonkeybusiness

  • Newbie
  • *
  • Posts: 11
    • View Profile
SFML game engine crashes on exit
« Reply #5 on: October 24, 2009, 09:03:29 pm »
Code: [Select]
nvoglnt.dll!6973d170()
 [Frames below may be incorrect and/or missing, no symbols loaded for nvoglnt.dll]
 nvoglnt.dll!6973d4fb()
 nvoglnt.dll!6975ae2a()
 nvoglnt.dll!69597bae()
 nvoglnt.dll!6958949d()
 nvoglnt.dll!6973af57()
 opengl32.dll!5ed19652()
 opengl32.dll!5ed19aad()
 opengl32.dll!5ed19c5f()
 sfml-window-d.dll!003b9069()
 sfml-window-d.dll!003bda1b()
 sfml-graphics-d.dll!101f583c()
 sfml-graphics-d.dll!101f5b20()
 sfml-graphics-d.dll!101f59d1()
 ntdll.dll!7c90118a()
 ntdll.dll!7c923ada()
 ntdll.dll!7c910435()
 ntdll.dll!7c91043e()
 ntdll.dll!7c923c88()
 kernel32.dll!7c81cb26()
msvcr90d.dll!__crtExitProcess(int status=0)  Line 732 C
msvcr90d.dll!doexit(int code=0, int quick=0, int retcaller=0)  Line 644 + 0x9 bytes C
msvcr90d.dll!exit(int code=0)  Line 412 + 0xd bytes C
Engine.exe!__tmainCRTStartup()  Line 595 C
Engine.exe!mainCRTStartup()  Line 399 C
kernel32.dll!7c817077()


Here's my call stack, when the error arises.
As you can see, some calls are made in both sfml-graphics-d.dll and opengl32.dll. This has made me to believe that my mistake lies in not freeing some memory allocated with sfml. Am I wrong?

Julien_v42

  • Newbie
  • *
  • Posts: 26
    • View Profile
    • http://tinyrpgsim.wordpress.com
SFML game engine crashes on exit
« Reply #6 on: October 24, 2009, 09:22:51 pm »
First thing that comes to mind when I hear about a crash when deleting something is "double delete".
You could try to remove deletion of items until it doesn't crash.
Maybe you took a pointer to a local variable stored in some structure (array, list, etc).

Hope this helps :)
Working on TinyRPGSim

nomonkeybusiness

  • Newbie
  • *
  • Posts: 11
    • View Profile
SFML game engine crashes on exit
« Reply #7 on: October 24, 2009, 09:44:10 pm »
But since the problem arises after it has left main(), then it shouldn't be a problem. I don't think that the program, behind the scenes tries to free memory that I allready freed myself.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
SFML game engine crashes on exit
« Reply #8 on: October 24, 2009, 10:03:30 pm »
Quote from: "nomonkeybusiness"
But since the problem arises after it has left main(), then it shouldn't be a problem. I don't think that the program, behind the scenes tries to free memory that I allready freed myself.
Do you use global or static variables? They are destroyed after main().
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

nomonkeybusiness

  • Newbie
  • *
  • Posts: 11
    • View Profile
SFML game engine crashes on exit
« Reply #9 on: October 24, 2009, 10:28:33 pm »
Other than a couple of static singletons, I use none of those. So you are saying that the problem might be some sfml-type that are ruining my program?

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
SFML game engine crashes on exit
« Reply #10 on: October 24, 2009, 10:36:50 pm »
Quote from: "nomonkeybusiness"
Other than a couple of static singletons, I use none of those. So you are saying that the problem might be some sfml-type that are ruining my program?
Why do you always blame others for the mistake? ;)

Indeed, it's very difficult to guess your error. Can't you find anything out by increasingly commenting out irrelevant parts of the program? Or by trying to check many of the pointers that come into question?

You might also try a memory-tool like valgrind...
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
SFML game engine crashes on exit
« Reply #11 on: October 24, 2009, 10:46:09 pm »
Quote from: "nomonkeybusiness"
I use my SAFE_DELETE macro pretty much anywhere I destroy stuff. So tell me, why is it wrong to use this macro?
Some reasons listed up, point 1 to 3 have already been mentioned. Many of the arguments refer to macros in general (not or not only yours).

1. if(p) delete p;
Checking for null pointers before delete is useless. As delete performs the comparison itsself, you don't gain anything by doing it a second time.

2. p = NULL;
Resetting the pointer to null is not obvious from the macro name. What does "safe" mean? Now you know it, but what about other people looking at your code, or even you after you haven't worked at this project for a while?

3. p = NULL;
It's probable, that the functionality to reset the pointer after deallocation is not even required, for example in a destructor. Not only that you are wasting few performance, this can be a source of error. Yes, you heard right, resetting to null is not always making code safer.

The reason is: The preemptive null-assignment nicely hides logic errors. Let's assume you deleted a pointer by mistake too early (may happen).
Code: [Select]
// code...
SAFE_DELETE(Pointer); // this should be done later for correct code
// a lot of code...
DoSomething(Pointer);
Code: [Select]
void DoSomething(Element* Pointer)
{
    if (Pointer)
       PerformCrucialOperations(*Pointer);
}

Very fine. Resetting the pointer makes the program stable, as it doesn't crash by a invalid pointer dereferencing. But - is this really wanted? The crucial operations aren't performed. It's likely you notice that only later, in a totally different function. Very funny to debug this. An instant crash, however, would have immediately shown the problem where it arises.

4. Evaluation (very important)
Code: [Select]
#define SAFE_DELETE(p) if(p) { delete p; } p = NULL;You should know that the expression p is evaluated three times, and indeed in every case the macro is expanded. Thats's almost always bad and one of the reasons why functions should be preferred in this context.

Let's regard a more complex argument to SAFE_DELETE:
Code: [Select]
SAFE_DELETE(GetPointer()); // where GetPointer() is a slow operationAs you see, the whole slow operation is performed three times, which is absolutely unnecessary. More than that, it can even be very dangerous. Consider this example:
Code: [Select]
Element* Ptr = GetPointerBeforeElementToDelete();
SAFE_DELETE(++Ptr);
This is very evil, because the pointer is incremented three times, thus leading to undefined behaviour because checking for null, deleting, and resetting to null refer to three different addresses.

5. Operator precedence
Not very relevant here, but macros have generally got problems with priorities. ;)
They often require to write down a forest of parentheses. Example:
Code: [Select]
#define PRODUCT(a,b) a*b
int result = PRODUCT(1+3, 2);
What do you expect as result? Hint: It's not 8.
The result is seven. That is because the macro expands to the following code:
Code: [Select]
int result = 1+3*2;Another problem functions don't have.

6. Type safety
Macros are not typesafe. Because they are just dumb text replacement, no type can be associated.
Code: [Select]
void func(double);
void func(float);

#define MYFLOAT 3.1415
func(MYFLOAT);
Because the macro-definer forgot to append the "f" prefix for floats, the wrong function is invoked. This wouldn't have happened with a typesafe constant:
Code: [Select]
const float MYFLOAT = 3.1415;
7. Lifetime
Preprocessor symbols do not survive the preprocessor. They are invisible to compiler and debugger, making error search more difficult.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

nomonkeybusiness

  • Newbie
  • *
  • Posts: 11
    • View Profile
SFML game engine crashes on exit
« Reply #12 on: October 24, 2009, 11:12:44 pm »
Quote from: "Nexus"
Why do you always blame others for the mistake? ;)
You might also try a memory-tool like valgrind...


I absolutely consider this my fault. I don't think that the problem is inside sfml, the reason I post here, is because the problem seems related to sfml, so I wan't to know if something happens inside sfml, that I am unaware of, and therefore, make some mistake.

I will check that out. It's for checking meamory-leakage, am I right?

Quote from: "Nexus"
lesson


Thanks for the lesson :)
It's always good to be "corrected", as I always strive to learn as much as I can.
If setting the pointer to NULL in safe-delete is bad, then I won't do it. My thoughts on the name "SAFE_DELETE" were to assure myself of both deleting and nulling the ptr. I don't really know why. I think I saw someone else do it, and it looked kind of handy. I'm lazy :/

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
SFML game engine crashes on exit
« Reply #13 on: October 24, 2009, 11:44:52 pm »
Quote from: "nomonkeybusiness"
I will check that out. It's for checking meamory-leakage, am I right?
I don't know valgrind myself. I haven't had that kind of error for a while, and for the other cases there is still my own little memory observator (I programmed it some time ago to learn more about memory management and new/delete overloading, but it's not fully well-engineered)...

Quote from: "nomonkeybusiness"
Thanks for the lesson :)
It's always good to be "corrected", as I always strive to learn as much as I can.
No problem. If you're not sure about macros one day, look into this thread again. ;)
I hope I could explain you some important issues.

Quote from: "nomonkeybusiness"
If setting the pointer to NULL in safe-delete is bad, then I won't do it. My thoughts on the name "SAFE_DELETE" were to assure myself of both deleting and nulling the ptr.
If you really need the functionality often, it's of course good practice to write it once and reuse it. I am just wondering a little because I rarely work with manual memory management (encapsulation inside classes is the point), and when I do, I don't use delete p; p = 0; as often that an own function would be appropriate.

Anyway, a function template with clear name is the better choice:
Code: [Select]
template <typename T>
void DeleteAndReset(T* Pointer)
{
    delete Pointer;
    Pointer = 0;
}

But the best approach is still to reflect every time you want to invoke the function, if delete and reset is required or if it's sufficient to deallocate the memory.

Quote from: "nomonkeybusiness"
I don't really know why. I think I saw someone else do it, and it looked kind of handy. I'm lazy :/
No, your approach is okay. It's very hard to estimate such things if you haven't got a lot of experience with this specific problem (this includes hours of futile debugging :)). So I want to save you from some evil pitfalls. There will still be enough of them, anyway... :D
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

 

anything