Hacker News new | ask | show | jobs
by wbkang 3735 days ago
What happens if sum is a virtual function? Or does it not matter? I am not too familiar with c++ casting magic.
2 comments

Most likely you'll get a segfault when it tries to read from page 0 to get to the class' vtable (which is where the references to the virtual functions live).
Yes, you'll get a segmentation fault, consider this code, compiled with debug information:

  #include <iostream>

  using namespace std;

  class myclass
  {
      public:
          virtual int sum(int a, int b)
          {
              return a + b;
          }
  };

  int main()
  {
      myclass test;
      cout << test.sum(1, 2) << endl;
      cout << ((myclass*)0)->sum(10, 11) << endl;
      return 0;
  }
Debugging:

  (gdb) b main
  Breakpoint 1 at 0x4008ae: file test.cpp, line 16.
  (gdb) run
  Starting program: /tmp/test 

  Breakpoint 1, main () at test.cpp:16
  16	      myclass test;
  (gdb) ni
  17	      cout << test.sum(1, 2) << endl;
  (gdb) info vtbl test
  vtable for 'myclass' @ 0x400a30 (subobject @   0x7fffffffe410):
  [0]: 0x400974 <myclass::sum(int, int)>
Notice that the function address to be called is not know at compile time, the compiler wrote a lookup table, named vtable, to know which function it will call based on the class instance.

  (gdb) disassemble main
  [snip]
   0x00000000004008ae <+8>: movq  $0x400a30,-0x10(%rbp) ; see the vtable address here
   => 0x00000000004008b6 <+16>:	lea  -0x10(%rbp),%rax ; ohh, the vtable address is the 'myclass test' instance*
   0x00000000004008ba <+20>:	mov    $0x2,%edx
   0x00000000004008bf <+25>:	mov    $0x1,%esi
   0x00000000004008c4 <+30>:	mov    %rax,%rdi ; pass this to RDI
   0x00000000004008c7 <+33>:	callq  0x400974 <myclass::sum(int, int)>
* it means that the first (and only one, in this case) field of my myclass is that vtable.

  (gdb) print test
  $1 = {_vptr.myclass = 0x400a30 <vtable for myclass+16>}
  (gdb) info register rax
  rax   0x7fffffffe410	140737488348176
  (gdb) x/x 0x7fffffffe410
  0x7fffffffe410:  0x00400a30
  (gdb) x/x 0x00400a30
  0x400a30 <_ZTV7myclass+16>:	0x00400974
Then, the compiler knows that it must call '[0]: 0x400974 <myclass::sum(int, int)>' function.

Compare with:

   ((myclass*)0)->sum(10, 11)
   0x00000000004008e5 <+63>:	mov    $0x0,%eax    ; vtable address is 0 :(
   0x00000000004008ea <+68>:	mov    (%rax),%rax  ; the address to RAX is 0, and we cannot access that segment of memory - BOOOM
   0x00000000004008ed <+71>:	mov    (%rax),%rax
   0x00000000004008f0 <+74>:	mov    $0xb,%edx
   0x00000000004008f5 <+79>:	mov    $0xa,%esi
   0x00000000004008fa <+84>:	mov    $0x0,%edi
   0x00000000004008ff <+89>:	callq  *%rax