The joys of game dev in C++


if(rect.m_Background.m_pTexture && rect.m_Background.m_pTexture->CanUse())

Getting null pointer crashes :stuck_out_tongue:

In Java, having a null pointer doesnā€™t crash, right ?

Iā€™m not sure. :stuck_out_tongue:

Yes, it crashes lol.

valgrind is your friend.

What I use:

valgrind --track-origins=yes --tool=memcheck --leak-check=full --num-callers=40 ./executable

Well to be more specific, it throws an Exception. The exception can be caught to avoid a crash. That is a quite significant difference to c++ null pointers being dereferenced. In practise though it makes no difference (although I think Javaā€™s handling of exceptions makes an NPE easier to debug) since we rarely catch NPEs but rather check to see if a variable is null before dereferencing as you would in c++.

But we are good programmers so letā€™s be precise.

Java is much easier to debug just by seeing exception.

To those who donā€™t know C++, translated to java this would look like this:


if (rect.m_Background.m_Texture != null && rect.m_Background.m_Texture.CanUse())

The crash is that m_Texture is null when calling .CanUse() on it.

I donā€™t think that will crash due to a [icode]NullPointerException[/icode], I think the JVM exits the evaluation when it sees the first part of the condition as false.

Thats my problem. Iā€™m working on a big project with multiple threads, and this is a valid case. The object is not null on the first half of the if, and it becomes invalid on the second half of the if.

This is a race condition and I have no idea where it is coming from since the code base is huge and very abstracted.

Also, it doesnā€™t help that the crash is not reproducible and all I have to work with are some crash logs from live app build.

Yea in C++ even in single threaded apps, random hard to reproduce seg faults kept me awake at night. We had one bug that we could never reproduce when compiled with debug symbols.

Also conisder that in java a NPE is dealing with things properly, there is a chance that the memory is only partly ā€œfreedā€ and that you end up with ā€œunspecified behaviourā€. One of the favorite things in the C/C++ specs.

Turn off randomization of memory layout so you get a fixed address.

So, did you try valgrind? Iā€™ve never used to detect race conditions myself, but according to the blog post Valgrind is NOT a leak checker, it can.

Edit: Alternatively, if youā€™re compiling with clang, it apparently has similar features built in (address sanitizer and thread sanitizer).

My colleagues told me that they tried to get it working on the project, but they couldnā€™t get it to work. The project is iOS/Android app.

Ah, too bad; Iā€™ve heard valgrind had some issues on OSX in the past. Well in that case, clangā€™s analysis tools might be another option (I assume youā€™re already compiling with either GCC or Clang?). Might be my lack of in-depth experience with c++, but just running the unit tests with valgrind has been indispensable for tracking down bugs.

Are you sure the null pointer crash isnā€™t in the first part of the expression? ie. rect or m_background is null?

Its C++ code, by our projectā€™s coding conventions, pointer variables must start with ā€˜pā€™, as in ā€˜m_pTextureā€™, rect is not a pointer and neither is m_Background. If rect was a pointer, it would be ā€˜pRectā€™ and ā€˜m_pBackgroundā€™

If you are not familiar with C++, defining something like this already allocates memory on the stack (not on the heap)


Rectangle rect; // Valid object, allocated on the stack
Rectangle* rect; // Pointer pointing to some garbage memory location

OK so assume another thread is changing m_pTexture while this thread is looking at it.

  1. Find all places in the code the variable is modified.
  2. If they can run on parallel threads, thatā€™s your problem. Accessing a modifiable variable from multiple threads simply must be synchronized.

TBH it looks like this code was written by someone who knew it could be a problem but was trying to avoid having to synchronize, like ā€œif I check itā€™s valid before I use it surely thatā€™ll be OK!ā€. But eventually it will always get changed right in the middle after the check but before the usage.

Perhaps they didnā€™t have the stomach to make changes throughout the ā€œlarge and very abstracted code baseā€ to fix this. There may be no alternative.

FWIW re. the code style of that statement, accessing a member directly is usually bad - accessing a member via a member doubly so. If access to m_pTexture is properly encapsulated it will make it trivial to add the synchronization!

In theory this could be possible but I highly doubt that this is the case now.

Rectangle& rect = *ptr; // this might be null and leads to undefined behavior.

Hmm Iā€™m not at work right now, but Iā€™m pretty sure its not the problem. The code before ā€˜ifā€™ goes like this:


rect.m_Background.m_pTexture = m_Animation.GetCurrent() // Get current texture animation frame
if (rect.m_Background.m_pTexture && rect.m_Background.m_pTexture->CanUse())

And the crash logs only point to crash on ā€˜ifā€™ line.

Also, Iā€™m pretty sure that the check there is to ensure that there is a texture overall, not that it might be accessed by another thread. Although I think this is a bad coding practiceā€¦

The whole code base is written with ā€˜ifā€™ statements which completely silence the flow of the production app and I feel like the app could be much better if it was developed without all those null checks and the ones who were making this whole thing just started testing it sooner and ironed out all the bugs/crashes that would come up without null checks.

Anyway, thanks for suggestions.

Rect or rect.something must be null , I would try an individual statement such as rect.m_background , see what happens.
Also
rect.m_Background.m_pTexture = m_Animation.GetCurrent()
Does m return a point and is m_pTexture a pointer , if not that is the issue!


Rectangle& rect = m_cRect;

// Somewhere in the header file
Rectangle m_cRect;

// Somewhere in the Rectangle.h file
Sprite m_Background;

// Somewhere in the Sprite.h file
Texture* m_pTexture;

The only pointer here is ā€˜m_pTextureā€™ as by its name :slight_smile: