1

Will the program:

#include <stdio.h>

struct foo
{
   void blah()  {printf("blah\n");}
   int i;
};

void main(int, char**)
{
   ((foo*)NULL)->blah();
}

Ever crash, or do anything other than output blah, on any compiler you are aware of? Will any function crash, when called via a NULL pointer, if it doesn't access any members (including the vtable)?

There have been other questions on this topic, for instance Accessing class members on a NULL pointer and Is it legal/well-defined C++ to call a non-static method that doesn't access members through a null pointer?, and it is always pointed out that this results in undefined behavior. But is this undefined in the real world, or only in the standard's world? Does any extant compiler not behave as expected? Can you think of any plausible reason why any future compiler wouldn't behave as expected?

What if the function does modify members, but the NULL ptr is guarded against. For instance,

void foo::blah()
{
   foo* pThis = this ? this : new foo();
   pThis->i++;
}

Edit: For the record, the reason I wanted this was to make the interface to my linked list class as easy and concise as possible. I wanted to initialize the list to NULL have idiomatic usage look like:

pList = pList->Insert(elt);
pList = pList->Remove(elt);
...

Where all the operators return the new head element. Somehow I didn't realize that using a container class would make things even easier, with no downside.

Community
  • 1
  • 1
Tyson Jacobs
  • 352
  • 1
  • 9
  • 6
    Why do you care? It's Undefined Behavior. – Andy Prowl Jul 01 '13 at 21:20
  • 4
    ***`int`*** `main()`... –  Jul 01 '13 at 21:21
  • possible duplicate of [Undefined, unspecified and implementation-defined behavior](http://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior) – Mooing Duck Jul 01 '13 at 21:21
  • 3
    I don't see the reason of the downvotes or the close vote... although he's asking about questionable coding practice, this is a perfectly valid question, especially since OP already knows that it's UB. – Matteo Italia Jul 01 '13 at 21:25
  • 2
    Now, @OP: the important point here is that probably there's a much better way to do what you are trying to do, and what we are dealing with is the classic [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem); you should try to describe your "more general" problem that requires you to do this stuff, probably there's a better solution. – Matteo Italia Jul 01 '13 at 21:29
  • "What if the function does modify members...?" But the example you give does *not* modify members in case of a null pointer. – WaelJ Jul 01 '13 at 21:35
  • @WaelJ sure it does, just not the NULL pointer's members – Tyson Jacobs Jul 01 '13 at 21:51
  • Sure, in which case the method is modifying a completely different object and not its own (i.e. not the object it was *called on*). – WaelJ Jul 01 '13 at 21:56

3 Answers3

8

Can you think of any plausible reason why any future compiler wouldn't behave as expected?

A helpful compiler might add code to access the real object under the hood in debug builds in the hope of helping you catch this issue in your code early in the development cycle.

What if the function does modify members, but the NULL ptr is guarded against. For instance,

void foo::blah()
{
   foo* pThis = this ? this : new foo();
   pThis->i++;
}

Since it is undefined behavior to call that function with a null pointer, the compiler can assume that the test will always pass and optimize that function to:

void foo::blah()
{
   this->i++;
}

Note that this is correct, since if this is not null, it behaves as-if the original code was executed, and if this was null, it would be undefined behavior and the compiler does not need to provide any particular behavior at all.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • Then again, I would have to ask, in practice, are you aware of any compiler which would make this "optimization"? If the coder is explicitly testing the this ptr for NULL, presumably it is for a reason, why would a compiler writer ever go out of their way to circumvent this? – Tyson Jacobs Jul 01 '13 at 21:59
  • @TysonJacobs: Compilers do these kind of things all over the place. Consider `bool b; if (b) { std::cout << "yes"; } if (!b) { std::cout << "no"; }`. That piece of code with -O2 in gcc can print neither 'yes' nor 'no', as the compiler assumes that `b` must be either 0 or 1, but being uninitialized it can have other values. Once you get bitten by this you start trying to outsmart optimizers. Have I ever seen that particular optimization in that particular example: no, but I have never tried. – David Rodríguez - dribeas Jul 01 '13 at 22:02
  • 2
    @TysonJacobs: because the code the optimizer sees is not the code you wrote, but has already seen various passes of compilation, and thus that check the optimizer sees may or may not have been written by the programmer, or may be the result of the inlining of several functions or whatever - the optimizer's only concern is to make the code run faster respecting the rules of the standard. – Matteo Italia Jul 01 '13 at 22:03
  • 4
    @TysonJacobs: in particular, read this: http://blog.llvm.org/2011/05/what-every-c-programmer-should-know_14.html – Matteo Italia Jul 01 '13 at 22:07
  • 1
    @MatteoItalia Thx, I think I'm scared straight :) – Tyson Jacobs Jul 02 '13 at 02:20
  • 1
    @TysonJacobs: on the other hand, I tried a bit to fool g++ with similar tricks and then looking at the generated assembly; it seems that, at least in v 4.7, with -O2 and -O3, it is quite respectful of `this!=NULL` stuff (I didn't manage to convince the optimizer that the check is redundant), probably because there's code out there that relies on this. Still, you shouldn't rely on this kind of stuff, because optimizers are allowed to kill your `if` straight if they feel like that. As stated above, you should state the problem that makes you need this stuff, probably there's a better solution. – Matteo Italia Jul 02 '13 at 02:25
  • @MateoItalia Thx, I edited with what I was wanting, but you were right, there was no good reason for it. Still it seems like a compiler encoding the rule "this must not be NULL" would only be good for eliminating (this == null) checks , which would be self defeating, since any such usage would be there for a reason. But I could certainly see overzealous compiler writers adding it, and I won't rely on this working. – Tyson Jacobs Jul 02 '13 at 17:24
5

Undefined behavior means you can't rely on what will happen. However it's sometimes useful to know what's happening under the covers while you're debugging so that you're not surprised when the impossible happens.

Most compilers will code this as a simple function with a hidden this parameter, and if the this parameter is never referenced the code will work as expected.

Checking for this == NULL might not work, depending on how aggressively your compiler optimizes. Since a well formed program couldn't possibly have this==NULL, the compiler is free to pretend that it will never happen and optimize away the if statement entirely. I know though that Microsoft's C++ will not make this optimization because their GetSafeHWND function relies on it working as expected.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 1
    Unless the compiler assumes "this" is never NULL, and optimizes away the conditional access. – DanielKO Jul 01 '13 at 21:35
  • 1
    I would also add, that everything will work as expected _unless_ the function that is called is `virtual`, because calling a virtual function entails looking up the vtable of the object, which in turn means dereferencing it. However, even in that case the program may surprisingly not crash in the case that the compiler deduced the precise runtime type of the "object" and optimized the vtable lookup away. – cmaster - reinstate monica Jul 01 '13 at 21:36
  • @DanielKO, thanks for the comment - I didn't see that part of the question. I'll add something for that case. – Mark Ransom Jul 01 '13 at 21:49
  • @DanielKO interesting point. I wonder if any of the language lawyers can comment on whether the standard would permit this optimization. – Tyson Jacobs Jul 01 '13 at 21:50
  • 2
    @TysonJacobs: There's no need for language lawyers. `this` is never null, so any checks that it not be `null` always pass. Perfectly valid. – GManNickG Jul 01 '13 at 21:54
  • 1
    Just for the record, this isn't just hypothetical -- I've been bitten in the past when I tried to write a "NULL-safe" method that checks the this-pointer to see if it is NULL before executing anything -- it caused my program to crash in some circumstances. Moving the if-not-NULL test to outside of the method stopped the crashing. (Presumably because that avoided the compiler's thispointer-will-never-be-NULL assumption) – Jeremy Friesner Jul 01 '13 at 21:59
2

Trying to guard for this == NULL wouldn't give you any real desirable effect. Mainly dereferencing NULL pointer, AFAIK, is undefined. It works differently for different compilers. Let's say that it does work in one scenario (like this) it doesn't work for this scenarios or this (virtual functions). The second and third scenarios are understandable, since the instance doesn't have a vtable entry to check for which of the virtual functions to call. But I'm not sure the same can be said for the first.

The other thing that you need to consider is that any invalid pointer can also give the same type of error you'd want to guard against, like this. Notice that it successfully printed 'Foo' and then went into a runtime error trying to access a. This is because the memory location being pointed to by Test* t is invalid. The same behavior is seen here, when Test* t is NULL.

So, in general, avoid such behaviors and design in your code. It's not predictable and it would cause undesirable effect if someone comes after you and changes your code thinking it should behave as it did previously.

Vite Falcon
  • 6,575
  • 3
  • 30
  • 48