Bug 66438 - libstdc++ 5.1 broke binary compat with old code using std::error_category
Summary: libstdc++ 5.1 broke binary compat with old code using std::error_category
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 5.1.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-06-05 23:11 UTC by James Y Knight
Modified: 2015-06-06 15:31 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
Compare old and new categories (442 bytes, patch)
2015-06-06 13:54 UTC, Jonathan Wakely
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description James Y Knight 2015-06-05 23:11:03 UTC
If you compile this program with GCC 4.9, but you have libstdc++ version 5.1 installed on your system. (E.g., this is the case for me because I'm using Debian unstable).

#include <system_error>

int main() {
  std::error_code x = make_error_code(std::errc::no_such_file_or_directory);
  std::error_condition e = std::errc::no_such_file_or_directory;
  return x == e;
}


Then running it will return 0 instead of 1, like it should, (and did, with libstdc++ 4.9 installed).

So, the thing to note, is that both "x" and "e" here have a category() of _ZSt16generic_categoryv() as their category instance -- NOT _ZNSt3_V216generic_categoryEv(), because it was built against the old headers. (This seems to be as intended.)

Going through the calls, first we have this from libstdc++-v3/include/std/system_error:

  inline bool
  operator==(const error_code& __lhs, const error_condition& __rhs) noexcept
  {
    return (__lhs.category().equivalent(__lhs.value(), __rhs)
            || __rhs.category().equivalent(__lhs, __rhs.value()));
  }

which calls, from libstdc++-v3/src/c++11/compatibility-c++0x.cc:

  bool
  error_category::equivalent(int __i,
                             const error_condition& __cond) const noexcept
  { return default_error_condition(__i) == __cond; }

which calls, from the same file:

  error_condition
  error_category::default_error_condition(int __i) const noexcept
  {
    if (*this == system_category())
      return error_condition(__i, _V2::system_category());
    return error_condition(__i, _V2::generic_category());
  }

which returns a _V2::generic_category() object. Oops. Now we're in big trouble!

Then, back to error_category::equivalent, where it calls, from libstdc++-v3/include/std/system_error:

  inline bool
  operator==(const error_condition& __lhs,
             const error_condition& __rhs) noexcept
  {
    return (__lhs.category() == __rhs.category()
            && __lhs.value() == __rhs.value());
  }

Which fails, because __lhs.category() is the V2 generic_category, and __rhs.category() is the "V1" generic_category.
Comment 1 Andreas Schwab 2015-06-06 07:33:37 UTC
You always need to use the libstdc++ that is bundled with the compiler.
Comment 2 Andrew Pinski 2015-06-06 08:20:29 UTC
(In reply to Andreas Schwab from comment #1)
> You always need to use the libstdc++ that is bundled with the compiler.

Actually that is true but that does not make this bug a valid bug. What is mentioned is c++11 abi breaks between 4.9 and 5. So this bug is still invalid but a slightly different reason. From now (5), gcc will no longer break the abi.
Comment 3 Jonathan Wakely 2015-06-06 12:16:36 UTC
Indeed. Before gcc-5 it was never supported to combine C++11 objects compiled with different major versions.

The whole point of calling C++11 support experimental was that we reserved the right to make incompatible changes to the C++11 features, otherwise you'd be forever stuck with the partial C++0x support added around the gcc-4.4 timeframe.
Comment 4 Gianfranco 2015-06-06 12:23:53 UTC
The problem actually is Debian has gcc-4.9 as default compiler, and the libstdc++ provided in testing is from gcc-5.
Comment 5 James Y Knight 2015-06-06 12:36:11 UTC
Sorry, please try again.

Andreas Schwab: I did compile it with the libstdc++ that came with the compiler -- and then I upgraded the binary libstdc++.so to the newer one that came with gcc 5. And it broken. Thus the report of breaking binary compat. (It also happens with new compiles in Debian because of what Gianfranco says)

Andrew Pinski:

The *one and only purpose* of the file libstdc++-v3/src/c++11/compatibility-c++0x.cc is to provide binary compatibility for c++11 binaries compiled against older libstdc++ versions, and now running against a newer one.

If libstdc++.so.6, version 5.1, is not supposed to work properly with c++ binaries compiled by the 4.9 compiler, it should not be providing these compatibility symbols at all.

Since it does provide them, there is clearly intent to provide compatibility so, it ought to work. Or they should be deleted...
Comment 6 Jonathan Wakely 2015-06-06 13:13:35 UTC
(In reply to James Y Knight from comment #5)
> The *one and only purpose* of the file
> libstdc++-v3/src/c++11/compatibility-c++0x.cc is to provide binary
> compatibility for c++11 binaries compiled against older libstdc++ versions,
> and now running against a newer one.

It ensures they will still link.

> If libstdc++.so.6, version 5.1, is not supposed to work properly with c++
> binaries compiled by the 4.9 compiler, it should not be providing these
> compatibility symbols at all.

I would prefer that, but it's not our policy.

> Since it does provide them, there is clearly intent to provide compatibility

I didn't realise you were the maintainer and knew what's supposed to work.

Oh wait, you're not :-)
Comment 7 Jonathan Wakely 2015-06-06 13:17:20 UTC
If you can provide a patch that makes it work without any unwanted side effects then I'll certainly look at it, but mixing versions for C++11 code is unsupported, and so I'm not going to spend my time trying to make it work.
Comment 8 Jonathan Wakely 2015-06-06 13:54:11 UTC
Created attachment 35708 [details]
Compare old and new categories

This fixes this specific testcase, but not all cases (if you compare error_condition objects created in different translation unit compiled with different GCC versions then whether it works depends on which error_condition is on the left-hand side).
Comment 9 James Y Knight 2015-06-06 15:26:35 UTC
What good is having special code to allow linking compatibility, if the program then can't work anyways? Isn't that anti-useful?

> I didn't realise you were the maintainer and knew what's supposed to work.

No, of course...I'm only a user....

> If you can provide a patch

I'm not certain, but it seems like probably the old-ABI error_category::default_error_condition(int) ought to just return an error_condition also with the old ABI, instead of the new one?


CC'ing debian's gcc maintainer, because the stated lack of desire for compatibility between libstdc++ version 5, and g++ 4.9 seems like it's probably something he wasn't aware of when upgrading.
Comment 10 James Y Knight 2015-06-06 15:31:38 UTC
Oops, actually cc'ing doko this time (hopefully.)