[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-10 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #21 from Jonathan Wakely  ---
Author: redi
Date: Tue Apr 10 14:36:09 2018
New Revision: 259281

URL: https://gcc.gnu.org/viewcvs?rev=259281&root=gcc&view=rev
Log:
PR libstdc++/85222 allow catching iostream errors as gcc4-compatible
ios::failure

Define a new exception type derived from std::ios::failure[abi:cxx11]
which also aggregates an object of the gcc4-compatible ios::failure
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 the gcc4-compatible ios::failure type
as well as handlers for ios::failure[abi:cxx11] and its bases.

PR libstdc++/85222
* src/c++11/Makefile.am [ENABLE_DUAL_ABI]: Add special rules for
cxx11-ios_failure.cc to rewrite type info for __ios_failure.
* src/c++11/Makefile.in: Regenerate.
* src/c++11/cxx11-ios_failure.cc (__ios_failure, __iosfail_type_info):
New types.
[_GLIBCXX_USE_DUAL_ABI] (__throw_ios_failure): Define here.
* src/c++11/ios.cc (__throw_ios_failure): Remove definition.
* src/c++98/ios_failure.cc (__construct_ios_failure)
(__destroy_ios_failure, is_ios_failure_handler): New functions.
[!_GLIBCXX_USE_DUAL_ABI] (__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
handler types, to always catch std::ios_base::failure.
* 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:
trunk/libstdc++-v3/testsuite/27_io/ios_base/failure/dual_abi.cc
Modified:
trunk/libstdc++-v3/ChangeLog
trunk/libstdc++-v3/src/c++11/Makefile.am
trunk/libstdc++-v3/src/c++11/Makefile.in
trunk/libstdc++-v3/src/c++11/cxx11-ios_failure.cc
trunk/libstdc++-v3/src/c++11/ios.cc
trunk/libstdc++-v3/src/c++98/ios_failure.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

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-10 Thread rguenth at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

Richard Biener  changed:

   What|Removed |Added

   Priority|P3  |P2

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-09 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

Jonathan Wakely  changed:

   What|Removed |Added

   Keywords||patch

--- Comment #20 from Jonathan Wakely  ---
Patch posted: https://gcc.gnu.org/ml/gcc-patches/2018-04/msg00424.html

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-09 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

Jonathan Wakely  changed:

   What|Removed |Added

 Status|UNCONFIRMED |ASSIGNED
   Last reconfirmed||2018-04-09
   Assignee|unassigned at gcc dot gnu.org  |redi at gcc dot gnu.org
 Ever confirmed|0   |1

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-06 Thread rguenth at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #19 from Richard Biener  ---
Luckily both failure classes are immutable (via access limitations) so the
following issue with the __dual_ios_failure idea doesn't exist:

 catch (old-ABI &e)
   {
 modify e in-place
 throw;
   }
 ...
 catch (new-ABI &e)
   {
 ... expect modified content ...
   }

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-06 Thread rguenther at suse dot de
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #18 from rguenther at suse dot de  ---
On Fri, 6 Apr 2018, redi at gcc dot gnu.org wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222
> 
> --- Comment #15 from Jonathan Wakely  ---
> (In reply to Richard Biener from comment #13)
> > I'm probably going to locally patch it to be consistent with the default ABI
> > choice - that at least keeps programs working that do not explicitely choose
> > the ABI via #define _GLIBCXX_USE_CXX11_ABI and is consistent with the system
> > integrators choice of the default ABI to keep compatibility to older GCC
> > versions.
> 
> That makes sense. Maybe we should do that on trunk too (it doesn't affect the
> default configuration where the new ABI is the default).

FYI:

Index: libstdc++-v3/src/c++11/ios.cc
===
--- libstdc++-v3/src/c++11/ios.cc   (revision 258812)
+++ libstdc++-v3/src/c++11/ios.cc   (working copy)
@@ -26,9 +26,8 @@
 // ISO C++ 14882: 27.4  Iostreams base classes
 //

-// Determines the version of ios_base::failure thrown by 
__throw_ios_failure.
-// If !_GLIBCXX_USE_DUAL_ABI this will get undefined automatically.
-#define _GLIBCXX_USE_CXX11_ABI 1
+// The ABI version of ios_base::failure thrown by __throw_ios_failure
+// is determined by the default ABI version choosed at configure time

 #include 
 #include 

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-06 Thread rguenther at suse dot de
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #17 from rguenther at suse dot de  ---
On Fri, 6 Apr 2018, redi at gcc dot gnu.org wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222
> 
> --- Comment #16 from Jonathan Wakely  ---
> (In reply to Jakub Jelinek from comment #14)
> > For the in-place transformation in libsupc++ if something catches the old
> > failure and a new failure is thrown, is it possible?  The other way around,
> > if we would be throwing the new failure and catching the old one, doesn't
> > seem to be possible, the cxx11 failure is bigger (32 bytes compared to 16
> > bytes for the old one).
> 
> I must be misunderstanding the scenario you're describing, because to me it
> seems like we could use 32 bytes to store a 16 byte object, but not the other
> way around.
> 
> Anyway, I think in-place transformations are not an option. Code could have
> pointers to the data in the original exception. If we destroy it and create a
> new object in the same location we invalidate those pointers.

Yeah, I think throwing a composite object of both representation is
the easiest way here (apart from the difficulty to build that in
the first place).

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-06 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #16 from Jonathan Wakely  ---
(In reply to Jakub Jelinek from comment #14)
> For the in-place transformation in libsupc++ if something catches the old
> failure and a new failure is thrown, is it possible?  The other way around,
> if we would be throwing the new failure and catching the old one, doesn't
> seem to be possible, the cxx11 failure is bigger (32 bytes compared to 16
> bytes for the old one).

I must be misunderstanding the scenario you're describing, because to me it
seems like we could use 32 bytes to store a 16 byte object, but not the other
way around.

Anyway, I think in-place transformations are not an option. Code could have
pointers to the data in the original exception. If we destroy it and create a
new object in the same location we invalidate those pointers.

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-06 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #15 from Jonathan Wakely  ---
(In reply to Richard Biener from comment #13)
> I'm probably going to locally patch it to be consistent with the default ABI
> choice - that at least keeps programs working that do not explicitely choose
> the ABI via #define _GLIBCXX_USE_CXX11_ABI and is consistent with the system
> integrators choice of the default ABI to keep compatibility to older GCC
> versions.

That makes sense. Maybe we should do that on trunk too (it doesn't affect the
default configuration where the new ABI is the default).

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-06 Thread jakub at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

Jakub Jelinek  changed:

   What|Removed |Added

 CC||jakub at gcc dot gnu.org

--- Comment #14 from Jakub Jelinek  ---
For the in-place transformation in libsupc++ if something catches the old
failure and a new failure is thrown, is it possible?  The other way around, if
we would be throwing the new failure and catching the old one, doesn't seem to
be possible, the cxx11 failure is bigger (32 bytes compared to 16 bytes for the
old one).  Could we just move it to a temporary, in-place construct the old one
and destruct the temporary?  What if the code then rethrows it and is caught
again in code that expects the new failure?

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-06 Thread rguenth at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #13 from Richard Biener  ---
Just to mention the testcase fails in the same way if you build and run it with
GCC 7 and libstdc++ from GCC 7 when that was configured with the gcc-4
compatible ABI by default.  Just in case that wasn't obvious...

Dropping the

// Determines the version of ios_base::failure thrown by __throw_ios_failure.
// If !_GLIBCXX_USE_DUAL_ABI this will get undefined automatically.
#define _GLIBCXX_USE_CXX11_ABI 1

from src/c++11/ios.cc probably makes that more "consistent", matching the
default ABI.  The PR66145 changed that from an unconditional #define to
0 to an unconditional #define to 1.  While, as the comment now says, a build
without the dual-abi will use the old behavior switching the ABI default
does not influence the behavior.

I realize PR66145 is exactly about "fixing" the case of the user not using
the default ABI but now we have still exactly the same situation when the user
does

#define _GLIBCXX_USE_CXX11_ABI 0

with a compiler defaulted to the new ABI.

So IMHO the original change was totally pointless... :/

I'm probably going to locally patch it to be consistent with the default ABI
choice - that at least keeps programs working that do not explicitely choose
the ABI via #define _GLIBCXX_USE_CXX11_ABI and is consistent with the system
integrators choice of the default ABI to keep compatibility to older GCC
versions.

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-05 Thread rguenther at suse dot de
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #12 from rguenther at suse dot de  ---
On Thu, 5 Apr 2018, rguenther at suse dot de wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222
> 
> --- Comment #11 from rguenther at suse dot de  ---
> On Thu, 5 Apr 2018, redi at gcc dot gnu.org wrote:
> 
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222
> > 
> > --- Comment #10 from Jonathan Wakely  ---
> > Seems simpler to just define:
> > 
> > struct __dual_ios_failure {
> >   __dual_ios_failure(std::string s, error_code e) : new_(s, e), old_(s) { }
> >   ios::failure[abi:cxx11] new_;
> >   ios::failure old_;
> > };
> > 
> > and make __throw_ios_failure() throw one of that type, and make the EH 
> > runtime
> > do the necessary adjustments to make this work:
> > 
> > __dual_ios_failure * p1;
> > 
> > try {
> >   try {
> > try {
> >   throw __dual_ios_failure("", {});
> > } catch (__dual_ios_failure& e1) {
> >   p1 = &e1;
> >   throw;
> > }
> >   } catch (ios::failure[abi:cxx11]& e2) {
> > assert( &e2 == &p1->new_ );
> > throw;
> >   }
> > } catch (ios::failure& e3) {
> >   assert( &e3 == &p1->old_ );
> > }
> > 
> > i.e. if the catch handler is one of the ios::failure types and the actual
> > thrown exception is __dual_ios_failure then catch the member instead of the
> > object itself. The "throw;" would re-throw the original object of type
> > __dual_abi_failure, so the next handler would be able to perform the same
> > checks and adjustments.
> > 
> > This would only require magic in the EH catch routines, not a new way to
> > declare base classes.
> 
> True.  Given the issue of declaring the __dual_ios_failure type - as you
> said, you can't write it that way - it's probably going to be a
> builtin type?  In which case "massaging" the typeinfo data to make
> the code in the EH catchers less special might be easier.
> 
> Not sure, I'm not at all familiar with these areas of GCC internals.
> 
> Whatever it takes, it would be nice to fix this in a way not
> breaking pre-GCC7 nor GCC7-and-later code...

So you'd have a new internal composite type which you'd associate
with a typeinfo refering to some custom 
__cxxabiv1::__mab_class_type_info you'd then
implement the special filtering on?  (mab aka multiple ambiguous
bases)

The internal type could the still look like it was just
multiple-inherited from the two exception types?

That would leave the rest of the EH personality alone and thus
not affect runtime of other exception type propagation.

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-05 Thread rguenther at suse dot de
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #11 from rguenther at suse dot de  ---
On Thu, 5 Apr 2018, redi at gcc dot gnu.org wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222
> 
> --- Comment #10 from Jonathan Wakely  ---
> Seems simpler to just define:
> 
> struct __dual_ios_failure {
>   __dual_ios_failure(std::string s, error_code e) : new_(s, e), old_(s) { }
>   ios::failure[abi:cxx11] new_;
>   ios::failure old_;
> };
> 
> and make __throw_ios_failure() throw one of that type, and make the EH runtime
> do the necessary adjustments to make this work:
> 
> __dual_ios_failure * p1;
> 
> try {
>   try {
> try {
>   throw __dual_ios_failure("", {});
> } catch (__dual_ios_failure& e1) {
>   p1 = &e1;
>   throw;
> }
>   } catch (ios::failure[abi:cxx11]& e2) {
> assert( &e2 == &p1->new_ );
> throw;
>   }
> } catch (ios::failure& e3) {
>   assert( &e3 == &p1->old_ );
> }
> 
> i.e. if the catch handler is one of the ios::failure types and the actual
> thrown exception is __dual_ios_failure then catch the member instead of the
> object itself. The "throw;" would re-throw the original object of type
> __dual_abi_failure, so the next handler would be able to perform the same
> checks and adjustments.
> 
> This would only require magic in the EH catch routines, not a new way to
> declare base classes.

True.  Given the issue of declaring the __dual_ios_failure type - as you
said, you can't write it that way - it's probably going to be a
builtin type?  In which case "massaging" the typeinfo data to make
the code in the EH catchers less special might be easier.

Not sure, I'm not at all familiar with these areas of GCC internals.

Whatever it takes, it would be nice to fix this in a way not
breaking pre-GCC7 nor GCC7-and-later code...

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-05 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #10 from Jonathan Wakely  ---
Seems simpler to just define:

struct __dual_ios_failure {
  __dual_ios_failure(std::string s, error_code e) : new_(s, e), old_(s) { }
  ios::failure[abi:cxx11] new_;
  ios::failure old_;
};

and make __throw_ios_failure() throw one of that type, and make the EH runtime
do the necessary adjustments to make this work:

__dual_ios_failure * p1;

try {
  try {
try {
  throw __dual_ios_failure("", {});
} catch (__dual_ios_failure& e1) {
  p1 = &e1;
  throw;
}
  } catch (ios::failure[abi:cxx11]& e2) {
assert( &e2 == &p1->new_ );
throw;
  }
} catch (ios::failure& e3) {
  assert( &e3 == &p1->old_ );
}

i.e. if the catch handler is one of the ios::failure types and the actual
thrown exception is __dual_ios_failure then catch the member instead of the
object itself. The "throw;" would re-throw the original object of type
__dual_abi_failure, so the next handler would be able to perform the same
checks and adjustments.

This would only require magic in the EH catch routines, not a new way to
declare base classes.

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-05 Thread rguenth at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #9 from Richard Biener  ---
(In reply to Jonathan Wakely from comment #8)
> (In reply to rguent...@suse.de from comment #7)
> > > It's not required to fix the simple case of a legacy binary using a new
> > > libstdc++.so but it breaks other cases.
> > 
> > None that are not broken right now?
> 
> Well with the case of a legacy shared lib and a new main(), currently the
> shared lib won't catch the exception but main will. It's arguably more
> broken if main doesn't catch it and terminates with an unhandled exception.
>  
> > Anyway, what would happen if __throw_ios_failure would throw a
> > 
> > struct ios_failure : ios_base::failure, ios_base::failure[c++11]
> > 
> > class (with both sub-classes properly initialized)?
> 
> Bug 66145 comment 23.

Bah.  Stupid C++ for not providing a way to disambiguate ;)

Looks like it also fails silently - just not catch anything.

> > 
> > If I do
> > 
> >   catch (ios_base::failure[c++11] &e)
> 
> You can't use the ABI tag in the name like this.

Of course, it was just pseudo-code.  Apart from the above issue which
makes it a non-starter it works though.

Downstream comments in the bug already argue you're breaking the ABI :/

Now it might be (no idea!) simpler to "fix" this in the unwinder when
an object with the above multi-inheritance is thrown (just to fix the
std::exception case).  Either by being able to modify the actual
implementation of the inheritance meta-data (if such exists) to avoid
the ambiguity and just re-direct to either base or by detecting the
situation and doing that manually.

Thus, provide an "extension" that makes the following valid:

struct base {};
struct err1 : base { };
struct err2 : base { };
struct err : err1, err2 /**/ { };

void f()
{
  err e;
  base &b = e;
}

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-05 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #8 from Jonathan Wakely  ---
(In reply to rguent...@suse.de from comment #7)
> > It's not required to fix the simple case of a legacy binary using a new
> > libstdc++.so but it breaks other cases.
> 
> None that are not broken right now?

Well with the case of a legacy shared lib and a new main(), currently the
shared lib won't catch the exception but main will. It's arguably more broken
if main doesn't catch it and terminates with an unhandled exception.

> Anyway, what would happen if __throw_ios_failure would throw a
> 
> struct ios_failure : ios_base::failure, ios_base::failure[c++11]
> 
> class (with both sub-classes properly initialized)?

Bug 66145 comment 23.

> 
> If I do
> 
>   catch (ios_base::failure[c++11] &e)

You can't use the ABI tag in the name like this.

>{
>  throw e;
>}
> 
> does it re-throw the original exception type?

No, "throw e;" throws a new exception object. If you just do "throw;" it
re-throws the original exception.

>  Can I catch
> that ios_failure class at all this way?

I'm not sure what "this way" refers to.

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-05 Thread rguenther at suse dot de
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #7 from rguenther at suse dot de  ---
On Thu, 5 Apr 2018, redi at gcc dot gnu.org wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222
> 
> --- Comment #6 from Jonathan Wakely  ---
> (In reply to rguent...@suse.de from comment #5)
> > On Thu, 5 Apr 2018, redi at gcc dot gnu.org wrote:
> > 
> > > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222
> > > 
> > > --- Comment #4 from Jonathan Wakely  ---
> > > (In reply to Richard Biener from comment #3)
> > > > Do you know of any other exception type affected by the c++11 vs. old 
> > > > ABI
> > > > issue or does the entire I/O hierarchy only ever throw exactly
> > > > ios_base::failure?
> > > 
> > > That's the only one.
> > > 
> > > > So a workaround would be to marshal these somehow in the C++ EH 
> > > > personality
> > > > routine?  The c++11 variant seems to be a superset feature-wise (apart 
> > > > from
> > > > the changed inheritance), so constructing (in-place?!) the c++98 variant
> > > > once we hit a filter for c++98 ios_base::failure with an EH object of
> > > > type ios_base::failure[c++11] would "work"?
> > > 
> > > Until you try to rethrow it and catch it as the new type again.
> > 
> > Ok, but that would be an even more weird case of an intermediate
> > old-ABI object sitting inbetween the c++11 throwing libstdc++ and
> > a c++11 object.
> 
> Which can happen with a legacy shared library trying to catch the old
> ios::failure, log something, and then re-throw it. If that shared library is
> used by a program where the main() function is using the new ABI and main()
> tries to catch ios::failure at the top-level, it won't be able to if the
> exception was replaced by another type.
> 
> > So the old std::ios::failure doesn't fit in the new one?
> 
> It fits, but overwriting it in place can create data races and invalidate
> existing references to the original object that was overwritten.
> 
> >  As said
> > above I consider the re-throwing and catching as c++11 a situation
> > that shouldn't be required for fixing the "legacy" binary case.
> 
> It's not required to fix the simple case of a legacy binary using a new
> libstdc++.so but it breaks other cases.

None that are not broken right now?

Anyway, what would happen if __throw_ios_failure would throw a

struct ios_failure : ios_base::failure, ios_base::failure[c++11]

class (with both sub-classes properly initialized)?

If I do

  catch (ios_base::failure[c++11] &e)
   {
 throw e;
   }

does it re-throw the original exception type?  Can I catch
that ios_failure class at all this way?

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-05 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #6 from Jonathan Wakely  ---
(In reply to rguent...@suse.de from comment #5)
> On Thu, 5 Apr 2018, redi at gcc dot gnu.org wrote:
> 
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222
> > 
> > --- Comment #4 from Jonathan Wakely  ---
> > (In reply to Richard Biener from comment #3)
> > > Do you know of any other exception type affected by the c++11 vs. old ABI
> > > issue or does the entire I/O hierarchy only ever throw exactly
> > > ios_base::failure?
> > 
> > That's the only one.
> > 
> > > So a workaround would be to marshal these somehow in the C++ EH 
> > > personality
> > > routine?  The c++11 variant seems to be a superset feature-wise (apart 
> > > from
> > > the changed inheritance), so constructing (in-place?!) the c++98 variant
> > > once we hit a filter for c++98 ios_base::failure with an EH object of
> > > type ios_base::failure[c++11] would "work"?
> > 
> > Until you try to rethrow it and catch it as the new type again.
> 
> Ok, but that would be an even more weird case of an intermediate
> old-ABI object sitting inbetween the c++11 throwing libstdc++ and
> a c++11 object.

Which can happen with a legacy shared library trying to catch the old
ios::failure, log something, and then re-throw it. If that shared library is
used by a program where the main() function is using the new ABI and main()
tries to catch ios::failure at the top-level, it won't be able to if the
exception was replaced by another type.

> So the old std::ios::failure doesn't fit in the new one?

It fits, but overwriting it in place can create data races and invalidate
existing references to the original object that was overwritten.

>  As said
> above I consider the re-throwing and catching as c++11 a situation
> that shouldn't be required for fixing the "legacy" binary case.

It's not required to fix the simple case of a legacy binary using a new
libstdc++.so but it breaks other cases.

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-05 Thread rguenther at suse dot de
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #5 from rguenther at suse dot de  ---
On Thu, 5 Apr 2018, redi at gcc dot gnu.org wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222
> 
> --- Comment #4 from Jonathan Wakely  ---
> (In reply to Richard Biener from comment #3)
> > Do you know of any other exception type affected by the c++11 vs. old ABI
> > issue or does the entire I/O hierarchy only ever throw exactly
> > ios_base::failure?
> 
> That's the only one.
> 
> > So a workaround would be to marshal these somehow in the C++ EH personality
> > routine?  The c++11 variant seems to be a superset feature-wise (apart from
> > the changed inheritance), so constructing (in-place?!) the c++98 variant
> > once we hit a filter for c++98 ios_base::failure with an EH object of
> > type ios_base::failure[c++11] would "work"?
> 
> Until you try to rethrow it and catch it as the new type again.

Ok, but that would be an even more weird case of an intermediate
old-ABI object sitting inbetween the c++11 throwing libstdc++ and
a c++11 object.

> This approach was considered, and deemed not worth the complexity (and
> additional performance hit that would affect every 'catch' in every program
> that has to check if the catch handler is for ios::failure).

True.  But given we have broken things fixing it either requires
breaking the ABI for c++11 objects compiled with gcc 7 or leaving
things broken for objects compiled with gcc 3.4 to gcc 6.  Or
doing a hack like that.

My main concern is that the dual-ABI story breaks down in the current
situation where there isn't a single libstdc++ that makes both
situations work (catch c++11 ios_base::failure and c++98 
ios_base::failure).  So there's no way you can deploy the dual-ABI
libstdc++ on an existing system without possibly breaking old
programs (or not providing the C++11 ABI at all).  In fact
there isn't a good workaround forward to have both apart from
changing the SONAME for the C++11 ABI library or playing other
tricks via LD_LIBRARY_PATH or so.

> It would be possible to make __throw_ios_failure() throw:
> 
> struct enhanced_failure : std::ios::failure {
>   unsigned char buf[sizeof old ios::failure];
> };
> 
> This can be caught as the new type, and when there's an attempt to catch it as
> the old type, construct it in the buffer and catch the object in the buffer.
> Constructing it lazily can introduce a race condition, so it might be better 
> to
> always pre-propulate the buffer, just in case anybody wants to catch the old
> type.

So the old std::ios::failure doesn't fit in the new one?  As said
above I consider the re-throwing and catching as c++11 a situation
that shouldn't be required for fixing the "legacy" binary case.

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-05 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #4 from Jonathan Wakely  ---
(In reply to Richard Biener from comment #3)
> Do you know of any other exception type affected by the c++11 vs. old ABI
> issue or does the entire I/O hierarchy only ever throw exactly
> ios_base::failure?

That's the only one.

> So a workaround would be to marshal these somehow in the C++ EH personality
> routine?  The c++11 variant seems to be a superset feature-wise (apart from
> the changed inheritance), so constructing (in-place?!) the c++98 variant
> once we hit a filter for c++98 ios_base::failure with an EH object of
> type ios_base::failure[c++11] would "work"?

Until you try to rethrow it and catch it as the new type again.

This approach was considered, and deemed not worth the complexity (and
additional performance hit that would affect every 'catch' in every program
that has to check if the catch handler is for ios::failure).

It would be possible to make __throw_ios_failure() throw:

struct enhanced_failure : std::ios::failure {
  unsigned char buf[sizeof old ios::failure];
};

This can be caught as the new type, and when there's an attempt to catch it as
the old type, construct it in the buffer and catch the object in the buffer.
Constructing it lazily can introduce a race condition, so it might be better to
always pre-propulate the buffer, just in case anybody wants to catch the old
type.

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-05 Thread rguenth at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #3 from Richard Biener  ---
Do you know of any other exception type affected by the c++11 vs. old ABI issue
or does the entire I/O hierarchy only ever throw exactly ios_base::failure?

So a workaround would be to marshal these somehow in the C++ EH personality
routine?  The c++11 variant seems to be a superset feature-wise (apart from
the changed inheritance), so constructing (in-place?!) the c++98 variant
once we hit a filter for c++98 ios_base::failure with an EH object of
type ios_base::failure[c++11] would "work"?

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-05 Thread rguenth at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #2 from Richard Biener  ---
(In reply to Jonathan Wakely from comment #1)
> (In reply to Richard Biener from comment #0)
> > A workaround is to use a libstdc++ built with --disable-libstdcxx-dual-abi
> 
> Or to catch std::exception&

That isn't a workaround for existing binaries.

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-05 Thread rguenth at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

Richard Biener  changed:

   What|Removed |Added

  Known to work||6.4.0
   Target Milestone|--- |7.4
  Known to fail||7.1.0, 8.0

[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498

2018-04-05 Thread redi at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85222

--- Comment #1 from Jonathan Wakely  ---
(In reply to Richard Biener from comment #0)
> A workaround is to use a libstdc++ built with --disable-libstdcxx-dual-abi

Or to catch std::exception&