Exception not caught opening a non-existing file using C++ - c++

I was running a MWE from here:
http://www.cplusplus.com/reference/ios/ios/exceptions/
On my machine it does not catch the exception. Here is my code
#include <iostream>
#include <fstream>
int main()
{
std::ifstream file;
file.exceptions( std::ifstream::failbit | std::ifstream::badbit );
try
{
file.open("IDoNotExist.txt");
}
catch(const std::ifstream::failure& e)
{
std::cout << "Bad luck!" << std::endl;
}
}
Using gcc 6.2.1 on Arch-Linux I get:
terminate called after throwing an instance of 'std::ios_base::failure'
what(): basic_ios::clear
However, on the link posted above it is mentioned that the code should also catch the exception related to opening the file. What went wrong?

It looks like a known bug in libstdc++.
The problem is that with the change to the C++11 ABI, many classes were duplicated in libstdc++6.so, one version with the old ABI, other with the new one.
Exception classes were not duplicated so this problem didn't exist at the time. But then, in some newer revision of the language, it was decided that std::ios_base::failure should derive from std::system_error instead of std::exception... but system_error is a C++11 only class so it must use the new ABI flag or it will complain. Now you have two different std::ios_base::failure classes and a mess in your hands!
The easy solution is to compile your program with -D_GLIBCXX_USE_CXX11_ABI=0 and resign to the old ABI until the bug is solved. Or alternatively, write catch (std::exception &e).

N.B. std::ifstream::failure is a type defined in the std::ios_base base class of ifstream, so the rest of this answer refers to it as std::ios_base::failure or just std::ios::failure.
The problem here is that since GCC 5 there are two different definitions of std::ios_base::failure in libstdc++ (see the Dual ABI docs for more details). That's needed because C++11 changed the definition of ios::failure from:
class ios_base::failure : public exception {
to:
class ios_base::failure : public system_error {
This is an ABI change, because system_error has additional data members compared to exception, and so it changes the size and layout of ios::failure.
So since GCC 5.1, when your code names std::ios_base::failure (or std::ifstream::failure or any other name for it) which definition you get depends on the value of the _GLIBCXX_USE_CXX11_ABI macro. And when an iostream error happens inside the libstdc++.so library, which type gets thrown depends on the value of the macro when libstdc++.so was built. If you try to catch one type and the library throws the other type, the catch won't work. This is what you're seeing. In your code std::ifstream::failure names the new type, but the library is throwing the old type, which is a different class, so the catch handler isn't matched.
With GCC 5.x and 6.x the code inside libstdc++.so throws the old type, so to catch it you need to either compile you code with -D_GLIBCXX_USE_CXX11_ABI=0 or change your handler to catch (const std::exception&) (because both the old and new types derive from std::exception).
With GCC 7.x the code inside the library throws the new type (changed by PR 66145), so you need to compile your code with -D_GLIBCXX_USE_CXX11_ABI=1 or catch std::exception.
For GCC 8.x the library now throws an exception type that can be caught by a handler for the old type or the new type (changed by PR 85222), so you don't need to change your code. It will Just Work™.

Related

Does BOOST_NO_EXCEPTIONS guarantee compatibility to -fno-exceptions?

I want to use Boost.Filesystem together with -fno-exceptions. According to the Boost.Filesystem documentation it states that it supports the BOOST_NO_EXCEPTIONS macro.
However, the following snippet:
#define BOOST_NO_EXCEPTIONS
#include <boost/filesystem.hpp>
int main() {}
compiled with:
g++ -fno-exceptions boost_test.cpp
gives the error:
/.../boost/filesystem/operations.hpp: In constructor
'boost::filesystem::filesystem_error::filesystem_error(const string&,
boost::system::error_code)':
/.../boost/filesystem/operations.hpp:84:16: error:
exception handling disabled, use -fexceptions to enable
catch (...) { m_imp_ptr.reset(); }
I compile using gcc 5 and boost version 1.57 on Mac OSX (also tested on similar ubuntu setups).
I am wondering whether my understanding of BOOST_NO_EXCEPTIONS is right in that it should cover the usage of -fno-exceptions or whether it's simply there for the boost::throw_exception part?
Well, "no" is the obvious answer here, g++ cannot deal with the filesystem_error class. There's a humdinger in boost/filesystem/config.hpp:
// throw an exception ----------------------------------------------------------------//
//
// Exceptions were originally thrown via boost::throw_exception().
// As throw_exception() became more complex, it caused user error reporting
// to be harder to interpret, since the exception reported became much more complex.
// The immediate fix was to throw directly, wrapped in a macro to make any later change
// easier.
#define BOOST_FILESYSTEM_THROW(EX) throw EX
This macro is used extensively in libs/filesystem/src/operations.cpp to throw exceptions. This is a show-stopper.
Fwiw, your sample program only appears to compile properly in clang and MSVC++, they only complain in their back-end about having to emit exception handling code, g++ does it in its front-end. No complaint from clang/msvc++ for this sample code since that exception handling code was already emitted previously, back when the boost libraries were built.
Which demonstrates another severe problem with your approach, you probably originally built boost without -fno-exceptions in effect. Not good.
This is what Boost.Filesystem the documentation says:
All exceptions thrown by the Filesystem Library are implemented by calling boost::throw_exception(). Thus exact behavior may differ depending on BOOST_NO_EXCEPTIONS at the time the filesystem source files are compiled.
In my understanding, it doesn't really say it support BOOST_NO_EXCEPTIONS
And when I did a egrep -r BOOST_NO_EXCEPTIONS under the filesystem directory, I found nothing
And after I read the source code, it supports my guessing. There are many places using try { ... } catch(...) in the code. You can also tell from the error message you got. Here is an example:
filesystem_error(
const std::string & what_arg, const path& path1_arg,
const path& path2_arg, system::error_code ec)
: system::system_error(ec, what_arg)
{
try
{
m_imp_ptr.reset(new m_imp);
m_imp_ptr->m_path1 = path1_arg;
m_imp_ptr->m_path2 = path2_arg;
}
catch (...) { m_imp_ptr.reset(); }
}
And if you read this, the semantic of BOOST_NO_EXCEPTIONS is actually not disabling exceptions, but:
forwarding all exceptions to a user-defined non-template version of
boost::throw_exception.

C++ Does Not Catch Exception [duplicate]

I am using mysql c++ connector with this (a bit simplified) code.
try
{
statement->setString(1, word);
statement->executeUpdate();
}
catch( sql::SQLException& e )
{
// I don't get here
return sqlerrno_to_error_code( e.getErrorCode() );
}
catch( std::exception& e )
{
// I do get here and the cast works
sql::SQLException& sqle = (sql::SQLException&) e;
return sqlerrno_to_error_code( sqle.getErrorCode() );
}
The connector is supposed to throw the sql::SQLException which derives from std::exception and has some additional methods like getErrorCode().
The exception thrown is caught in the second catch block, but can be cast to (and used as)sql::SQLException successfully.
Even more weird is that a similar code in a different executable catches sql::SQLException as expected. The difference between them is that the first one is in a shared object (.so) that is loaded with dlopen().
RHEL 5.7 32 bit, gcc 4.1.2
See the note for dynamic_cast, throw, typeid don't work with shared libraries on the GCC Frequently Asked Questions page.
Because you are using dlopen(), you need to link your executable with the -E flag (or pass-Wl,-E to g++ if g++ is invoking the linker) and pass the RTLD_GLOBAL flag to dlopen().

weird - mysql's sql::SQLException is not caught by its type, but is caught as std::exception and cast back successfully

I am using mysql c++ connector with this (a bit simplified) code.
try
{
statement->setString(1, word);
statement->executeUpdate();
}
catch( sql::SQLException& e )
{
// I don't get here
return sqlerrno_to_error_code( e.getErrorCode() );
}
catch( std::exception& e )
{
// I do get here and the cast works
sql::SQLException& sqle = (sql::SQLException&) e;
return sqlerrno_to_error_code( sqle.getErrorCode() );
}
The connector is supposed to throw the sql::SQLException which derives from std::exception and has some additional methods like getErrorCode().
The exception thrown is caught in the second catch block, but can be cast to (and used as)sql::SQLException successfully.
Even more weird is that a similar code in a different executable catches sql::SQLException as expected. The difference between them is that the first one is in a shared object (.so) that is loaded with dlopen().
RHEL 5.7 32 bit, gcc 4.1.2
See the note for dynamic_cast, throw, typeid don't work with shared libraries on the GCC Frequently Asked Questions page.
Because you are using dlopen(), you need to link your executable with the -E flag (or pass-Wl,-E to g++ if g++ is invoking the linker) and pass the RTLD_GLOBAL flag to dlopen().

Why are my C++ exceptions not being caught?

I have some C++ code that uses a very standard exception pattern:
try {
// some code that throws a std::exception
}
catch (std::exception &e) {
// handle the exception
}
The problem is that the exceptions are not being caught and I cannot figure out why.
The code compiles to a static library in OS X (via Xcode). The library is linked into a Cocoa application, with a call to the function in question happening via an Objective-C++ thunk. I suspect that the interplay between Objective-C and C++ is the culprit but all my attempts to pin this down have failed.
I have not been able to create a simple example that reproduces this behavior in a simple example. When I take the relevant code out of the context of my big program everything works.
Can anyone suggest why my exceptions are not being caught?
C++ allows you a variety of options for catching: value, reference or pointer.
Note that this code only catches std::exceptions passed by reference or value:
try {
// some code that throws a std::exception
}
catch (std::exception &e) {
// handle the exception
}
It's likely that the exception is being passed by pointer:
catch (std::exception* e)
Check the code that is throwing the exception, and see how it's doing it.
As Mark points out, if you catch by value instead of by reference you risk slicing your object.
Try a catch(...) {} block, see if an exception is really thrown.
I suspect that the interplay between Objective-C and C++ is the culprit but all my attempts to pin this down have failed.
You're probably right, although it's hard to track down.
First, GCC explicitly does not allow you to throw exceptions in Objective C++ and catch them in C++ ("when used from Objective-C++, the Objective-C exception model does not interoperate with C++ exceptions at this time. This means you cannot #throw an exception from Objective-C and catch it in C++, or vice versa (i.e., throw ... #catch).")
However, I think you're describing a case where Objective C++ calls C++ code, the C++ code throws and you're hoping for C++ code to catch the exception. Unfortunately I'm having difficulty finding documentation for this specific case. There is some hope because, "It is believed to be safe to throw a C++ exception from one file through another file compiled for the Java exception model, or vice versa, but there may be bugs in this area." If they can do it for Java, there is a chance they can do it for Objective C++.
At the very least, you'll need to specify -fexceptions at compile time ("you may need to enable this option when compiling C code that needs to interoperate properly with exception handlers written in C++"). Again, that doesn't specifically mention Objective C++ but it may apply.
One little known gotcha with exceptions relates to the access of the base class.
If you are actually throwing a class that derives privately from std::exception then the std::exception handler will not be chosen.
For example:
#include <iostream>
class A { };
class B : private A { } ;
int main ()
{
try
{
throw B ();
}
catch (A & )
{
std::cout << "Caught an 'A'" << std::endl;
}
catch (B & )
{
std::cout << "Caught an 'B'" << std::endl;
}
}
Usually, such an order of handlers would result in the 'B' handler never being selected, but in this case 'B' dervies from 'A' privately and so the catch handler for type 'A' is not considered.
I can offer two theories:
the exception gets caught before it comes your catch clause; any function on the stack might be the culprit. As Michael proposes, try catching everything.
exception unwinding fails to locate your handler. To analyze this in more detail, you would have to step through the exception unwinding code, which is very hairy. See whether compiling the Objective-C code with -fobjc-exceptions helps.
This might be a long shot, but in Visual Studio's compiler settings there is an option to switch off exceptions entirely. Perhaps there's something similar in GCC / XCode.
C++ exceptions can be just about anything, quite frequently a char*. As suggested before add catch (...) to at least get it to break and see what's going on.
Thanks for the input from everyone. Those are good suggestions for anyone who runs into a similar problem. It's working now, but I'm not 100% sure which of various changes I made caused things to become sane again. Once again, the approach of simplifying down to something that works and building back up from there paid off.
One thing that wasn't mentioned in the responses, and which I think was part of my confusion, is to make sure that the handler makes it obvious that it actually caught the exception. I think that in some of my formulations of the handler it was masking that fact and passing the exception on to a higher level handler.

Can't catch exception!

I'm using swig to wrap a class from a C++ library with python. It works overall, but there is an exception that is thrown from within the library and I can't seem to catch it in the swig interface, so it just crashes the python application!
The class PyMonitor.cc describes the swig interface to the desired class, Monitor.
Monitor's constructor throws an exception if it fails to connect. I'd like to handle this exception in PyMonitor, e.g.:
PyMonitor.cc:
#include "Monitor.h"
// ...
bool PyMonitor::connect() {
try {
_monitor = new Monitor(_host, _calibration);
} catch (...) {
printf("oops!\n");
}
}
// ...
However, the connect() method never catches the exception, I just get a "terminate called after throwing ..." error, and the program aborts.
I don't know too much about swig, but it seems to me that this is all fine C++ and the exception should propagate to the connect() method before killing the program.
Any thoughts?
You have to forward the exceptions to Python if you want to parse them there.
See the SWIG Documentation.
In order to forward exceptions, you only have to add some code in the SWIG interface (.i) file. Basically, this can be anywhere in the .i file.
All types of exceptions should be specified here, and SWIG only catches the listed exception types (in this case std::runtime_error, std::invalid_argument, std::out_of_range), all other exceptions are caught as unknown exceptions (and are thus forwarded correctly!).
// Handle standard exceptions.
// NOTE: needs to be before the %import!
%include "exception.i"
%exception
{
try
{
$action
}
catch (const std::runtime_error& e) {
SWIG_exception(SWIG_RuntimeError, e.what());
}
catch (const std::invalid_argument& e) {
SWIG_exception(SWIG_ValueError, e.what());
}
catch (const std::out_of_range& e) {
SWIG_exception(SWIG_IndexError, e.what());
}
catch (...) {
SWIG_exception(SWIG_RuntimeError, "unknown exception");
}
}
I'm not familiar with swig, or with using C++ and Python together, but if this is under a recent version of Microsoft Visual C++, then the Monitor class is probably throwing a C structured exception, rather than a C++ typed exception. C structured exceptions aren't caught by C++ exception handlers, even the catch(...) one.
If that's the case, you can use the __try/__except keywords (instead of try/catch), or use the _set_se_translator function to translate the C structured exception into a C++ typed exception.
(Older versions of MSVC++ treated C structured exceptions as C++ int types, and are caught by C++ handlers, if I remember correctly.)
If this isn't under Microsoft Visual C++, then I'm not sure how this could be happening.
EDIT: Since you say that this isn't MSVC, perhaps something else is catching the exception (and terminating the program) before your code gets it, or maybe there's something in your catch block that's throwing another exception? Without more detail to work with, those are the only cases I can think of that would cause those symptoms.
It's possible that a function called directly or indirectly by the Monitor constructor is violating its exception specification and doesn't allow std::bad_exception to be thrown. If you haven't replaced the standard function for trapping this, then it would explain the behaviour that you are seeing.
To test this hypothesis you could try defining your own handler:
void my_unexpected()
{
std::cerr << "Bad things have happened!\n";
std::terminate();
}
bool PyMonitor::connect() {
std::set_unexpected( my_unexpected );
try {
_monitor = new Monitor(_host, _calibration);
} catch (...) {
printf("oops!\n");
}
}
If you get the "Bad things have happened!" error message then you have confirmed that this is the case, but unfortunately there may not be a lot that you can do. If you're 'lucky', you may be able to throw an exception from my_unexpected that is allowed by the exception specification of the function that is currently failing, but in any case your unexpected handler is not allowed to terminate normally. It must throw or otherwise terminate.
To fix this you really need to get into the called code and either correct it so that the exception specification is not violated, either by fixing the specification itself or by fixing the code so that it doesn't throw the exception that isn't expected.
Another possibility is that an exception is being thrown during stack unwinding caused by the original exception being thrown. This also would cause termination of the process. In this case, although you can replace the standard terminate function, you have no option but to abort the program. A terminate handler isn't allowed to throw or return, it must terminate the program.