So the latest bug I ran into at work involved a missing vtable in Clang. No, I’m not able to produce a reduced case, so evasion is the only route.

In the meantime, let’s document how to look at vtables.

So, the layout of vtables in memory is simple: the first 8 bytes of every class with virtual methods is a pointer to a table of function pointers. There’s exactly one vtable for every class, and if the information for generating this is missing, you get the familiar linker error.

class EliminateConditionals
  class Predicate
    virtual bool shouldEliminate() const { return true; }
    virtual ~Predicate() {}
    static void queryPredicate() {}

An object of the EliminateConditionals class will be 1 byte long (any two 0 byte objects will be equal to each other, hence 1 byte). An object of the class Predicate will be 8 bytes long (the vtable entry), and the vtable will contain one 8 byte pointer each to shouldEliminate() and ~Predicate(). The reason they ask you to make destructors virtual is simple: if you’re using a derived object cast as a base object, and then destructing it doesn’t call the destructors on the members unique to the derived class.

(lldb) im loo -r -v -s "vtable for EliminateConditionals
2 symbols match the regular expression 'vtable for EliminateConditionals' \
in /home/artagnon/tmp/class-size:
        Address: class-size[0x0000000100001160] (class-size.__DATA.__data + 16)
        Summary: vtable for EliminateConditionals::Predicate
         Module: file = "/home/artagnon/tmp/class-size", arch = "x86_64"
         Symbol: id = {0x00000048}, range =
         [0x0000000100001160-0x0000000100001188), \

         name="vtable for EliminateConditionals::Predicate", \
        Address: class-size[0x0000000100001110] (class-size.__DATA.__const + 0)
        Summary: class-size`vtable for EliminateConditionals
         Module: file = "/home/artagnon/tmp/class-size", arch = "x86_64"
         Symbol: id = {0x0000005e}, range =
         [0x0000000100001110-0x0000000100001130), \
          We can `mem r` this

         name="vtable for EliminateConditionals", \

That’s an image lookup, and it works as long as everything is loaded; nothing needs to run.