13

I've read in many places (for example here) about people getting a "pure virtual method called" error and program crash at runtime. This answer says that

Most compilers assign such vtable entries to a stub which emits an error before aborting the program.

and this one even says that Itanium ABI specifies what that stub is.

The problem is: all my attempts to see this behaviour in action are caught by the compiler (GCC 6.4.1) at compile time as undefined references. For example, when calling a pure virtual function from a constructor of the abstract class, I get a warning

pure virtual ‘virtual int X::f()’ called from constructor

but at the same time simply no code at all is generated for X::f() so this is followed by

undefined reference to 'X::f()'

from the linker and the compilation fails. This seems a pretty foolproof way of preventing the error at runtime. In which situation would my compiler actually need to generate the aforementioned stub? Or has it gotten smart enough to detect all the possible pathological situations early enough?

The Vee
  • 11,420
  • 5
  • 27
  • 60
  • 3
    It's never required to generate the stub. Calling a pure virtual method is undefined behavior. Some compilers take advantage of the permissive nature of undefined behavior to provide you with one as a courtesy. – François Andrieux Sep 15 '17 at 15:49

1 Answers1

10

Usually it will be called indirectly from within a constructor. Here's a minimal example:

#include <iostream>

struct X {
    virtual void foo() = 0;
    void bar() { foo(); }
    X() { bar(); std::cout << "X"; }
};

struct Y : X {
    void foo() override {}
};


int main() {
    Y y;
    return 0;
}

The compiler is obligated to bind the call statically if it appears inside the c'tor directly (and hence can produce a useful error message for a pure virtual function). But when the call is indirect, from another member, it must be dynamically dispatched.

Naturally, the Y part is not yet constructed during the construction of X, so the whole thing collapses on itself in a blaze of undefined behavior.

Live example - With the stub at work

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • I'm surprised the compiler doesn't complain about calling a virtual method from the constructor. – Steve Sep 15 '17 at 15:50
  • 3
    @Steve - But we're not calling a virtual function from the c'tor. Not directly. And it's intractable to check if we call one indirectly. – StoryTeller - Unslander Monica Sep 15 '17 at 15:52
  • Ah. That makes a lot of sense. Thanks for clarifying. – Steve Sep 15 '17 at 15:54
  • Most interesting! Actually with `-O3` gcc realizes that `foo` is called from the ctor, saves all the hassle and replaces the whole of `main` by a call to `__cxa_pure_virtual` instead of stopping compilation even so, that's quite funny: https://godbolt.org/g/ieR9oz – The Vee Sep 15 '17 at 15:55
  • @TheVee - Yeah, I suppose the example code is simple enough for an aggressive optimizer to figure it out. But such code exists in the wild, with far more elaborate setups and deeper nesting. – StoryTeller - Unslander Monica Sep 15 '17 at 15:56
  • 1
    Yes, I'm well aware of that being intractable in general, the reason is completely clear with pointing this out. It didn't occur to me to think of indirect function calls in my own attempts. – The Vee Sep 15 '17 at 15:59