if(rect.m_Background.m_pTexture && rect.m_Background.m_pTexture->CanUse())
Getting null pointer crashes
if(rect.m_Background.m_pTexture && rect.m_Background.m_pTexture->CanUse())
Getting null pointer crashes
In Java, having a null pointer doesnāt crash, right ?
Iām not sure.
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?
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.
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.
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