What exactly are the libcxx ABI guarantees?

Sorry if this is a complete n00b question, but I’m trying to understand the limits of the ABI “promise” a specific ABI version of libcxx provides.

Taking a concrete example, if I have two code bases, both of which use some version of libcxx with the same ABI, both using the Itanium C++ ABI, under what conditions (if any) should I expect undefined behavior when one library shares STL objects with the other?

Obviously if they share the exact same compiler+linker flags and identical version of libcxx there shouldn’t be issues. But where do things fall over? Different C++ versions (C++11 for one and C++20 for another)? Older / newer releases of libcxx with the same ABI version number? Different decisions about RTTI/exceptions (I don’t necessarily mean if an exception is thrown). Different linker flags?

Thanks!

This isn’t at all a noob question. This is in fact a very hard question, and we are working on improving the answer. In general, there shouldn’t be issues switching between C++ versions. Though there are a few cases where it can be problematic. e.g. std::accumulate is in C++20 defined to move the accumulation object instead of copying it. This results in at least an observable behaviour change, but that should at least not bring down your program, since the linker will discard one version, and the other should still do about the same thing. Compiling against different libc++ versions is also fine. RTTI and exceptions are much more problematic, since they have behaviour changes that aren’t just “it’s technically not conforming”. Mixing these configurations could potentially result in memory leaks or worse. Though many people still mix them, so your mileage may vary. If there aren’t any exceptions thrown it’s probably fine™. I’m not sure what linker flags you have in mind, but I don’t think that should matter much.

2 Likes

Thanks for the quick reply, it’s great to know what’s covered and what’s not.

One small suggestion, it might be useful to be slightly more explicit (e.g. here: Libc++ ABI stability — libc++ documentation) listing some of these examples as being affirmatively supported, just to really nail home the scope of the promises being made, and perhaps to point to areas (like you highlighted with std::accumulate) where there will be some observable differences in behavior.

Otherwise, pretty pleased with the commitment to ABI compatibility!

IMO it’s quite hard for libc++ to make hard promises. When the C++ Committee accepts ABI breaking papers we have little choice. (Several libc++ developers are Committee members so we are aware of what happens there.) ABI breaking papers are rare, but not unheard of. For example, in C++11 libstdc++ had to make ABI breaking changes in std::string, something people still run into. Other ABI breaking changes accepted by the Committee have been much less disruptive.

Still we try hard to remain ABI compatible.

Regarding RTTI/exceptions: We do support users turning off RTTI and exceptions when they compile against a library where exceptions and RTTI are enabled. Users turning exceptions on against a library where exceptions and RTTI have been disabled doesn’t work, obviously, cause you’re lacking the appropriate runtime support for exceptions.

If you mix -fexceptions and -fno-exceptions in your own code, it should also work but be careful about the implications of actually throwing stuff from the -fexceptions side, since any such exception won’t be caught as it propagates through the -fno-exceptions code.

1 Like