It is safe to check if `this` is null

First of all, I know that calling a method with a null pointer is undefined behavior. I also know that since this should not happen, compilers can (and do) assume that thisit will always be non-null.

But in real code, you sometimes do this by accident. Usually it has no harmful effects, except that, of course, thisit is null in the method, and everything can work.

As a debugging tool, and in the spirit of crashing early, I put assert(this != 0)in a method that I accidentally called against null pointers a couple of times earlier. This seems to work, but clang complains:

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 to detect thisis null. A simple comparison can be optimized.

  • I could do some pointer arithmetic thisto try to trick the compiler or make it treat the pointer as an integer.
  • I could use memcmp.
  • Perhaps there are compiler-specific extensions to say "don't optimize this expression"?

Another problem is that in the case of zero inheritance, this pointer may actually be something like 0x00000004, so it would be nice to handle this case as well. I'm interested in a solution for Clang, MSVC or GCC.

+4
source share
5

gcc -fsanitize=null. .

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.

:

[ ~]$ 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'
+6

-, .

Class *object = ...;
...;
if (object) {
  object->...
}

, this nullptr -, , , this nullptr . , rhs , lhs . ( , , ) ​​

, this nullptr, , , nullptr ub. assert (this!= Nullptr), == nullptr , , , ub.

ub . UB ( ), . ?

, ( assert), (O (lgn)) , , , this nullptr. , .

, assert , " nullptr" ? .

, , , , .

+1

, : , .

: uintptr_t . , , .

clang 3.9, gcc 7.0. 0x10 .

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

+1

, assert(this != nullptr), , . this, :

int* ptr = static_cast<int*>(this);

assert.

0

clang - this == 0 true, undefined. , ( assert()), , , .

It sounds like hanging on a rope that you are trying to cut above yourself, and again combine the ends ...

If you want your method not to be called accidentally with (this == 0), just do it virtualand it will force the kernel to be unloaded.

-2
source

Source: https://habr.com/ru/post/1661819/


All Articles