[Bug libstdc++/85222] [7/8 Regression] ABI breakage of __throw_ios_failure by r244498
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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&