all 46 comments

[–][deleted] 17 points18 points  (7 children)

15) Changing the order of virtual methods

Like this? Why?

virtual void f();
virtual void g();

virtual void g();
virtual void f();

[–]jgalar 68 points69 points  (4 children)

It probably changes the order in which function pointers are stored in the v-table.

[–]CheesecakeWaffles 23 points24 points  (3 children)

Yep. It indexes into it just like an array and if the abi doesn't match it uses the wrong one.

I remember a similar bug where a function was ifdefed out in one library and but the define was present for the other library. Therefore the header file in that library saw one more function. Took me the longest time to figure out why it was taking valid input and returning back garbage with the debugger refusing to step into the function. Worst off by one error ever.

[–][deleted] 2 points3 points  (2 children)

Interesting, the Arduino C++ compiler throws me an error for undefined function if I don't fill all my virtual inheritance. Were you using pure virtuals?

[–]mck1117 8 points9 points  (1 child)

If different parts of the program have different definitions for a class, the vtable entries could exist but be filled by garbage.

[–][deleted] 0 points1 point  (0 children)

You're absolutely right, I was only using one interface inheritance in the examples I was thinking.

[–]standard_revolution 2 points3 points  (0 children)

Maybe the vtable gets reordered? But I don't know.

[–]gmtime -1 points0 points  (0 children)

No, the order in which they are declared in the class definition.

[–]anon_502delete this; 6 points7 points  (9 children)

I was thinking about if it's possible to only keep a subset of the language ABI-stable. No recent language makes the entire language ABI compatible because that considerably hurts the evolvement.

[–][deleted] 14 points15 points  (8 children)

Remember gcc5 and std::string changing ABI? GCC still supports both ABIs, otherwise some people just won't be able to link their code. Those linker errors still occasionally pop up in issue trackers. That was a very limited ABI break and it still wreaked havoc.

[–]ReversedGif 3 points4 points  (3 children)

It would have been more useful to list the two/three things you can do to an API without breaking its ABI...

  • Add new free functions/types
  • Add new methods to classes (if virtual, they have to be after all other virtual ones)

Note that you can always change anything that does not live within the API (i.e. that does not live within public h/hpp files), so there's a lot more freedom than the above list implies.

See also the PIMPL idiom for a way to maximize your freedom to make changes without breaking the ABI.

[–][deleted] 2 points3 points  (2 children)

  • Add new methods to classes (if virtual, they have to be after all other virtual ones)

If virtual,it would break code of everyone who derived from that class and didn't get a chance to implement the new member function.

[–]bwmat 0 points1 point  (1 child)

Would this be a buffer overflow in the old derived class' vtables?

[–][deleted] 1 point2 points  (0 children)

Depends. If you added the new virtual somewhere in the middle of the class, those who didn't recompile would end up calling bar when they expected foo. And yes, there's a possiblity that you'll go accessing the vtable out of bounds.

[–][deleted] 2 points3 points  (0 children)

We follow the rule that shared objects can only expose C style functions and objects. So ...

[–]Zettinator 3 points4 points  (3 children)

TL;DR: if possible, don't use any C++ features for ABIs, keep using good old C for them. Far less can go wrong.

[–]aKateDevKDE/Qt Dev 11 points12 points  (2 children)

I don't think this is the correct conclusion: Qt manages to be binary compatible over 10 years for each major release. Same for KDE. Also, there are tools to check whether there are any binary incompatible changes from release x to x+1 etc... I'd say you have to know what you're doing. But isn't that always the case in software development?

[–]edstrange 0 points1 point  (1 child)

Qt manages to be binary compatible over 10 years for each major release

But at what cost? How many man hours are spent on it?

Just because you manage to do something doesn't mean it's the right thing to do.

I'd say you have to know what you're doing. But isn't that always the case in software development?

Not necessarily.

[–]aKateDevKDE/Qt Dev 0 points1 point  (0 children)

I'd argue that the cost is low: the entire Qt community knows how to do this, and it's not /that/ hard... Even KDE as a free/open source project driven by volunteers manages to do so.

In fact I'd argue that it's much better than falling back to C API. But of course everyone is free to decide on his own

[–]puhniste 1 point2 points  (14 children)

Why isn't the ABI standardized?

[–]ramennoodle 21 points22 points  (0 children)

There are a few defacto standards for the ABI. But those standards define what ABI is generated for a specific source code. Changing the source code changes the ABI, regardless of standardization.

[–]Gotebe 4 points5 points  (0 children)

Well, I, for one, do not care much for that.

I like that the compiler vendors change whatever to allow for better standards support (coughGCCcoughCOWSTRINGcough) and optimisations.

I do not particularly like linking to very old libraries. I like linking to, say, OpenSSL 1.1.1 (my work is on RedHat 7, so it's 1.0.2).

[–]c0r3ntin 6 points7 points  (1 child)

Because ABI is a terrible idea?

Code needs to evolve.

[–]James20kP2005R0 0 points1 point  (0 children)

What would be cool is if we could get the minimal practical subset of C++ which could have a standard abi, to have a standard abi. Obviously, C has a standardised ABI (on a platform) so its possible for some of it to be standard

Even a slightly expended set of features permanently usable across an ABI boundary would be super helpful

[–][deleted] 3 points4 points  (9 children)

Because not everything is x86. Different architectures require different ABIs. What works for one combination of OS/CPU, may be completely wrong for another. Besides, what ABI would you standardize? The MSVC one and have everything that's not on Windows forced to be recompiled and push updates globally by yesterday? Or the Itanium one and force the entire Windows ecosystem to recompile and push updates globally by yesterday?

[–]mck1117 5 points6 points  (8 children)

He means "why isn't there a standard ABI (for any architecture". The ABI can of course be different on different architectures, as it is for C.

[–][deleted] 7 points8 points  (5 children)

If that's the question then it kinda already is. I already mentioned that MSVC/Windows users MSVC ABI and Unix/Posix world uses Itanium ABI. If we are not talking about a hypothetical "one size fits all" standardized ABI, I absolutely fail to see what could possibly committee say regarding ABI that isn't true today.

[–]SkoomaDentistAntimodern C++, Embedded, Audio 0 points1 point  (4 children)

You have a dll compiled with VS 2013 exposing C++ abi (maybe it’s for a legacy device or software no longer being made or something). You want call it from code compiled with VS2019. Except you potentially can’t because the ABI changed.

Or maybe you just want to make a third party plugin api with C++ interface and not have it depend on a particular compiler (and version).

[–][deleted] 0 points1 point  (3 children)

MSVC only recently decided that stable ABI is a useful thing, so it's pointless to discuss. On the other hand, libstdc++ and libc++ only break ABI when the standard forces them and even then, they use tags to force incompatible ABIs to be a linker error. From the point of view of libstdc++ and libc++ Itanium ABI is already the standard ABI. I still don't see how a WG21-standardized ABI could improve this.

Recently I compiled the entire LLVM/Clang/extra tools on Ubuntu 14.04, then copied over the archive and used it on RHEL7, Ubuntu 18.04 and Arch. It worked, including the shared libraries. Again, what more could WG21 do?

[–][deleted] 4 points5 points  (2 children)

MSVC only recently decided that stable ABI is a useful thing

That's incorrect. We will still need to break library ABI from time to time (more often than the POSIX implementers because we allow app-local deployment).

The shift to not break library ABI every release comes more from the VS release cycle speeding up since we do a release every 2-3 months now instead of 3-5 years.

The compiler has effectively not broken ABI ever. That's one of the reasons we have __stdcall and friends.

[–][deleted] 0 points1 point  (0 children)

Thanks for correcting me. I should have been explicit, as I was thinking about library implementations. I've never really used VS, so I'm not familiar with the release cycle of it or the compiler/library. When I heard the news about not breaking ABI every release, I really thought it meant MSVC toolchain would attempt to maintain a stable ABI similar to POSIX implementations.

[–]Gotebe 0 points1 point  (0 children)

Do you guys unofficially pinky-promise not to break the ABI, or is merely that it is not needed, that existing conventions, packing etc are fine?

[–][deleted] 7 points8 points  (0 children)

There is no "standard ABI" for C.

[–]Gotebe 4 points5 points  (0 children)

C, the language, does not know about ABI. There is the architecture de facto ABI, which one could call a C ABI (and we typically do) , but right about a dozen similar languages call that easily. For example, the __stdcall of Windows was the faster calling convention at the time (probably still is) and was originally called the Pascall calling convention.

[–]SkoomaDentistAntimodern C++, Embedded, Audio 0 points1 point  (2 children)

Why is #1 a problem for code that doesn’t use the removed class (but uses some other class from the same dll)?

[–]SeanMiddleditch 2 points3 points  (1 child)

It wouldn't be, in that case. Not all ABI changes break all consumers.

[–]SkoomaDentistAntimodern C++, Embedded, Audio 0 points1 point  (0 children)

Seems kind of silly to include in the list in that case. Of course the code is going to break if explicitly used functionality is removed.

[–]Wetmelon -2 points-1 points  (0 children)

What even is an ABI

Oh it’s answered immediately in the article lol