www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - how to catch D Throwables (or exceptions) from C++?

reply Timothee Cour via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
eg:

```
dlib.d:
extern(C) void dfun(){assert(0, "some_msg");}

clib.cpp:
extern "C" void dfun();
void fun(){
  try{
    dfun();
  }
  catch(...){
    // works but how do i get "some_msg" thrown from D?
  }
}
```
Nov 30 2016
next sibling parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Thursday, 1 December 2016 at 01:58:13 UTC, Timothee Cour wrote:
 eg:

 ```
 dlib.d:
 extern(C) void dfun(){assert(0, "some_msg");}

 clib.cpp:
 extern "C" void dfun();
 void fun(){
   try{
     dfun();
   }
   catch(...){
     // works but how do i get "some_msg" thrown from D?
   }
 }
 ```
portably not sure, but if you're using dwarf / libunwind you can probably use the API directly and get a pointer to the exception object and dereference a field of it's (i.e. p+ Throwable.msg.offsetof ).
Nov 30 2016
prev sibling next sibling parent =?UTF-8?B?UsOpbXkgTW91w6t6YQ==?= <remy.moueza gmail.com> writes:
On Thursday, 1 December 2016 at 01:58:13 UTC, Timothee Cour wrote:
 eg:

 ```
 dlib.d:
 extern(C) void dfun(){assert(0, "some_msg");}

 clib.cpp:
 extern "C" void dfun();
 void fun(){
   try{
     dfun();
   }
   catch(...){
     // works but how do i get "some_msg" thrown from D?
   }
 }
 ```
I had the a similar problem when writing bindings to the RtMidi library back in 2013. I opted for catching C++ exceptions in C++, wrap the functions in a C API; the C API returns a special type that contains a status, a result and an error message. On the D side, when a status is false, a D exception is raised, mirroring the one that was caught in C++. This strategy is described in dconf 2014: https://www.youtube.com/watch?v=1JZNvKhA3mA&t=20m45s It should be working the other way arround: catch a D exception in D, return a wrapped value: on the C++ side, if the wrapped value status is false, throw an exception Below is an sample of the code I wrote: In C++: ``` * Special return type. * - success is true when a call went right, * is false when an exception occured. * - errMsg can be used to throw a D exception. * - value is the value to be returned from a call. */ template <typename T> struct answer { int success; T value; const char * errMsg; }; * Predefined types of return for RtMidi. */ typedef answer<RtMidiIn *> answerRtMidiIn_p; typedef answer<RtMidiOut *> answerRtMidiOut_p; typedef answer<bool> answerBool; typedef answer<const char *> answerConstChar_p; typedef answer<double> answerDouble; answerRtMidiIn_p RtMidiIn_new ( int api, char * clientName, unsigned int queueSizeLimit) { RtMidiIn * ptr; try { const std::string name = std::string (clientName); ptr = new RtMidiIn ((RtMidi::Api) api, name, queueSizeLimit); answerRtMidiIn_p ans = {true, ptr, ""}; return ans; } catch (RtError & error) { answerRtMidiIn_p ans = {false, 0, error.getMessage ().c_str ()}; return ans; } } ``` in D: ``` /* Special return type. * - success is true when a call went right, * is false when an exception occured. * - errMsg can be used to throw a D exception. * - value is the value to be returned from a call. */ struct answer (T) { int success; T value; const (char) * errMsg; } extern (C) { // ... answer!(void *) RtMidiIn_new ( int api, immutable(char) * clientName, uint queueSizeLimit); // ... } class RtMidiIn { // Pointer to the C++ class, package visibility. protected void * ptr; public: this ( int api = UNSPECIFIED, string clientName = "RtMidi Input Client", uint queueSizeLimit = 100) { answer!(void *) ans = RtMidiIn_new (api, clientName.toStringz, queueSizeLimit); if (! ans.success) throw new RtError (ans.errMsg.to!string); this.ptr = ans.value; } // ... } ```
Dec 01 2016
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2016-12-01 02:58, Timothee Cour via Digitalmars-d-learn wrote:
 eg:

 ```
 dlib.d:
 extern(C) void dfun(){assert(0, "some_msg");}

 clib.cpp:
 extern "C" void dfun();
 void fun(){
   try{
     dfun();
   }
   catch(...){
     // works but how do i get "some_msg" thrown from D?
   }
 }
 ```
At least for a C++ exception it's possible to get the current exception with __cxxabiv1::__cxa_current_primary_exception(). I verified and it works for C++ exceptions. I would think that the following works for D exceptions, but I cannot even catch the D exception in C++. Maybe it's not working properly on macOS. // c++ void foo(); const char* getExceptionMessage(void*); void bar() { try { foo(); } catch(...) { void* e = __cxxabiv1::__cxa_current_primary_exception(); if (e) { const char* msg = getExceptionMessage(e); if (msg) printf("%s\n", msg); else printf("no message\n"); } else { printf("no exception\n"); } } } // d extern(C++) void foo() { throw new Exception("foo"); } extern(C++) immutable(char)* getExceptionMessage(void* e) { if (e) { auto t = cast(Throwable) e; return t.msg.ptr; } return null; } I'm compiling the C++ code with clang++ and I need to link with libc++abi. -- /Jacob Carlborg
Dec 02 2016
parent Elie Morisse <syniurge gmail.com> writes:
On Friday, 2 December 2016 at 08:13:51 UTC, Jacob Carlborg wrote:
 On 2016-12-01 02:58, Timothee Cour via Digitalmars-d-learn 
 wrote:
 eg:

 ```
 dlib.d:
 extern(C) void dfun(){assert(0, "some_msg");}

 clib.cpp:
 extern "C" void dfun();
 void fun(){
   try{
     dfun();
   }
   catch(...){
     // works but how do i get "some_msg" thrown from D?
   }
 }
 ```
At least for a C++ exception it's possible to get the current exception with __cxxabiv1::__cxa_current_primary_exception(). I verified and it works for C++ exceptions. I would think that the following works for D exceptions, but I cannot even catch the D exception in C++. Maybe it's not working properly on macOS. // c++ void foo(); const char* getExceptionMessage(void*); void bar() { try { foo(); } catch(...) { void* e = __cxxabiv1::__cxa_current_primary_exception(); if (e) { const char* msg = getExceptionMessage(e); if (msg) printf("%s\n", msg); else printf("no message\n"); } else { printf("no exception\n"); } } } // d extern(C++) void foo() { throw new Exception("foo"); } extern(C++) immutable(char)* getExceptionMessage(void* e) { if (e) { auto t = cast(Throwable) e; return t.msg.ptr; } return null; } I'm compiling the C++ code with clang++ and I need to link with libc++abi.
Exceptions thrown from D set a different exception class in the header, and the C++ personality routine (i.e the function that gets called for each catch block) only handles exceptions which displays the C++ exception class, so let D exceptions slip through. To catch exceptions thrown by D code in C++ I think this would have to be done by throwing a C++ exception (eventually wrapping a D class), but this is yet to be implemented.
Dec 02 2016