Situation
I want to create a Python language binding for a C++ API using SWIG. Some of the API functions may throw exceptions. The C++ application has a hierarchy of self-defined exceptions, like this example:
std::exception
-> API::Exception
-> API::NetworkException
-> API::TimeoutException
-> API::UnreachableException
-> API::InvalidAddressException
The desired behavior is as follows:
All exception types should have a matching Python class as wrapper. These wrapper classes should be valid Python exceptions.
When an API call throws a C++ exception, it should be caught. The corresponding Python exception (i.e. the wrapper class of the caught C++ exception) should be thrown.
This should be a dynamic process: the Python exception type is decided at runtime, only based on the runtime type of the caught C++ exception. This way, there is no need to describe the complete exception hierarchy in the SWIG interface file.
Problems and questions
Wrapper classes are no Python exceptions.
While SWIG creates wrapper classes for all self-defined exceptions (like for any other class), these classes are not Python exceptions. The wrapper of the base exception (API::Exception in the example) extends Object instead of BaseException, the Python class of which all exceptions in Python should be derived.
Furthermore, it doesn't seem possible to let SWIG add a parent class manually. Note this is possible when using SWIG with Java through the usage of %typemap(javabase) (see SWIG documentation for details).
How can the Python C API throw a user-defined exception?
The most common way to throw a Python exception from the Python C API is by calling PyErr_SetString [reference]. This is also shown in the demo application below.
But this is only trivial with the standard (built-in) exceptions of Python, because references to them are stored in global variables [reference] in the Python C API.
I know there is a method PyErr_NewException [reference] to get references to self-defined exceptions, but I didn't got this working.
How can the Python C API evaluate the C++ type at runtime and then find the corresponding Python wrapper class by name?
I assume a Python class can be searched by name at runtime, through the reflection part of the Python C API. Is this the way to go? And how is it done in practice?
Demo application
To experiment with this problem, I created a tiny C++ API with a single function that calculates the factorial of a number. It has a minimal self-defined exception hierarchy, consisting of only one class TooBigException.
Note this exception acts as the base exception in the general problem and the application should work with any subclass of it. This means the solution may only use the dynamic (i.e. runtime) type of the caught exception to rethrow it in Python (see below).
The full source code of the demo application is as follows:
// File: numbers.h
namespace numbers {
int fact(int n);
}
// File: numbers.cpp
#include "TooBigException.h"
namespace numbers {
int fact(int n) {
if (n > 10) throw TooBigException("Value too big", n);
else if (n <= 1) return 1;
else return n*fact(n-1);
}
}
// File: TooBigException.h
namespace numbers {
class TooBigException: public std::exception {
public:
explicit TooBigException(const std::string & inMessage,
const int inValue);
virtual ~TooBigException() throw() {}
virtual const char* what() const throw();
const std::string & message() const;
const int value() const;
private:
std::string mMessage;
int mValue;
};
}
// File: TooBigException.cpp
#include "TooBigException.h"
namespace numbers {
TooBigException::TooBigException(const std::string & inMessage, const int inValue):
std::exception(),
mMessage(inMessage),
mValue(inValue)
{
}
const char* TooBigException::what() const throw(){
return mMessage.c_str();
}
const std::string & TooBigException::message() const {
return mMessage;
}
const int TooBigException::value() const {
return mValue;
}
}
To get the Python binding I use the following SWIG interface file:
// File: numbers.i
%module numbers
%include "stl.i"
%include "exception.i"
%{
#define SWIG_FILE_WITH_INIT
#include "TooBigException.h"
#include "numbers.h"
%}
%exception {
try {
$action
}
catch (const numbers::TooBigException & e) {
// This catches any self-defined exception in the exception hierarchy,
// because they all derive from this base class.
<TODO>
}
catch (const std::exception & e)
{
SWIG_exception(SWIG_RuntimeError, (std::string("C++ std::exception: ") + e.what()).c_str());
}
catch (...)
{
SWIG_exception(SWIG_UnknownError, "C++ anonymous exception");
}
}
%include "TooBigException.h"
%include "numbers.h"
So every call to the API is wrapped by a try-catch block. First exceptions of our base type are caught and handled. Then all other exceptions are caught and rethrown using the SWIG exception library.
Note any subclass of numbers::TooBigException is caught and the wrappers of their dynamic (i.e. runtime) type should be thrown, not the wrapper of their static (i.e. compile time) type, which is always TooBigException!
The project can be built easily by executing the following commands on a Linux machine:
$ swig -c++ -python numbers.i
$ g++ -fPIC -shared TooBigException.cpp numbers.cpp numbers_wrap.cxx \
-I/usr/include/python2.7 -o _numbers.so
Current implementation
My current implementation still (successfully) throws a fixed standard Python exception. The code <TODO> above is then replaced by:
PyErr_SetString(PyExc_Exception, (std::string("C++ self-defined exception ") + e.what()).c_str());
return NULL;
Which gives the following (expected) behavior in Python:
>>> import numbers
>>> fact(11)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: C++ self-defined exception Value too big
It looks like someone has answered your basic question over on the swig-user list...
%exception {
try {
$action
} catch (MyException &_e) {
SWIG_Python_Raise(SWIG_NewPointerObj(
(new MyException(static_cast<const MyException& >(_e))),
SWIGTYPE_p_MyException,SWIG_POINTER_OWN),
"MyException", SWIGTYPE_p_MyException);
SWIG_fail;
}
}
This does assume you have generated wrappers for your exception classes, I believe.
Example for your hierarchy
std::exception
-> API::Exception
-> API::NetworkException
-> API::TimeoutException
-> API::UnreachableException
-> API::InvalidAddressException
example.i:
%module example
%include "stl.i"
%include "exception.i"
%{
#define SWIG_FILE_WITH_INIT
#include "example.cpp"
%}
%{
#define CATCH_PE(Namespace,Exception) \
catch(const Namespace::Exception &e) \
{ \
SWIG_Python_Raise(SWIG_NewPointerObj(new Namespace::Exception(e), \
SWIGTYPE_p_##Namespace##__##Exception,SWIG_POINTER_OWN), \
#Exception, SWIGTYPE_p_##Namespace##__##Exception); \
SWIG_fail; \
} \
/**/
// should be in "derived first" order
#define FOR_EACH_EXCEPTION(ACTION) \
ACTION(API,UnreachableException) \
ACTION(API,TimeoutException) \
ACTION(API,InvalidAddressException) \
ACTION(API,NetworkException) \
ACTION(API,Exception) \
/**/
// In order to remove macros, need traits:
// http://swig.10945.n7.nabble.com/traits-based-access-to-swig-type-info-td12315.html
%}
%exception {
try {
$action
}
FOR_EACH_EXCEPTION(CATCH_PE)
catch (const std::exception & e)
{
SWIG_exception(SWIG_RuntimeError, (std::string("C++ std::exception: ") + e.what()).c_str());
}
catch (...)
{
SWIG_exception(SWIG_UnknownError, "C++ anonymous exception");
}
}
%include "example.cpp"
example.cpp:
#include <exception>
#include <stdexcept>
namespace API
{
struct Exception: std::exception
{
virtual const char* what() const throw()
{
return "It is API::Exception";
}
};
struct NetworkException: Exception
{
virtual const char* what() const throw()
{
return "It is API::NetworkException";
}
};
struct TimeoutException: NetworkException
{
virtual const char* what() const throw()
{
return "It is API::TimeoutException";
}
};
struct UnreachableException: NetworkException
{
virtual const char* what() const throw()
{
return "It is API::UnreachableException";
}
};
struct InvalidAddressException: Exception
{
virtual const char* what() const throw()
{
return "It is API::InvalidAddressException";
}
};
inline void select(int i)
{
switch(i)
{
case 0: throw Exception();
case 1: throw NetworkException();
case 2: throw TimeoutException();
case 3: throw UnreachableException();
case 4: throw InvalidAddressException();
default: throw std::runtime_error("It is std::runtime_error");
}
}
}
Build:
swig -c++ -python example.i &&
g++ -fPIC -shared -lpython2.7 example.cpp example_wrap.cxx -I/usr/include/python2.7 -o _example.so
test.py:
#!/usr/bin/env python2.7
from exceptions import BaseException
from example import *
def catch(i):
try:
select(i)
except UnreachableException as e:
print "Caught UnreachableException"
print e.what()
print e
except TimeoutException as e:
print "Caught TimeoutException"
print e.what()
print e
except InvalidAddressException as e:
print "Caught InvalidAddressException"
print e.what()
print e
except NetworkException as e:
print "Caught NetworkException"
print e.what()
print e
except Exception as e:
print "Caught Exception"
print e.what()
print e
except BaseException as e:
print "Caught BaseException"
print str(e)
print "_"*16
for i in xrange(6):
catch(i)
Output is:
Caught Exception
It is API::Exception
<example.Exception; proxy of <Swig Object of type 'API::Exception *' at 0x7f9f54a02120> >
________________
Caught NetworkException
It is API::NetworkException
<example.NetworkException; proxy of <Swig Object of type 'API::NetworkException *' at 0x7f9f54a02120> >
________________
Caught TimeoutException
It is API::TimeoutException
<example.TimeoutException; proxy of <Swig Object of type 'API::TimeoutException *' at 0x7f9f54a02120> >
________________
Caught UnreachableException
It is API::UnreachableException
<example.UnreachableException; proxy of <Swig Object of type 'API::UnreachableException *' at 0x7f9f54a02120> >
________________
Caught InvalidAddressException
It is API::InvalidAddressException
<example.InvalidAddressException; proxy of <Swig Object of type 'API::InvalidAddressException *' at 0x7f9f54a02120> >
________________
Caught BaseException
C++ std::exception: It is std::runtime_error
________________
Based on answer in maillist.
Related
In my iOS project, I use a C++ module. The C++ module throws exception for some cases and the Objective C++ wrapper fails to catch it. For instance
Here is my HelloWorld.h
#include <string>
using namespace std;
class HelloWorld{
public:
string helloWorld();
};
#endif
Implementation HelloWorld.cpp
#include "HelloWorld.h"
string HelloWorld::helloWorld(){
throw (std::runtime_error("runtime_error")); // Throwing exception to test
string s("Hello from CPP");
return s;
}
Objective C++ wrapper HelloWorldIOSWrapper.h
#import <Foundation/Foundation.h>
#interface HelloWorldIOSWrapper:NSObject
- (NSString*)getHello;
#end
#endif /* HelloWorldIOSWrapper_h */
Implementation HelloWorldIOSWrapper.mm
#import "HelloWorldIOSWrapper.h"
#include "HelloWorld.h"
#implementation HelloWorldIOSWrapper
- (NSString*)getHello{
try {
HelloWorld h;
NSString *text=[NSString stringWithUTF8String: h.helloWorld().c_str()];
return text;
} catch (const std::exception & e) {
NSLog(#"Error %s", e.what());
}
return nil;
}
#end
#import "HelloWorldIOSWrapper.h" is added to the Bridging-Header
And now, when I try to invoke getHello() from controller, app crashes leaving the below message in log
libc++abi: terminating with uncaught exception of type std::runtime_error: runtime_error
dyld4 config: DYLD_LIBRARY_PATH=/usr/lib/system/introspection DYLD_INSERT_LIBRARIES=/Developer/usr/lib/libBacktraceRecording.dylib:/Developer/usr/lib/libMainThreadChecker.dylib:/Developer/Library/PrivateFrameworks/DTDDISupport.framework/libViewDebuggerSupport.dylib
terminating with uncaught exception of type std::runtime_error: runtime_error
I expect that the exception must be caught in the wrapper, but, no idea why is it not caught leading to app crash. What do I miss?
C++ Interoperability
In 64-bit processes, Objective-C exceptions (NSException) and C++
exception are interoperable. Specifically, C++ destructors and
Objective-C #finally blocks are honored when the exception mechanism
unwinds an exception. In addition, default catch clauses—that is,
catch(...) and #catch(...)—can catch and rethrow any exception
On the other hand, an Objective-C catch clause taking a dynamically
typed exception object (#catch(id exception)) can catch any
Objective-C exception, but cannot catch any C++ exceptions. So, for
interoperability, use #catch(...) to catch every exception and #throw;
to rethrow caught exceptions. In 32-bit, #catch(...) has the same
effect as #catch(id exception).
#try {
}
#catch (...) {
}
I'm using LibJIT to JIT-compile a programming language. My compiler is written in C++, so I have a C++ program calling the LibJIT library, which is written in C.
In my C++ code I have some functions that throw exceptions, and sometimes these get triggered on the far side of a LibJIT-compiled function. That is, my C++ program uses LibJIT to compile a function, calls it, and the JIT-compiled function in turn calls a C++ function that throws an exception. But instead of the exception being propagated back through the JIT-compiled function to my handler, the runtime calls std::terminate.
Apparently the exception-handling mechanism needs each function in the call stack to implement some kind of exception support. When compiling C code, the -fexceptions flag tells the compiler (at least gcc) to include this support.
Is there a way to include this exception support in my LibJIT-generated functions?
I tried using the LibJIT instructions to set up a "catcher" block that rethrows all exceptions, but that didn't work; it looks like the LibJIT's exception-handling model is separate from the C++ model.
Obviously I don't really want to throw C++ exceptions into my language's code, and I'll have to figure out some other error-handling strategy. But I'm wondering if it's even possible to get it to work.
Here's a sample program that demonstrates the issue. I'm sorry it's this long but LibJIT is pretty low-level so you have to write a lot of code to get anything done. I'm compiling on Linux with clang 10.0.0.
#include <array>
#include <exception>
#include <iostream>
#include <string>
#include <jit/jit.h>
class ex : public std::exception {};
extern "C" int bad(int arg) {
std::cout << "Called with arg=" << arg << std::endl;
throw ex();
}
jit_function_t build_function(jit_context_t context) {
// The signature of the compiled function and "bad" are the same.
std::array<jit_type_t, 1> params{jit_type_int};
jit_type_t signature = jit_type_create_signature(jit_abi_cdecl, jit_type_int, params.data(), params.size(), 1);
jit_function_t function = jit_function_create(context, signature);
jit_value_t arg_value = jit_value_get_param(function, 0);
jit_value_t bad_value =
jit_value_create_nint_constant(function, jit_type_void_ptr, (reinterpret_cast<jit_nint>(bad)));
std::array<jit_value_t, 1> bad_args{arg_value};
jit_value_t result = jit_insn_call_indirect(function, bad_value, signature, bad_args.data(), bad_args.size(), 0);
jit_insn_return(function, result);
jit_function_compile(function);
return function;
}
int main(int argc, char* argv[]) {
// This exception will be caught:
try {
bad(7);
} catch (const ex&) {
std::cout << "Caught exception from direct call" << std::endl;
}
// Initialize libjit.
// We're single-threaded so not going to bother with jit_context_build_start/jit_context_build_end.
jit_init();
jit_context_t context = jit_context_create();
jit_function_t function = build_function(context);
// This one will not be caught, calls std::terminate instead:
try {
int (*closure)(int) = reinterpret_cast<int (*)(int)>(jit_function_to_closure(function));
closure(7);
} catch (const ex&) {
std::cout << "Caught exception from libjit call" << std::endl;
}
return 0;
}
Output:
Called with arg=7
Caught exception from direct call
Called with arg=7
terminate called after throwing an instance of 'ex'
what(): std::exception
Aborted
I export a function from d to c++ with extern(C++). The d code has a try catch statement on the highest level.Whenever the d code throws a exception the program aborts. I have c++ objects on the call stack and call the function in d. Then there is the d try catch statement and then the d exception throw.
The d code:
extern (C++) void ThrowEx() {
try {
throw new Exception("hello");
} catch (Exception ex) {
}
}
The c++ code:
extern "C" int rt_init();
void ThrowEx();
void func() {
rt_init();
ThrowEx();
}
When I change ThrowEx to not throw an exception everything works as expected. The d code gets executed and no error occurs.
When the program crashes the following output is generated:
dwarfeh(224) fatal error
uncaught exception
I have posted two other questions earlier this week, about exceptions and why my program does not handle exceptions. I have 'undressed' my program from unnecesarry code, and here it is:
#include <string>
#include <stdexcept>
#include <iostream>
class some_class
{
public:
some_class(const some_class &);
some_class(const char *);
std::string m_id;
};
some_class::some_class(const char *p_id) :
m_id(p_id)
{
}
some_class::some_class(const some_class &p_that) :
m_id(p_that.m_id)
{
}
extern some_class return_a_struct(const char *p_id);
int run()
{
some_class l = return_a_struct("john");
throw std::runtime_error("something bad happened");
return 0;
}
extern "C" int main(int, char **)
{
try
{
run();
}
catch(const std::exception &p)
{
std::cout << p.what() << std::endl;
}
return 0;
}
some_class return_a_struct(const char *p_id)
{
return some_class(p_id);
}
The output should be:
somethingbad happened
According to the exception (std::runtime_error) I throw.
In run(), I call a function that returns some_class. The object returned is then copy-constructed into the object I assign it to. So far, so good. But then I throw the exception, and the program never reaches the catch handler in function main. It crashes with the following message:
This application has requested the Runtime to terminate it in an unusual way
Please contact the application's support team for more information.
If I ommit the call to return_a_struct() this doesn't happen.
Question is: Is this a bug in gcc (part of MinGW latest release running on Windows 7), or am I doing something wrong. Any work arounds?
GCC-options:
gcc -fexceptions -g3 test_case.cpp -l libstdc++ -o test_case.exe
g++ test_case.cpp -o test_case.exe
I'm using boost test framework 1.47 and I'm having difficulties testing my exceptions
Here is my exception class
class VideoCaptureException : public std::exception
{
std::string m_Description;
public:
VideoCaptureException(const char* description)
{
m_Description = std::string(description);
}
VideoCaptureException(const std::string& description)
{
m_Description = description;
}
virtual ~VideoCaptureException() throw() {}
virtual const char* what() const throw()
{
return m_Description.c_str();
}
}
I'm trying to test code that simply throws this exception
BOOST_CHECK_THROW( source.StopCapture(), VideoCaptureException )
For some reason it doesn't work.
unknown location(0): fatal error in "testVideoCaptureSource": unknown type
testVideoCaptureSource.cpp(28): last checkpoint
What is it that I'm doing wrong?
After encountering this error myself, I have tracked it down to a silly, but easy-to-make mistake:
throw new VideoCaptureException( "uh-oh" );
will fail with that error message, while:
throw VideoCaptureException( "uh-oh" );
will succeed.
The new variant causes a pointer to an exception to be caught, rather than the exception itself. The boost library doesn't know what to do with this, so it just says "unknown type".
It would be nice if the library explained the situation properly, but hopefully anybody else hitting "fatal error: unknown type" will find this page and see how to fix it!