Search code examples
c++pointersgdbmember

Why can I call a member function through a wild pointer


#include <iostream>
using namespace std;

class Car{
public:
    void start() {
        std::cout << "start" << std::endl;
    };
    virtual void stop() {
        std::cout << "stop" << std::endl;
    };
};

int main() {
    Car* p;// = new Car;
    p->start();
    p->stop();
    return 0;
}

This code gave me the output as below:

me@Ubuntu:~/tmp$ ./a.out
start
Segmentation fault (core dumped)

OK, I understand that p is a wild pointer, so this should be an undefined behavior. But I've tried to run this code on some other X86_64 machines and the outputs were exactly the same, which means that I can always get the start and Segmentation fault.

I'm wondering why I can always get that start.

I used gdb to debug this code:

(gdb) b main
Breakpoint 1 at 0x40084e: file main.cpp, line 16.
(gdb) r
Starting program: /home/zyh/tmp/a.out
Breakpoint 1, main () at main.cpp:16
16          p->start();
(gdb) display /5i $pc
1: x/5i $pc
=> 0x40084e <main()+8>: mov    -0x8(%rbp),%rax
   0x400852 <main()+12>:        mov    %rax,%rdi
   0x400855 <main()+15>:        callq  0x4008c8 <Car::start()>
   0x40085a <main()+20>:        mov    -0x8(%rbp),%rax
   0x40085e <main()+24>:        mov    (%rax),%rax

As you can see, we find that there is such a line: callq 0x4008c8 <Car::start()>.

So, again, I know that this should be an undefined behavior but I'm thinking if there is some reason which could explain why the member function start could be invoked by a wild pointer.


Solution

  • Short answer: "start()" is a non-virtual function.

    Explanation: For non-virtual functions, C++ determines what function it calls depending on the pointer type - not on the type of the actual refereced object.

    So it finds the function via the pointer type and then, as you don't use the referenced object in "start()" (you don't access any data members), your program doesn't produce a segmentation fault.

    If you call a virtual member function such as "stop()", however, C++ uses dynamic dispatch to determine the function to be used. Therefore it tries to get a pointer to the virtual method table from the object and this results in the segmentation fault.