3

Why doesn't the following C++ program have a link conflict with the system-provided __cxa_throw ?

#include <cstring>

void __cxa_throw(void *, void *, void (*)(void *)) {
    std::puts("bad luck");
}

int main() {
    throw 13;
}

Is there something magical about that symbol? For a normal function this would be an ODR violation wouldn't it?

Andrew Tomazos
  • 66,139
  • 40
  • 186
  • 319
  • The runtime-provided function is probably `extern "C"`, while yours gets a mangled name. In any case, this program exhibits undefined behavior by way of using a reserved name. – Igor Tandetnik Jan 17 '21 at 22:53
  • 2
    ODR: _"...The compiler is __not__ required to diagnose this violation, but the behavior of the program that violates it is undefined...."_ https://en.cppreference.com/w/cpp/language/definition – Richard Critten Jan 17 '21 at 22:53
  • @IgorTandetnik: Tried it with `extern "C"`, still works, no link error. – Andrew Tomazos Jan 17 '21 at 22:56
  • @RichardCritten: Sure, but for other symbols it does cause a link error - so my question is why not this one? – Andrew Tomazos Jan 17 '21 at 22:57
  • When linking a bunch of .obj files and static libraries together, symbols defined in .obj files take priority. That's how you can write your own `operator new`, say; but if you don't, one provided by the runtime library is used. Your program still exhibits undefined behavior; "seems to work" is one possible manifestation of undefined behavior. – Igor Tandetnik Jan 17 '21 at 22:58
  • 2
    you are not allowed to define ANY symbols which starts with double underscore. Those symbols are reserved for compiler and standard library. https://stackoverflow.com/a/224420/1387438 – Marek R Jan 17 '21 at 23:02
  • _"but for other symbols it does cause a link error"_ No, not necessarily. Try doing that with a shared library. – Asteroids With Wings Jan 17 '21 at 23:07
  • *For a normal function this would be an ODR violation wouldn't it?* -- yes, but what makes you think this isn't an ODR violation? An ODR violation does not require a compiler (or a linker) diagnostic. – Sam Varshavchik Jan 17 '21 at 23:23

1 Answers1

3

As @Igor pointed out, you need to add extern "C" to prevent name mangling.

But the cause why it works is because the symbol is most likely defined as weak. This means that if you redefine it, the linker will use your version instead of the standard's library.

Gcc's source code confirms they define it as weak. I am unsure about the reason, perhaps some internal compatiblity with shared libraries and such... Actually there is a comment right above the definition I somehow missed:

77 /* Everything from libstdc++ is weak, to avoid requiring that library
   to be linked into plain C applications using libitm.so.  */

So that's the reason.

It goes without saying that it is really terrible idea to do this, more even without proper documentation on what other functions expect __cxa_throw to do.

Quimby
  • 17,735
  • 4
  • 35
  • 55