39

Please do not answer the question "how do I solve this error message?"

In the error message provided by gold:

/usr/bin/ld.gold: the vtable symbol may be undefined
because the class is missing its key function

What is a key function? I find reference to it in the GCC manual page for Function Attributes under the section dllimport. The relevant text reads:

On the SH Symbian OS target the dllimport attribute also has another affect (sic)—it can cause the vtable and run-time type information for a class to be exported. This happens when the class has a dllimport'ed constructor or a non-inline, non-pure virtual function and, for either of those two conditions, the class also has an inline constructor or destructor and has a key function that is defined in the current translation unit.

From this I take away that there is some function distinct from constructors or destructors, required under some conditions, when using the dllimport attribute, on Symbian OS. Interesting, but I'm compiling for Linux on Linux, and grep -r dllimport reveals nothing. So this paragraph does not apply.

(FWIW the problem derives (in this instance) from an undefined destructor but both the documentation and the output of the linker go to great pains to distinguish a "key function" from a destructor. For other kinds of missing symbols, the linker spells the name of the missing symbol.)

So, what is a key function really?

Barmar
  • 741,623
  • 53
  • 500
  • 612
Cuadue
  • 3,769
  • 3
  • 24
  • 38
  • virtual destructor? – Zereges Aug 23 '17 at 22:19
  • 11
    Why no [mcve]? I get you don't want a problem solved, but helping others get the same error message (starting point) seems polite. – Yakk - Adam Nevraumont Aug 23 '17 at 22:37
  • 7
    @Yakk How does asking what something *is* require an MCVE? – Rob Aug 24 '17 at 04:10
  • 5
    @rob "I got this error doing something" is *improved* by including how to get the error, because people helpimg can get to your starting poimt (getting the error) faster. Getting the error then gets you the context in which the error happens, instead of the OP's interpretation of the context, which could lead the answerer to a better spot to seach for a definition. I said nothing about "requires". And the mcce would have revealed it was an undefined *virtual* destructor, which the OP failed to mention. – Yakk - Adam Nevraumont Aug 24 '17 at 05:50
  • 4
    @Yakk The question is not about the error at all. It's asking 'what is a key function?' The error provoked the question, but it's completely unrelated to the question and answer. – Rob Aug 24 '17 at 06:57
  • 2
    Then why not delete this part of the questions as the "why I ask" is not really relevant on this site and only causes confusion to others (see the this comment section as example)? – Mailerdaimon Aug 24 '17 at 07:17
  • 2
    @rob becauae context matters. "Key function" without context is meaningless; the more context, the more the meaning is clear, *and* the easier investigation can be. It is asking "when I get this error, it talks about 'key function'. What does that mean **in that error**". If you answer what a key function is in a crypto algorithm that is obviously wrong. The fact the error involved vtables, and an undefined virtual method, would siggest google search terms that could lead to an answer. – Yakk - Adam Nevraumont Aug 24 '17 at 07:56

2 Answers2

32

key function is defined as the first non-inline, virtual function declared in the class. The official gcc wiki about it is here.

navylover
  • 12,383
  • 5
  • 28
  • 41
  • 1
    IOW, OP probably forgot to define the first non-inline virtual function, or to link the relevant object file. So, instead of an "undefined reference" error to it, you get this bizarre message - not defining the key function causes the vtable not to be emitted, which is probably spotted earlier than missing references to the key function itself. – Matteo Italia Aug 23 '17 at 22:34
  • 2
    What happens if all virtual functions are defined inline? – MikeMB Aug 24 '17 at 05:59
  • 3
    @MikeMB: from the link above: "Whenever possible the vtable will only be generated and output in a single object file rather than generating the vtable in every object file which refers to the class (which might be hundreds of objects that include a header but don't actually use the class.)". I suspect that your case is one that falls out of the "whenever possible" above, so a vtable will be generated in every TU with the same attributes as `inline` function, and the linker will know it can pick one at random. I'll do some tests to see if this is the case. – Matteo Italia Aug 24 '17 at 08:04
  • @MatteoItalia, Did you find some time to do some tests around this scenario? I got stuck to this problem recently and investigating for RCA. – Bhupesh Pant Sep 23 '18 at 17:37
  • Uh sorry, unfortunately that was a good deed that I forgot. – Matteo Italia Sep 24 '18 at 00:22
21

(moving/expanding from the comment)

As @navylover explained, the key function is the first non-inline, virtual function defined in the class; it's important because it is used by the compiler as a conventional marker to decide in what TU the vtable must be emitted (as it must be emitted just once) - whichever TU contains the definition of the key function, the corresponding object module will contain the vtable as well.

It follows that, if no TU defines the key function (e.g. because you forgot to define it), the vtable will never get emitted, hence the error.

gold there is trying to hint you in the right direction: if the vtable is missing, probably is because the key function is missing as well (again, either because you didn't define or forgot to link its module), although it may not be listed explicitly as an undefined reference (which could put you on the right track) because in the rest of the code nobody invokes it directly1, as in this example:

struct Test {
    virtual void foo();
    virtual int bar() {
        return 0;
    }
};

int main() {
    Test t;
    t.bar();
    return 0;
}

 

[matteo@teolapkubuntu /tmp]$ g++ -fuse-ld=gold keyf.cpp 
/tmp/ccduMsT3.o:keyf.cpp:function main: error: undefined reference to 'vtable for Test'
/usr/bin/ld.gold: the vtable symbol may be undefined because the class is missing its key function

Compare this with regular GNU ld, which just says

[matteo@teolapkubuntu /tmp]$ g++ keyf.cpp 
/tmp/ccUr3Xyi.o: In function `main':
keyf.cpp:(.text+0x1a): undefined reference to `vtable for Test'
collect2: error: ld returned 1 exit status

Ok, so what? It's not like I have to explicitly define vtables, so it's definitely not obvious where should I start to look to go fixing this kind of error.


  1. Such a function may however be invoked indirectly through a pointer to base class, and the linker would still show only the undefined reference to the vtable and not to the function, as the only reference to the function in this case would be in the vtable, which is missing.
Matteo Italia
  • 123,740
  • 17
  • 206
  • 299