Bug 66145 - [5/6/7 Regression] std::ios_base::failure objects thrown from libstdc++.so use old ABI
Summary: [5/6/7 Regression] std::ios_base::failure objects thrown from libstdc++.so us...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 5.0
: P2 normal
Target Milestone: 7.0
Assignee: Jonathan Wakely
URL:
Keywords: ABI, wrong-code
: 67620 69877 (view as bug list)
Depends on: 85222
Blocks:
  Show dependency treegraph
 
Reported: 2015-05-14 16:59 UTC by Jonathan Wakely
Modified: 2018-08-08 15:40 UTC (History)
21 users (show)

See Also:
Host:
Target:
Build:
Known to work: 4.8.4, 4.9.2
Known to fail:
Last reconfirmed: 2015-05-20 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Wakely 2015-05-14 16:59:24 UTC
Using the new cxx11 ABI in GCC5 (and trunk) the exception here isn't caught:

#define _GLIBCXX_USE_CXX11_ABI 1
#include <fstream>
#include <limits>

int main()
{
  std::fstream f;
  f.exceptions(std::ios::badbit);
  try {
    f.pword(std::numeric_limits<int>::max());
  } catch (const std::ios_base::failure&) {
    return 0;
  }
  throw 1;
}


terminate called after throwing an instance of 'std::ios_base::failure'
  what():  ios_base::_M_grow_words is not valid
Aborted (core dumped)

This is because src/c++11/functexcept.cc has:

// We don't want to change the type thrown by __throw_ios_failure (yet?)
#define _GLIBCXX_USE_CXX11_ABI 0

I actually planned to change it for GCC5 but missed it. If we change the ABI used to compile functexcept.cc then the code above would fail when using the old ABI instead.

One option to make both forms work would be to hack the EH runtime to make handlers for std::ios_base::failure able to catch std::ios_base::failure[abi:cxx11] objects, and vice versa, creating an object of the other type on the fly.
Comment 1 Jonathan Wakely 2015-05-20 16:58:05 UTC
Let's call this a regression, since the testcase used to catch the exception, but now doesn't with the default build settings.
Comment 2 H.J. Lu 2015-06-01 12:02:37 UTC
*** Bug 66262 has been marked as a duplicate of this bug. ***
Comment 3 Jonathan Wakely 2015-09-18 09:54:45 UTC
*** Bug 67620 has been marked as a duplicate of this bug. ***
Comment 4 Jonathan Wakely 2015-10-06 21:52:47 UTC
Reduced from testcase at  https://bugzilla.redhat.com/show_bug.cgi?id=1269290

#include <iostream>
#include <fstream>
#include <system_error>
#include <exception>


int main() {

  try {
    std::ifstream input("notafile");
    input.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    input.get();
  } catch(const std::ios::failure &e) {
    std::cout << "caught a failure " << e.what()
      << '\n';
  } catch(const std::system_error &e) {
    std::cout << "caught a system_error " << e.what()
      << '\n';
  } catch(const std::runtime_error &e) {
    std::cout << "caught a runtime_error " << e.what()
      << '\n';
  } catch(const std::exception &e) {
    std::cout << "caught an exception " << e.what()
      << '\n';
  }
}

The last handler matches, but it should have matched earlier.
Comment 5 Jonathan Wakely 2015-10-06 23:02:11 UTC
(In reply to Jonathan Wakely from comment #4)
> The last handler matches, but it should have matched earlier.

Doh, this is expected, because the C++03 ios::failure doesn't derive from runtime_error.
Comment 6 Daniel Seither 2015-11-16 10:44:02 UTC
Is there any simple workaround for this bug short of checking f.fail() after each operation?
Comment 7 Jonathan Wakely 2015-11-16 12:16:20 UTC
I would suggest not using exceptions with iostreams, they've always been an odd mix anyway.
Comment 8 Richard Biener 2015-12-04 10:47:30 UTC
GCC 5.3 is being released, adjusting target milestone.
Comment 9 Jonathan Wakely 2016-02-19 19:37:02 UTC
*** Bug 69877 has been marked as a duplicate of this bug. ***
Comment 10 Malcolm Parsons 2016-04-01 09:15:20 UTC
https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html says

"Although the standard exception types defined in <stdexcept> use strings, they are not defined twice, so that a std::out_of_range exception thrown in one file can always be caught by a suitable handler in another file, even if the two files are compiled with different ABIs."

Why doesn't this apply to the std::ios_base exceptions?
Comment 11 Jonathan Wakely 2016-04-01 09:23:59 UTC
(In reply to Malcolm Parsons from comment #10)
> Why doesn't this apply to the std::ios_base exceptions?

Because the C++11 standard mandated an ABI change for std::ios_base::failure, by giving it a std::system_error base class that wasn't present in C++03.
Comment 12 Richard Biener 2016-06-03 10:07:20 UTC
GCC 5.4 is being released, adjusting target milestone.
Comment 13 Boris Kolpackov 2016-07-08 11:45:25 UTC
This is getting pretty bad since recent versions of most distributions (Debian/Ubuntu, Fedora) now have _GLIBCXX_USE_CXX11_ABI set to 1 by default while their libstdc++ still throws "old ABI" ios::failure.

This (i.e., the #define in functexcept.cc), BTW, is still in GCC 6.1.
Comment 14 Jonathan Wakely 2016-07-08 14:09:00 UTC
Yes, and I'm still planning to fix it.

(And I still think using exceptions in iostreams is dumb in the first place).
Comment 15 Boris Kolpackov 2016-07-09 16:33:32 UTC
> And I still think using exceptions in iostreams is dumb in the first place.

I am interested to hear what is your recommendation to do instead, call good()
after every IO operation?

In fact, I think that with inheritance from system_error iostream exceptions finally got (barely) usable. But because of this bug (which is now pervasive) we will probably have to scrap the use of exceptions. So I am genuinely interested to hear about the alternatives/recommendations.
Comment 16 Jonathan Wakely 2016-07-12 11:08:09 UTC
(In reply to Boris Kolpackov from comment #15)
> I am interested to hear what is your recommendation to do instead, call
> good()
> after every IO operation?

The normal way that iostreams are designed to be used:

  if (is >> x >> y >> z)

or

  if (os << a << b << c)

Not explicitly calling good() after every operation, that's dumb too.
Comment 17 Boris Kolpackov 2016-07-12 16:26:54 UTC
> if (is >> x >> y >> z)

And what should happen in the else part of such statements?

if (is >> x >> y >> z)
  ...
else
  throw something();

Also note that if the 'is >> x' call in the above chain fails, you will still execute 'is >> y' and 'is >> z' before noticing the failure.
Comment 18 Jonathan Wakely 2016-07-12 17:10:18 UTC
(In reply to Boris Kolpackov from comment #17)
> > if (is >> x >> y >> z)
> 
> And what should happen in the else part of such statements?
> 
> if (is >> x >> y >> z)
>   ...
> else
>   throw something();

Whatever is appropriate for the program.

> Also note that if the 'is >> x' call in the above chain fails, you will
> still execute 'is >> y' and 'is >> z' before noticing the failure.

But they don't do anything if the stream state isn't good, they just return.

I'm not suggesting anything radical or novel, just the standard way to use iostreams.
Comment 19 Victor Mataré 2016-07-12 18:39:24 UTC
> I'm not suggesting anything radical or novel, just the standard way to use
> iostreams.

I'd call that "the legacy way" or the "C-like pattern". Call it "predominant" or "established" if you wish.

But The Standard also defines an intuitive, modern, exception-driven error handling, and I (probably along with every other developer who dislikes leaky abstractions) really don't see why I shouldn't be using it. Obviously the transition issues after the inheritance change were foreseeable, so I'd expect the C++11 standard or any accompanying document to mention it. Or does the standardization and the resulting guidance deliberately exclude deployment issues such as this?

Maybe anyone with more insight into the standardization process knows anything about this?
Comment 20 Victor Mataré 2016-07-12 18:50:28 UTC
(In reply to Victor Mataré from comment #19)
> > I'm not suggesting anything radical or novel, just the standard way to use
> > iostreams.
> [...]
> Maybe anyone with more insight into the standardization process knows
> anything about this?

Addendum: Maybe one (probably not the best) solution could be to let the linker throw a warning or an error, and to let the distributors sort it out.

Btw, if this triggers a bug somewhere in a larger, existing codebase, it might be hard to track down for developers, so I think we should at least have a warning kinda soonish.
Comment 21 Boris Kolpackov 2016-07-13 15:43:30 UTC
Speaking of possible fixes, I had this crazy idea, not sure if it is technically possible though: what if libstdc++ throws some custom exception that derives from both version of ios::failure? This way both old and new ABI users will be able to catch it via the respective bases.
Comment 22 Shital Shah 2016-07-20 17:34:33 UTC
This bug just bit me and I came to know about this regression via thread on StackOverflow.com. I've also filed related bug where what() method on exception returns irrelevant message: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71950


Hope this gets fixed soon.

Stackoverflow disucssion:

http://stackoverflow.com/questions/38471518/how-to-get-io-error-messages-when-creating-a-file-in-c/
Comment 23 Jonathan Wakely 2016-07-20 19:11:53 UTC
(In reply to Boris Kolpackov from comment #21)
> Speaking of possible fixes, I had this crazy idea, not sure if it is
> technically possible though: what if libstdc++ throws some custom exception
> that derives from both version of ios::failure? This way both old and new
> ABI users will be able to catch it via the respective bases.

Apart from the difficulty of deriving from both types when they can't both be declared at the same time (which could be solved) that solution would mean you couldn't catch it with a handler of type const std::exception&, because the base class would be ambiguous (it's not a virtual base).

Ideally I'd like it to be caught by handlers for std::ios_base::failure and std::ios_base::failure[abi-tag:__cxx11] but I'm not sure that's possible.

Another option is to decide which to throw based on an environment variable, so applications can choose whether they want the types thrown by the library to be catchable by new code or old code.

But we might end up just throwing the new type, and saying old code needs to be recompiled, or just to catch it as std::exception not std::ios_base::failure.
Comment 24 Boris Kolpackov 2016-07-21 14:15:25 UTC
Some more speculation/crazy ideas about the potential fix:

If just throwing the new version and forgetting about the old one is an option, then perhaps we could "de-inherit" old from std::exception and inherit new from this modified variant of old (in addition to system_error). This will give us:

1. Old code will be able to catch it as old ios::failure.

2. Old code will be able to catch it as std::exception (via the new version's inheritance chain).

3. typeid() will even report it as ios::failure (unlike in my previous suggestion).

Regarding how to have two version at the same time, I may be wrong, but I thought inline namespaces were used to implement this dual ABI.
Comment 25 Jonathan Wakely 2016-07-21 14:21:40 UTC
(In reply to Boris Kolpackov from comment #24)
> Some more speculation/crazy ideas about the potential fix:
> 
> If just throwing the new version and forgetting about the old one is an
> option, then perhaps we could "de-inherit" old from std::exception and
> inherit new from this modified variant of old (in addition to system_error).

That would be an ABI break for the old ABI. If breaking the old ABI was an option we wouldn't be in this situation in the first place.

> Regarding how to have two version at the same time, I may be wrong, but I
> thought inline namespaces were used to implement this dual ABI.

No, maybe take a look at the code.
Comment 26 Boris Kolpackov 2016-07-21 15:08:37 UTC
> If breaking the old ABI was an option we wouldn't be in this situation in the first place.

By throwing the new version you are breaking the ABI. The point I was trying to make is that maybe in this case we can allow the old code to still limp along (and thus make this change more palatable).
Comment 27 Davin McCall 2016-11-08 13:54:10 UTC
> Another option is to decide which to throw based on an environment variable, so > applications can choose whether they want the types thrown by the library to be > catchable by new code or old code.

Please don't do this. It will mean programs that require wrapper scripts just to work properly, or problems with old-abi programs launching new-abi programs and vice-versa, and will undoubtedly cause confusion when programs seem to work correctly some of the time and not otherwise.

> But we might end up just throwing the new type, and saying old code needs to be > recompiled, or just to catch it as std::exception not std::ios_base::failure.

If you are going to mandate that old code needs to be recompiled (including if you say that it should catch std::exception, since that requires altering the code and therefore implies recompilation), I would suggest that you also bump the soname; this is definitely an ABI break. At that point you can remove the dual ABI anyway, since you only need to support the new one.

If you do not plan on bumping the soname, but will change the thrown exception type to the new type, I would suggest that this change be made as soon as is practically possible to avoid the production of further software being compiled against the old ABI - which will then need to be recompiled when this change is made. The less that needs to be recompiled the better, especially since that was IIUC the reason for the creation of the dual ABI in the first place.
Comment 28 Jonathan Wakely 2017-01-16 15:58:38 UTC
Author: redi
Date: Mon Jan 16 15:58:06 2017
New Revision: 244498

URL: https://gcc.gnu.org/viewcvs?rev=244498&root=gcc&view=rev
Log:
PR66145 use new ABI for std::ios::failure exceptions

	PR libstdc++/66145
	* src/c++11/functexcept.cc: Use new ABI for std::ios_base::failure
	exceptions.
	* testsuite/27_io/basic_ios/copyfmt/char/1.cc: Don't override ABI
	for test, so new ios::failure can be caught.
	* testsuite/27_io/basic_ios/exceptions/char/1.cc: Likewise.
	* testsuite/27_io/basic_istream/extractors_arithmetic/char/
	exceptions_failbit.cc: Likewise.
	* testsuite/27_io/basic_istream/extractors_arithmetic/wchar_t/
	exceptions_failbit.cc: Likewise.
	* testsuite/27_io/basic_istream/extractors_other/char/
	exceptions_null.cc: Likewise.
	* testsuite/27_io/basic_istream/extractors_other/wchar_t/
	exceptions_null.cc: Likewise.
	* testsuite/27_io/basic_istream/sentry/char/12297.cc: Likewise.
	* testsuite/27_io/basic_istream/sentry/wchar_t/12297.cc: Likewise.
	* testsuite/27_io/basic_ostream/inserters_other/char/
	exceptions_null.cc: Likewise.
	* testsuite/27_io/basic_ostream/inserters_other/wchar_t/
	exceptions_null.cc: Likewise.
	* testsuite/27_io/ios_base/storage/2.cc: Likewise.

Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/src/c++11/functexcept.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_ios/copyfmt/char/1.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_ios/exceptions/char/1.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_istream/extractors_arithmetic/char/exceptions_failbit.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_istream/extractors_arithmetic/wchar_t/exceptions_failbit.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_istream/extractors_other/char/exceptions_null.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_istream/extractors_other/wchar_t/exceptions_null.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_istream/sentry/char/12297.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_istream/sentry/wchar_t/12297.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_other/char/exceptions_null.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_other/wchar_t/exceptions_null.cc
    trunk/libstdc++-v3/testsuite/27_io/ios_base/storage/2.cc
Comment 29 Jonathan Wakely 2017-01-16 16:06:28 UTC
GCC 7 will throw the new ios_base::failure type (unless built so the cxx11 ABI is completely disabled).
Comment 30 Jonathan Wakely 2017-01-20 15:32:42 UTC
I don't plan to change this for gcc 5 and gcc 6, because changing the type of exception thrown by the library doesn't seem appropriate for a minor release within the 5.x or 6.x series.
Comment 31 Jonathan Wakely 2017-02-03 19:27:23 UTC
Author: redi
Date: Fri Feb  3 19:26:51 2017
New Revision: 245167

URL: https://gcc.gnu.org/viewcvs?rev=245167&root=gcc&view=rev
Log:
PR libstdc++/66145 ensure new ABI for ios::failure tests

	PR libstdc++/66145
	* testsuite/27_io/basic_ios/copyfmt/char/1.cc: Restore ABI override
	so new ios::failure can be caught even when old ABI is the default.
	* testsuite/27_io/basic_ios/exceptions/char/1.cc: Likewise.
	* testsuite/27_io/basic_istream/extractors_arithmetic/char/
	exceptions_failbit.cc: Likewise.
	* testsuite/27_io/basic_istream/extractors_arithmetic/wchar_t/
	exceptions_failbit.cc: Likewise.
	* testsuite/27_io/basic_istream/extractors_other/char/
	exceptions_null.cc: Likewise.
	* testsuite/27_io/basic_istream/extractors_other/wchar_t/
	exceptions_null.cc: Likewise.
	* testsuite/27_io/basic_istream/sentry/char/12297.cc: Likewise.
	* testsuite/27_io/basic_istream/sentry/wchar_t/12297.cc: Likewise.
	* testsuite/27_io/basic_ostream/inserters_other/char/
	exceptions_null.cc: Likewise.
	* testsuite/27_io/basic_ostream/inserters_other/wchar_t/
	exceptions_null.cc: Likewise.
	* testsuite/27_io/ios_base/storage/2.cc: Likewise.

Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/testsuite/27_io/basic_ios/copyfmt/char/1.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_ios/exceptions/char/1.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_istream/extractors_arithmetic/char/exceptions_failbit.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_istream/extractors_arithmetic/wchar_t/exceptions_failbit.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_istream/extractors_other/char/exceptions_null.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_istream/extractors_other/wchar_t/exceptions_null.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_istream/sentry/char/12297.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_istream/sentry/wchar_t/12297.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_other/char/exceptions_null.cc
    trunk/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_other/wchar_t/exceptions_null.cc
    trunk/libstdc++-v3/testsuite/27_io/ios_base/storage/2.cc
Comment 32 Richard Biener 2018-04-04 13:43:07 UTC
Now the reverse fails - a program compiled with a GCC defaulting to the old ABI
(like GCC 4.8) now fails to run with a dual-ABI libstdc++:

#include <iostream>
#include <fstream>
using namespace std;
int main ()
{
  std::ifstream pstats;
  pstats.exceptions(ifstream::failbit | ifstream::badbit | ifstream::eofbit);
  try {
      printf("\n Opening file : /proc/0/stat ");
      pstats.open("/proc/0/stat");
  }
  catch(ifstream::failure e)
    {
      printf("\n!!Caught ifstream exception!!\n");
      if(pstats.is_open()) {
          pstats.close();
      }
    }
  return 0;
}
tmp> g++-4.8 t.C
tmp> ./a.out 

terminate called after throwing an instance of 'std::ios_base::failure[abi:cxx11]'
  what():  basic_ios::clear: iostream error
Aborted (core dumped)
tmp> LD_LIBRARY_PATH=/space/rguenther/install/gcc-6.4/lib64 ./a.out 

 Opening file : /proc/0/stat 
!!Caught ifstream exception!!
Comment 33 Richard Biener 2018-04-04 13:59:59 UTC
(In reply to Richard Biener from comment #32)
> Now the reverse fails - a program compiled with a GCC defaulting to the old
> ABI
> (like GCC 4.8) now fails to run with a dual-ABI libstdc++:
> 
> #include <iostream>
> #include <fstream>
> using namespace std;
> int main ()
> {
>   std::ifstream pstats;
>   pstats.exceptions(ifstream::failbit | ifstream::badbit | ifstream::eofbit);
>   try {
>       printf("\n Opening file : /proc/0/stat ");
>       pstats.open("/proc/0/stat");
>   }
>   catch(ifstream::failure e)
>     {
>       printf("\n!!Caught ifstream exception!!\n");
>       if(pstats.is_open()) {
>           pstats.close();
>       }
>     }
>   return 0;
> }
> tmp> g++-4.8 t.C
> tmp> ./a.out 
> 
> terminate called after throwing an instance of
> 'std::ios_base::failure[abi:cxx11]'
>   what():  basic_ios::clear: iostream error
> Aborted (core dumped)
> tmp> LD_LIBRARY_PATH=/space/rguenther/install/gcc-6.4/lib64 ./a.out 
> 
>  Opening file : /proc/0/stat 
> !!Caught ifstream exception!!

--disable-libstdcxx-dual-abi makes the symbol (__throw_ios_failure) throw
c++98 classes again.  --with-default-libstdcxx-abi=gcc4-compatible does not.

Probably impossible to fix without breaking the ABI again, but there should
have been two __throw_ios_failure entries (and callers be "versioned" as well).
At least the old symbol should have been preserved as backward compatible
and a new with a new version be added ... should have been ...
Comment 34 Jonathan Wakely 2018-04-04 16:43:37 UTC
(In reply to Richard Biener from comment #33)
> Probably impossible to fix without breaking the ABI again, but there should
> have been two __throw_ios_failure entries (and callers be "versioned" as
> well).

I considered that, but for 99.99% of cases the caller is inside libstdc++.so not in user code (because the iostream classes are explicitly instantiated in the library), so there's no much point. The library is still only going to call one symbol, either the old one or the new one. For the other 0.01% of calls, having two versions of the function would be an ODR violation, which in practice would mean that non-inlined calls from different translation units have vague linkage and the linker discards all but one copy, which you'd have no control over whether it keeps a copy calling the new version or the old.

To version the calls would have required either versioning the entire iostream hierarchy (and having two or each of std::cout, std::cin, std::cerr, and std::clog) or some nasty hack like every iostreams operation setting a thread-local variable to note whether the caller was new code or old code, and check that flag when throwing to decide which type to throw. But even that wouldn't be right, because the caller might be using one ABI and the location of the catch be using the other one. There's no good solution.

> At least the old symbol should have been preserved as backward compatible
> and a new with a new version be added ... should have been ...

Maybe, but again, since the caller is (almost always) in the library not in user code, the old symbol would never be called.

Although __throw_ios_failure() is visible to user code, they shouldn't ever be calling it directly. It's not a public API.
Comment 35 Richard Biener 2018-04-05 07:42:12 UTC
(In reply to Jonathan Wakely from comment #34)
> (In reply to Richard Biener from comment #33)
> > Probably impossible to fix without breaking the ABI again, but there should
> > have been two __throw_ios_failure entries (and callers be "versioned" as
> > well).
> 
> I considered that, but for 99.99% of cases the caller is inside libstdc++.so
> not in user code (because the iostream classes are explicitly instantiated
> in the library), so there's no much point. The library is still only going
> to call one symbol, either the old one or the new one. For the other 0.01%
> of calls, having two versions of the function would be an ODR violation,
> which in practice would mean that non-inlined calls from different
> translation units have vague linkage and the linker discards all but one
> copy, which you'd have no control over whether it keeps a copy calling the
> new version or the old.
> 
> To version the calls would have required either versioning the entire
> iostream hierarchy (and having two or each of std::cout, std::cin,
> std::cerr, and std::clog)

Yes.

> or some nasty hack like every iostreams operation
> setting a thread-local variable to note whether the caller was new code or
> old code, and check that flag when throwing to decide which type to throw.
> But even that wouldn't be right, because the caller might be using one ABI
> and the location of the catch be using the other one. There's no good
> solution.

Some kind of marshalling between the ABIs so std::ios_base::failure[abi:cxx11]
gets translated to std::ios_base::failure and thus can be catched?

> > At least the old symbol should have been preserved as backward compatible
> > and a new with a new version be added ... should have been ...
> 
> Maybe, but again, since the caller is (almost always) in the library not in
> user code, the old symbol would never be called.
> 
> Although __throw_ios_failure() is visible to user code, they shouldn't ever
> be calling it directly. It's not a public API.

The user code doesn't call this function - the library does so.  But the
user code rightfully so expects to be able to catch exceptions thrown by
the library and that doesn't work anymore.

If that weren't so this very bug should have been closed as WONTFIX instead
of breaking the existing contract between libstdc++ and callers.

I have opened a new bug for the ABI regression.
Comment 36 Jonathan Wakely 2018-04-10 15:04:52 UTC
(In reply to Richard Biener from comment #35)
> I have opened a new bug for the ABI regression.

That's PR 85222 and is now fixed on trunk, so comment 32 works again.
Comment 37 Jonathan Wakely 2018-08-08 15:40:45 UTC
Author: redi
Date: Wed Aug  8 15:40:11 2018
New Revision: 263414

URL: https://gcc.gnu.org/viewcvs?rev=263414&root=gcc&view=rev
Log:
PR libstdc++/66145 allow catching iostream errors as cxx11 ios::failure

Define a new exception type derived from the gcc4-compatible ios::failure
which also aggregates an object of the ios::failure[abi:cxx11] type.
Make __throw_ios_failure throw this new type for iostream errors
that raise exceptions. Provide custom type info for the new type so that
it can be caught by handlers for ios::failure[abi:cxx11] type
as well as handlers for the gcc4-compatible ios::failure and its bases.

Backport from mainline
2018-04-10  Jonathan Wakely  <jwakely@redhat.com>

	PR libstdc++/85222
	* src/c++11/cxx11-ios_failure.cc (__construct_ios_failure)
	(__destroy_ios_failure, is_ios_failure_handler): New functions.
	* src/c++11/ios.cc (__throw_ios_failure): Remove definition.
	(_GLIBCXX_USE_CXX11_ABI): Don't define here.
	* src/c++98/Makefile.am [ENABLE_DUAL_ABI]: Add special rules for
	ios_failure.cc to rewrite type info for __ios_failure.
	* src/c++98/Makefile.in: Regenerate.
	* src/c++98/ios_failure.cc [_GLIBCXX_USE_DUAL_ABI]
	(__iosfailure, __iosfailure_type_info): New types.
	(__throw_ios_failure): Define here.
	* testsuite/27_io/ios_base/failure/dual_abi.cc: New.
	* testsuite/27_io/basic_ios/copyfmt/char/1.cc: Revert changes to
	add -D_GLIBCXX_USE_CXX11_ABI=0 to dg-options.
	* testsuite/27_io/basic_ios/exceptions/char/1.cc: Likewise.
	* testsuite/27_io/basic_istream/extractors_arithmetic/char/
	exceptions_failbit.cc: Likewise.
	* testsuite/27_io/basic_istream/extractors_arithmetic/wchar_t/
	exceptions_failbit.cc: Likewise.
	* testsuite/27_io/basic_istream/extractors_other/char/
	exceptions_null.cc: Likewise.
	* testsuite/27_io/basic_istream/extractors_other/wchar_t/
	exceptions_null.cc: Likewise.
	* testsuite/27_io/basic_istream/sentry/char/12297.cc: Likewise.
	* testsuite/27_io/basic_istream/sentry/wchar_t/12297.cc: Likewise.
	* testsuite/27_io/basic_ostream/inserters_other/char/
	exceptions_null.cc: Likewise.
	* testsuite/27_io/basic_ostream/inserters_other/wchar_t/
	exceptions_null.cc: Likewise.
	* testsuite/27_io/ios_base/storage/2.cc: Likewise.

Added:
    branches/gcc-6-branch/libstdc++-v3/testsuite/27_io/ios_base/failure/dual_abi.cc
Modified:
    branches/gcc-6-branch/libstdc++-v3/ChangeLog
    branches/gcc-6-branch/libstdc++-v3/src/c++11/cxx11-ios_failure.cc
    branches/gcc-6-branch/libstdc++-v3/src/c++11/ios.cc
    branches/gcc-6-branch/libstdc++-v3/src/c++98/Makefile.am
    branches/gcc-6-branch/libstdc++-v3/src/c++98/Makefile.in
    branches/gcc-6-branch/libstdc++-v3/src/c++98/ios_failure.cc
    branches/gcc-6-branch/libstdc++-v3/testsuite/27_io/basic_ios/copyfmt/char/1.cc
    branches/gcc-6-branch/libstdc++-v3/testsuite/27_io/basic_ios/exceptions/char/1.cc
    branches/gcc-6-branch/libstdc++-v3/testsuite/27_io/basic_istream/extractors_arithmetic/char/exceptions_failbit.cc
    branches/gcc-6-branch/libstdc++-v3/testsuite/27_io/basic_istream/extractors_arithmetic/wchar_t/exceptions_failbit.cc
    branches/gcc-6-branch/libstdc++-v3/testsuite/27_io/basic_istream/extractors_other/char/exceptions_null.cc
    branches/gcc-6-branch/libstdc++-v3/testsuite/27_io/basic_istream/extractors_other/wchar_t/exceptions_null.cc
    branches/gcc-6-branch/libstdc++-v3/testsuite/27_io/basic_istream/sentry/char/12297.cc
    branches/gcc-6-branch/libstdc++-v3/testsuite/27_io/basic_istream/sentry/wchar_t/12297.cc
    branches/gcc-6-branch/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_other/char/exceptions_null.cc
    branches/gcc-6-branch/libstdc++-v3/testsuite/27_io/basic_ostream/inserters_other/wchar_t/exceptions_null.cc
    branches/gcc-6-branch/libstdc++-v3/testsuite/27_io/ios_base/storage/2.cc