Summary: | [5/6/7 Regression] std::ios_base::failure objects thrown from libstdc++.so use old ABI | ||
---|---|---|---|
Product: | gcc | Reporter: | Jonathan Wakely <redi> |
Component: | libstdc++ | Assignee: | Jonathan Wakely <redi> |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | boris, compnerd, daniel.kruegler, davmac, doko, jaak, rguenth, tavianator, webrown.cpp |
Priority: | P2 | Keywords: | ABI, wrong-code |
Version: | 5.0 | ||
Target Milestone: | 7.0 | ||
Host: | Target: | ||
Build: | Known to work: | 4.8.4, 4.9.2 | |
Known to fail: | Last reconfirmed: | 2015-05-20 00:00:00 | |
Bug Depends on: | 85222 | ||
Bug Blocks: |
Description
Jonathan Wakely
2015-05-14 16:59:24 UTC
Let's call this a regression, since the testcase used to catch the exception, but now doesn't with the default build settings. *** Bug 66262 has been marked as a duplicate of this bug. *** *** Bug 67620 has been marked as a duplicate of this bug. *** 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. (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. Is there any simple workaround for this bug short of checking f.fail() after each operation? I would suggest not using exceptions with iostreams, they've always been an odd mix anyway. GCC 5.3 is being released, adjusting target milestone. *** Bug 69877 has been marked as a duplicate of this bug. *** 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? (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. GCC 5.4 is being released, adjusting target milestone. 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. Yes, and I'm still planning to fix it. (And I still think using exceptions in iostreams is dumb in the first place). > 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.
(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. > 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.
(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. > 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?
(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. 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. 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/ (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. 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. (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. > 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).
> 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. 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 GCC 7 will throw the new ios_base::failure type (unless built so the cxx11 ABI is completely disabled). 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. 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 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!! (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 ... (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. (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. (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. 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 |