1

Is there a way in Visual Studio 2010 to automatically catch a bug of calling a member function on a NULL object? Some flag perhaps, that puts an appropriate assertion at the begging of every member function?

The default behavior is to silently accept it and only crash when a field is accessed. In some cases however if is much later then the original error.


Edit: I know that calling member function on a NULL pointer invokes undefined behavior. It is a bug in my code that I want to eradicate. I hope that Visual Studio has some non-standard tool that could assist me.

CygnusX1
  • 20,968
  • 5
  • 65
  • 109
  • Are you trying to solve a REAL problem, or a hypothetical one? If it's a real problem I think some form of "macro" as described below is definitely a suitable solution - just scatter it all over the place - particularly where you're currently seeing the problem. You can always remove it when you have removed the problem. If it's a hypothetical problem, then I'm not sure there is a good hypothetical answer... – Mats Petersson Mar 10 '13 at 14:48
  • 1
    I am solving a real problem. Since the code is in constant development I expect to catch similar bugs in the future. Keeping all those asserts everywhere would really clutter my code. – CygnusX1 Mar 10 '13 at 17:24
  • I know you are asking for MSVC, but if anyone is asking for this who can use clang/gcc then there is the `-fsanitize=null` option. – rdb May 28 '18 at 22:41

5 Answers5

2

No, but if you fully embrace RAII and only use C++11 smart pointers (never explicitly calling delete) you'll be hard pressed to ever run into such a bug.

David
  • 27,652
  • 18
  • 89
  • 138
  • You can still catch the bug with smart pointers, but they have the necessary assertion built-in and will reveal the problem immediately. – CygnusX1 Mar 10 '13 at 14:10
2

No, and it would be useless.

Calling a member function on a NULL pointer invokes undefined behavior. As the name imply, you cannot be sure of the behavior at this point.

Specifically:

void MyObject::foo() {
    if (this) { throw std::logic_exception("this is NULL"); }

    std::cout << "Hello, world!\n";
}

Can reasonably changed by any conforming compiler to:

void MyObject::foo() {
    std::cout << "Hello, world!\n";
}

since, after all, the Standard guarantees that this is NEVER null in the first place!

What can be done, however, is not relying on "bare" pointers:

template <typename T>
class Pointer {
public:
    Pointer(): _ptr(nullptr) {}
    Pointer(T* t): _ptr(t) {}

    T* operator->() const { assert(_ptr); return _ptr; }
    T& operator*() const { assert(_ptr); return *_ptr; }

private:
    T* _ptr;
};

And then using it like you would a pointer:

int main() {
    Pointer<MyObject> value = container.find("Element");
    value->foo();
}

And if ever it is null, then the assert fires before the call to foo is attempted.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • That's pretty much what I suggested in the comment of my answer. Felt like it is somewhat noobish until a more experienced person like you shared it. It could become more elegant with some boilerplate code generation like compilers and meta-compilers do behind the scene. – dtech Mar 10 '13 at 14:53
  • @ddriver: you are right that with some code instrumentation automatically added by the compiler it gets much more elegant. You might want to check Clang's AddressSanitizer for this, it will catch the invalid pointer access and shuts down the program with a clear and understandable error message pointing you at the line of the null pointer (in the source). – Matthieu M. Mar 10 '13 at 15:02
  • But still, in debug mode the runtime does plenty of extra work, I doubt it would hurt performance that much if every pointer is checked before usage. Maybe there should be such an option... – dtech Mar 10 '13 at 15:08
  • @ddriver: it's not just about null pointers though (those are easy), it's also about dangling pointers (that point to already destructed objects)! – Matthieu M. Mar 10 '13 at 15:37
  • Added an edit in my question. I know calling NULL is against standard and I do not want this in production code. I just hope for some additional aid from the compiler finding these situations. – CygnusX1 Mar 10 '13 at 17:29
  • If nothing better comes I will probably try to "smartify" the pointers as you suggest it. It will require a lot of recoding though... – CygnusX1 Mar 10 '13 at 17:34
  • 1
    @CygnusX1: another solution is to run instrumented code, Valgrind, AddressSanitizer, ThreadSanitizer, MemorySanitizer; it only detects bugs in code that runs though, so you need a good coverage. – Matthieu M. Mar 10 '13 at 18:07
1

You can check if this is NULL, but if you are running in MSVS, you should consider the DebugBreak - option, to force a debug break to investigate the Stack. This could lead to the bug most effective. I removed the checking from Release compiles, because running that code without a debugger will make your application hang itself, because no debugger can tell it to continue. To avoid that issue, you can think about isDebuggerPresent().

#ifdef DEBUG
#define CHECK() if (this==NULL) DebugBreak();
#else
#define CHECK() 
#endif

IsDebuggerPresent:

DebugBreak on MSDN:

Community
  • 1
  • 1
EGOrecords
  • 1,959
  • 2
  • 19
  • 33
0

I'm not aware of any special option to check for this, but you could easily write a macro:

 #define CHECK_THIS()  assert(this)

or

 #define CHECK_THIS() do { if (this == NULL) { std::cerr << "'this' is NULL at " \
                             << __FILE__ << ":" << __LINE__ << " in " << __func__; \
                             exit(2); } while(0)

(It's using "do - while" so that it can be placed anywhere without interfering with other if-statements, etc).

Then just add CHECK_THIS() in any relevant functions.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
0

Automatic - I don't know, but you can always use an assert:

assert(this);

As for this and considering it is a keyword that refers to the "callee" class instance - how can it be NULL? Call through a NULL pointer?

dtech
  • 47,916
  • 17
  • 112
  • 190
  • Somewhere one can have `ptr->doSomething()` with `ptr == NULL`. That's how you can catch the bug. – CygnusX1 Mar 10 '13 at 14:08
  • @CygnusX1 well it that case assert is your friend, just call it before calling anything else and you are done. It is used quite a lot in framework code. – dtech Mar 10 '13 at 14:10
  • Yes, asserts can help, but they can also clutter the code a lot. It is also easy to catch a bug of not putting a necessary assertion somewhere. As a result one trades one bug for another. – CygnusX1 Mar 10 '13 at 14:12
  • @CygnusX1 - what about implementing your own Pointer class that implicitly casts to a regular pointer, overload the `->` operator to do an assert and then call the function from the private pointer in the class? Effectively a safe wrapper around the pointer. As "smart" pointers do it. – dtech Mar 10 '13 at 14:17
  • If nothing better comes, I may do it this way, but it will be a lot of code to rewrite. – CygnusX1 Mar 10 '13 at 17:32
  • @CygnusX1 - why rewrite, I bet you can regex the changes :) – dtech Mar 10 '13 at 17:33