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().
Related
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â˘.
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.
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().
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.
I have a test program called ftest. It loads .so files that contain tests and runs the tests that it finds in there. One of these tests loads and runs a .so that contains a Postgres database driver for our O/RM.
When the Postgres driver throws an exception which is defined in that .so file (or one that it links to, but ftest does not link to) and is caught by the test framework the exception destructor triggers a segfault.
This segfault happens whenever the compiled exception is in a .so that has been dynamically loaded (using dload).
This sort of thing works fine in Windows which has the same architecture. We don't really want to restrict ourselves to only use exceptions that are from the core libraries -- add-ins should be free to create their own exception classes and have them handled normally.
The exceptions are sub-classes of std::exception. Sometimes the exceptions may be defined in libraries (such as libpqxx) which means that exceptions are sometimes out of our control too.
Exceptions are thrown using something like:
throw exception_class( exception_arguments );
And are caught using:
catch ( std::exception &e ) {
// handler code
}
Is there some special compiler option needed to get this working? Do we need to switch to throw exceptions via throw new exception_class( args ) (we don't really want to do this)?
Assuming your using gcc -
Append -Wl,-E when you build the executable calling dlload(). This exports all type info symbols from the executable, which should allow the RTTI (when catching the exception) to work properly.
VC++ uses string compares to match typeinfo, results in slower dynamic_cast<> etc but smaller binaries. g++ uses pointer compares.
I encountered the same problem when attempting to use pure virtual interfaces classes implemented in a run-time loaded .so.
There are a few articles relating to the subject floating around on the net as well.
hope that helps,
Hayman.