Thread overview | |||||||
---|---|---|---|---|---|---|---|
|
November 30, 2016 how to catch D Throwables (or exceptions) from C++? | ||||
---|---|---|---|---|
| ||||
Attachments:
| 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? } } ``` |
December 01, 2016 Re: how to catch D Throwables (or exceptions) from C++? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timothee Cour | 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 ).
|
December 01, 2016 Re: how to catch D Throwables (or exceptions) from C++? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timothee Cour | 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; } // ... } ``` |
December 02, 2016 Re: how to catch D Throwables (or exceptions) from C++? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timothee Cour | 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 |
December 02, 2016 Re: how to catch D Throwables (or exceptions) from C++? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | 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.
|
Copyright © 1999-2021 by the D Language Foundation