https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66438

            Bug ID: 66438
           Summary: libstdc++ 5.1 broke binary compat with old code using
                    std::error_category
           Product: gcc
           Version: 5.1.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: foom at fuhm dot net
  Target Milestone: ---

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.

Reply via email to