Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safely check if `this` is null

First of all, I'm aware that calling a method on a null pointer is undefined behavior. I also know that, because this is not supposed to happen, compilers can (and do) assume this to always be non-null.

But in real code, you sometimes do it accidentially. Usually, it has no ill effects, except that of course this is null in the method, and things may crash.

As a debugging aid, and in the spirit of crash-early, I put assert(this != 0) in a method that I accidentially called on null pointers a couple of times before. It seems to work, but clang complains with:

warning: 'this' pointer cannot be null in well-defined C++ code; comparison may be
      assumed to always evaluate to true [-Wtautological-undefined-compare]
    assert (this ! = 0);
            ^~~~     ~

I wonder what the best (least incorrect) way would be to detect that this is null. A simple comparison could be optimized out.

  • I could do some pointer arithmetic on this to try and fool the compiler, or force it to treat the pointer as an integer.
  • I could use memcmp.
  • Maybe there are compiler-specific extensions to say "don't optimize this expression away"?

One additional concern is that, in case of inheritance, the "null" this pointer might actually be something like 0x00000004, so it would be nice to also handle that case. I'm interested in a solution for either Clang, MSVC, or GCC.

like image 558
jdm Avatar asked Nov 24 '16 09:11

jdm


People also ask

How do you check if this is null?

Typically, you'll check for null using the triple equality operator ( === or !== ), also known as the strict equality operator, to be sure that the value in question is definitely not null: object !== null . That code checks that the variable object does not have the value null .

Should you check for null?

It is a good idea to check for null explicitly because: You can catch the error earlier. You can provide a more descriptive error message.

Where do you put a null check?

If you have implemented layering in your project, good place to do null checks are the layers that receives data externally. Like for example: the controllers, because it receives data from the user... or the gateways because it receives data from repositories.

Why is checking for null important?

Checking for null values and initializing them is a necessary step in the implementation of a ruleset, because input objects might be null or contain null values. Objects used in the rules are either input parameter objects or objects that have been inserted in the working memory.


2 Answers

In gcc you can build with -fsanitize=null. Clang should have this option as well.

From man gcc:

       -fsanitize=null
           This option enables pointer checking.  Particularly, the application built with this option turned on will issue an error message when it tries to dereference a NULL pointer, or if a
           reference (possibly an rvalue reference) is bound to a NULL pointer, or if a method is invoked on an object pointed by a NULL pointer.

Here is a test program:

[ ~]$ cat 40783056.cpp
struct A {
  void f() {}
};

int main() {
  A* a = nullptr;
  a->f();
}
[ ~]$ g++ -fsanitize=null 40783056.cpp
[ ~]$ 
[ ~]$ ./a.out 
40783056.cpp:7:7: runtime error: member call on null pointer of type 'struct A'
like image 155
ks1322 Avatar answered Oct 10 '22 13:10

ks1322


First of all, as pointed out by the comments to this question: do try using sanitizers built into the compilers.

To answer your question: you can cast your pointer to uintptr_t and compare that value. Please note that this conversion is implementation defined and is not guaranteed to work as you expected.

The following code optimizes nothing out with clang 3.9, but removes null pointer check with gcc 7.0. 0x10 has been chosen arbitrarily.

struct foo
{
  void bar() {
      if(this == nullptr) {
        sink(__LINE__);
      }
      if((uintptr_t)this < 0x10) {
        sink(__LINE__);
      }
      if((volatile uintptr_t)this < 0x10) {
        sink(__LINE__);
      }
  }
};

demo

like image 29
krzaq Avatar answered Oct 10 '22 11:10

krzaq