digitalmars.D - C++/D interface: exceptions
- Andrei Alexandrescu (14/14) Sep 11 2014 Hello,
- David Nadlinger (13/16) Sep 11 2014 Just a quick comment on this: 2) is very simple to implement for
- David Nadlinger (4/5) Sep 11 2014 Aaand of course I missed the fact that your list in fact started
- deadalnix (5/11) Sep 11 2014 Yes, that is pretty why I limited myself to the "unwind properly
- Jacob Carlborg (7/10) Sep 11 2014 On 64bit Objective-C can catch C++ exceptions. But I don't think you can...
- Sean Kelly (16/27) Sep 12 2014 I think the trick is setting up the stack frame in such a way
- Marco Leise (6/22) Sep 12 2014 What exception object?
- H. S. Teoh via Digitalmars-d (11/34) Sep 12 2014 [...]
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (14/51) Sep 12 2014 How about
- Marco Leise (31/46) Sep 12 2014 No, let's just stick to 1) please :p
- Iain Buclaw via Digitalmars-d (11/46) Sep 12 2014 Digitalmars-d wrote:
- Sean Kelly (8/13) Sep 12 2014 I'm hoping it's simply a matter of sticking the right data in a
- David Nadlinger (6/13) Sep 12 2014 I suggest familiarizing yourself with how libunwind works. Look
- deadalnix (15/27) Sep 12 2014 This is really WAY harder that it seems.
- Sean Kelly (4/24) Sep 12 2014 Shouldn't matter. It's just a callback taking a different
- deadalnix (4/15) Sep 12 2014 Yes, but still require the D runtime to interface with the C++
- Jacob Carlborg (5/13) Sep 11 2014 Is handling the exception any more of a headache compared to only using ...
- deadalnix (4/17) Sep 11 2014 This is what SDC does.
- Sean Kelly (9/12) Sep 11 2014 Allowing a C++ exception to propagate through D code is
- Iain Buclaw via Digitalmars-d (9/14) Sep 11 2014 thrown from C++ functions into D code that calls them.
- Jacob Carlborg (4/7) Sep 11 2014 And Objective-C.
- Jacob Carlborg (5/18) Sep 11 2014 1 and 2 would really be a help for the D/Objective-C integration as well...
- Marco Leise (12/35) Sep 12 2014 I would say aim for 1. I wouldn't expect any less or any more.
Hello, We are racking our brains to figure out what to do about exceptions thrown from C++ functions into D code that calls them. A few levels of Nirvana would go like this: 0. Undefined behavior - the only advantage to this is we're there already with no work :o). 1. C++ exceptions may be caught only by C++ code on the call stack; D code does the stack unwinding appropriately (dtors, scope statements) but can't catch stuff. 2. D code can catch exceptions from C++ (e.g. via a CppException wrapper class) and give some info on them, e.g. the what() string if any. Making any progress on this is likely to be hard work, so any idea that structures and simplifies the design space would be welcome. Andrei
Sep 11 2014
On Friday, 12 September 2014 at 00:34:52 UTC, Andrei Alexandrescu wrote:Making any progress on this is likely to be hard work, so any idea that structures and simplifies the design space would be welcome.Just a quick comment on this: 2) is very simple to implement for all the compilers that actually use libunwind Dwarf 2 EH on Linux, i.e. GDC and LDC (I think deadalnix already looked into this for SDC). 3) is also doable, but of course significantly more annoying because you need to deal with the internals of the exception ABI of your C++ compiler. Accessing the exception object is relatively trivial, ABI and mangling support is slowly coming anyway, but OTOH handling the exception lifetime correctly could become somewhat of a headache. David
Sep 11 2014
On Friday, 12 September 2014 at 00:44:10 UTC, David Nadlinger wrote:2) […] 3)Aaand of course I missed the fact that your list in fact started at 0.
Sep 11 2014
On Friday, 12 September 2014 at 00:44:10 UTC, David Nadlinger wrote:3) is also doable, but of course significantly more annoying because you need to deal with the internals of the exception ABI of your C++ compiler. Accessing the exception object is relatively trivial, ABI and mangling support is slowly coming anyway, but OTOH handling the exception lifetime correctly could become somewhat of a headache.Yes, that is pretty why I limited myself to the "unwind properly but do not catch" option. This one would require to mess with the innards of various C++ runtime.
Sep 11 2014
On 12/09/14 05:25, deadalnix wrote:Yes, that is pretty why I limited myself to the "unwind properly but do not catch" option. This one would require to mess with the innards of various C++ runtime.On 64bit Objective-C can catch C++ exceptions. But I don't think you can do anything with the exception, i.e. it uses the following catch syntax: catch(...) {} Would that be easier? -- /Jacob Carlborg
Sep 11 2014
On Friday, 12 September 2014 at 06:56:29 UTC, Jacob Carlborg wrote:On 12/09/14 05:25, deadalnix wrote:I think the trick is setting up the stack frame in such a way that the C++ exception mechanism knows there's a catch block available at all. From there, we should be able to use the standard interface-to-class method to call virtual functions on the exception object, and hopefully the C++ runtime will handle cleanup for us. I imagine the easiest thing would be to find a platform where we already know how exceptions are thrown in C++ (DMC on Windows?) and figure out how to make it work in D. With inner functions and inline asm, I'm sure it's possible to make this work without compiler changes. I don't know whether the unwinding mechanism differs across compilers or even compiler versions for a particular platform though. This may all end up being a bit brittle.Yes, that is pretty why I limited myself to the "unwind properly but do not catch" option. This one would require to mess with the innards of various C++ runtime.On 64bit Objective-C can catch C++ exceptions. But I don't think you can do anything with the exception, i.e. it uses the following catch syntax: catch(...) {} Would that be easier?
Sep 12 2014
Am Fri, 12 Sep 2014 15:55:37 +0000 schrieb "Sean Kelly" <sean invisibleduck.org>:On Friday, 12 September 2014 at 06:56:29 UTC, Jacob Carlborg wrote:What exception object? throw "bad things happened"; -- MarcoOn 64bit Objective-C can catch C++ exceptions. But I don't think you can do anything with the exception, i.e. it uses the following catch syntax: catch(...) {} Would that be easier?I think the trick is setting up the stack frame in such a way that the C++ exception mechanism knows there's a catch block available at all. From there, we should be able to use the standard interface-to-class method to call virtual functions on the exception object, and hopefully the C++ runtime will handle cleanup for us.
Sep 12 2014
On Fri, Sep 12, 2014 at 06:19:54PM +0200, Marco Leise via Digitalmars-d wrote:Am Fri, 12 Sep 2014 15:55:37 +0000 schrieb "Sean Kelly" <sean invisibleduck.org>:[...] Yeah, in C++, you can throw *anything*. Including ridiculous things like `throw NULL;` or `throw 3.14159;`. There's no method for that! What we might end up doing, might be to wrap the C++ exception in a D exception that contains a pointer to the C++ type along with whatever type info we can glean from the C++ runtime. We probably won't be able to do much more than that. T -- Bomb technician: If I'm running, try to keep up.On Friday, 12 September 2014 at 06:56:29 UTC, Jacob Carlborg wrote:What exception object? throw "bad things happened";On 64bit Objective-C can catch C++ exceptions. But I don't think you can do anything with the exception, i.e. it uses the following catch syntax: catch(...) {} Would that be easier?I think the trick is setting up the stack frame in such a way that the C++ exception mechanism knows there's a catch block available at all. From there, we should be able to use the standard interface-to-class method to call virtual functions on the exception object, and hopefully the C++ runtime will handle cleanup for us.
Sep 12 2014
On Friday, 12 September 2014 at 16:37:43 UTC, H. S. Teoh via Digitalmars-d wrote:On Fri, Sep 12, 2014 at 06:19:54PM +0200, Marco Leise via Digitalmars-d wrote:How about try { my_cpp_func(); } catch(CppException!(const(char)*) e) { writeln(e.payload.fromStringz()); } ? Btw, how does implicit conversion work with `catch` in C++? I.e., if you throw a `char*`, will it be caught when you catch `const char*`? This can not be handled easily with such a template, as we would need to catch both `CppException!(const(char)*)` and `CppException!(char*)`.Am Fri, 12 Sep 2014 15:55:37 +0000 schrieb "Sean Kelly" <sean invisibleduck.org>:[...] Yeah, in C++, you can throw *anything*. Including ridiculous things like `throw NULL;` or `throw 3.14159;`. There's no method for that! What we might end up doing, might be to wrap the C++ exception in a D exception that contains a pointer to the C++ type along with whatever type info we can glean from the C++ runtime. We probably won't be able to do much more than that.On Friday, 12 September 2014 at 06:56:29 UTC, Jacob Carlborg wrote:What exception object? throw "bad things happened";On 64bit Objective-C can catch C++ exceptions. But I don't think you can do anything with the exception, i.e. it uses the following catch syntax: catch(...) {} Would that be easier?I think the trick is setting up the stack frame in such a way that the C++ exception mechanism knows there's a catch block available at all. From there, we should be able to use the standard interface-to-class method to call virtual functions on the exception object, and hopefully the C++ runtime will handle cleanup for us.
Sep 12 2014
Am Fri, 12 Sep 2014 17:57:39 +0000 schrieb "Marc Sch=C3=BCtz" <schuetzm gmx.net>:How about =20 try { my_cpp_func(); } catch(CppException!(const(char)*) e) { writeln(e.payload.fromStringz()); } =20 ? =20 Btw, how does implicit conversion work with `catch` in C++? I.e.,=20 if you throw a `char*`, will it be caught when you catch `const=20 char*`? This can not be handled easily with such a template, as=20 we would need to catch both `CppException!(const(char)*)` and=20 `CppException!(char*)`.No, let's just stick to 1) please :p Not only const(char) vs. char might be an issue because C's const doesn't match D's const exactly, but also char can be defined to be literally anything that can hold at least 8 bits. http://msdn.microsoft.com/en-us/library/0d294k5z.aspx http://www.cplusplus.com/reference/climits/ http://en.wikipedia.org/wiki/C_data_types I know this argument could be made about interfacing with C++ in general, but in case of throwing we do not replicate the structure of the C++ side in D as we would do with declarations of structs and classes, so the types would be thrown from C++ and end up "raw" in D. I think this requires at least a D compiler flag to name the C++ compiler eco system to emulate: e.g. MSVC++, ICC, DMC, GCC. With that information you could then catch(what_the_c_compiler_understands_by_a_const_unsigned_char_ptr) or catch(what_the_c_compiler_understands_by_a_const_signed_char_ptr) NOT possible: catch(what_the_c_compiler_understands_by_a_const_char_ptr), because that would have been remapped by the C++ compiler to either one of the former (I think). The raw void* exception data for C char* may be presented inside the catch block as byte*, ubyte*, ushort* or whatever is known to match the C compiler specified on the command line. (I hope my assumption about how C++ compilers mangle exception types is not too far off.) --=20 Marco
Sep 12 2014
On 12 Sep 2014 19:00, "via Digitalmars-d" <digitalmars-d puremagic.com> wrote:On Friday, 12 September 2014 at 16:37:43 UTC, H. S. Teoh viaDigitalmars-d wrote:wrote:On Fri, Sep 12, 2014 at 06:19:54PM +0200, Marco Leise via Digitalmars-dthink you can do anything with the exception, i.e. it uses > > the following catch syntax:Am Fri, 12 Sep 2014 15:55:37 +0000 schrieb "Sean Kelly" <sean invisibleduck.org>:On Friday, 12 September 2014 at 06:56:29 UTC, Jacob Carlborg > wrote:On 64bit Objective-C can catch C++ exceptions. But I don't > >that the C++ exception mechanism knows there's a catch > block available at all. From there, we should be able to > use the standard interface-to-class method to call virtual > functions on the exception object, and hopefully the C++ > runtime will handle cleanup for us.catch(...) {} Would that be easier? I think the trick is setting up the stack frame in such a > wayI'd vote no.How about try { my_cpp_func(); } catch(CppException!(const(char)*) e) { writeln(e.payload.fromStringz()); } ?What exception object? throw "bad things happened";[...] Yeah, in C++, you can throw *anything*. Including ridiculous things like `throw NULL;` or `throw 3.14159;`. There's no method for that! What we might end up doing, might be to wrap the C++ exception in a D exception that contains a pointer to the C++ type along with whatever type info we can glean from the C++ runtime. We probably won't be able to do much more than that.
Sep 12 2014
On Friday, 12 September 2014 at 17:57:41 UTC, Marc Schütz wrote:Btw, how does implicit conversion work with `catch` in C++? I.e., if you throw a `char*`, will it be caught when you catch `const char*`? This can not be handled easily with such a template, as we would need to catch both `CppException!(const(char)*)` and `CppException!(char*)`.I'm hoping it's simply a matter of sticking the right data in a lookup table and letting the C++ runtime figure out what the proper match is for us. D currently has a custom mechanism for throwing on non-Windows platforms, but it may be worth switching to the established C++ approach, provided we can do so without losing anything (and this is a big "if" given how we implicitly chain exceptions).
Sep 12 2014
On Friday, 12 September 2014 at 22:50:50 UTC, Sean Kelly wrote:I'm hoping it's simply a matter of sticking the right data in a lookup table and letting the C++ runtime figure out what the proper match is for us.I suggest familiarizing yourself with how libunwind works. Look up personality routines, or even just peruse GCC's libstdc++-v3/libsupc++/eh_personality.cc or Clang's libcxxabi/src/cxa_{exception, personality}.cpp.D currently has a custom mechanism for throwing on non-Windows platforms, but it may be worth switching to the established C++ approach, provided we can do so without losing anything (and this is a big "if" given how we implicitly chain exceptions).s/D/DMD/. And yes, LDC does implement exception chaining.
Sep 12 2014
On Friday, 12 September 2014 at 17:57:41 UTC, Marc Schütz wrote:How about try { my_cpp_func(); } catch(CppException!(const(char)*) e) { writeln(e.payload.fromStringz()); } ? Btw, how does implicit conversion work with `catch` in C++? I.e., if you throw a `char*`, will it be caught when you catch `const char*`? This can not be handled easily with such a template, as we would need to catch both `CppException!(const(char)*)` and `CppException!(char*)`.This is really WAY harder that it seems. First, you got to understand C++'s RTTI so you can generate the correct code to match catch blocks. That mean the D compiler must be able to generate the RTTI symbols for them to link. Then you got to implement the runtime part of it, considering there is absolutely NO standardization at all, it is 100% dependent on implementations details of the C++ standard lib you are using. You got to retrieve the exception from an opaque pointer on a structure that is compiler/stdlib dependent and make sense of it. Then you got to understand the C++ RTTI information do the proper matching of C++ exceptions with catch blocks's type. Finally, you have to interface with the C++ runtime to do the proper call in order to make the C++ runtime aware of what D's doing. This part is more standardized, so that should be easier.
Sep 12 2014
On Friday, 12 September 2014 at 16:11:28 UTC, Marco Leise wrote:Am Fri, 12 Sep 2014 15:55:37 +0000 schrieb "Sean Kelly" <sean invisibleduck.org>:Shouldn't matter. It's just a callback taking a different parameter type. Though I think it would be a fair limitation to say that D will only catch objects.On Friday, 12 September 2014 at 06:56:29 UTC, Jacob Carlborg wrote:What exception object? throw "bad things happened";On 64bit Objective-C can catch C++ exceptions. But I don't think you can do anything with the exception, i.e. it uses the following catch syntax: catch(...) {} Would that be easier?I think the trick is setting up the stack frame in such a way that the C++ exception mechanism knows there's a catch block available at all. From there, we should be able to use the standard interface-to-class method to call virtual functions on the exception object, and hopefully the C++ runtime will handle cleanup for us.
Sep 12 2014
On Friday, 12 September 2014 at 06:56:29 UTC, Jacob Carlborg wrote:On 12/09/14 05:25, deadalnix wrote:Yes, but still require the D runtime to interface with the C++ runtime, in order to restore the proper context.Yes, that is pretty why I limited myself to the "unwind properly but do not catch" option. This one would require to mess with the innards of various C++ runtime.On 64bit Objective-C can catch C++ exceptions. But I don't think you can do anything with the exception, i.e. it uses the following catch syntax: catch(...) {} Would that be easier?
Sep 12 2014
On 12/09/14 02:44, David Nadlinger wrote:Just a quick comment on this: 2) is very simple to implement for all the compilers that actually use libunwind Dwarf 2 EH on Linux, i.e. GDC and LDC (I think deadalnix already looked into this for SDC).It would be nice if DMD could do the same for D exceptions.3) is also doable, but of course significantly more annoying because you need to deal with the internals of the exception ABI of your C++ compiler. Accessing the exception object is relatively trivial, ABI and mangling support is slowly coming anyway, but OTOH handling the exception lifetime correctly could become somewhat of a headache.Is handling the exception any more of a headache compared to only using C++? -- /Jacob Carlborg
Sep 11 2014
On Friday, 12 September 2014 at 00:34:52 UTC, Andrei Alexandrescu wrote:Hello, We are racking our brains to figure out what to do about exceptions thrown from C++ functions into D code that calls them. A few levels of Nirvana would go like this: 0. Undefined behavior - the only advantage to this is we're there already with no work :o). 1. C++ exceptions may be caught only by C++ code on the call stack; D code does the stack unwinding appropriately (dtors, scope statements) but can't catch stuff.This is what SDC does.2. D code can catch exceptions from C++ (e.g. via a CppException wrapper class) and give some info on them, e.g. the what() string if any.This would require that druntime to be dependent on C++ runtime.
Sep 11 2014
On Friday, 12 September 2014 at 00:34:52 UTC, Andrei Alexandrescu wrote:We are racking our brains to figure out what to do about exceptions thrown from C++ functions into D code that calls them.Allowing a C++ exception to propagate through D code is definitely possible. Catching a C++ exception would require some knowledge of how that particular C++ runtime throws exceptions though. Like I can see registering an exception handler for a C++ exception maybe somewhat similar to SEH, then prettying it up with syntactic sugar. It seems tricky but doable, at least at a glance.
Sep 11 2014
On 12 Sep 2014 01:35, "Andrei Alexandrescu via Digitalmars-d" < digitalmars-d puremagic.com> wrote:Hello, We are racking our brains to figure out what to do about exceptionsthrown from C++ functions into D code that calls them.A few levels of Nirvana would go like this: 0. Undefined behavior - the only advantage to this is we're there alreadywith no work :o).1. C++ exceptions may be caught only by C++ code on the call stack; Dcode does the stack unwinding appropriately (dtors, scope statements) but can't catch stuff.Libunwind + handling foreign exceptions you can do this. And is beneficial in that it works with any other languages that use libunwind, such as gccgo. Iain
Sep 11 2014
On 12/09/14 07:01, Iain Buclaw via Digitalmars-d wrote:Libunwind + handling foreign exceptions you can do this. And is beneficial in that it works with any other languages that use libunwind, such as gccgo.And Objective-C. -- /Jacob Carlborg
Sep 11 2014
On 12/09/14 02:35, Andrei Alexandrescu wrote:Hello, We are racking our brains to figure out what to do about exceptions thrown from C++ functions into D code that calls them. A few levels of Nirvana would go like this: 0. Undefined behavior - the only advantage to this is we're there already with no work :o). 1. C++ exceptions may be caught only by C++ code on the call stack; D code does the stack unwinding appropriately (dtors, scope statements) but can't catch stuff. 2. D code can catch exceptions from C++ (e.g. via a CppException wrapper class) and give some info on them, e.g. the what() string if any. Making any progress on this is likely to be hard work, so any idea that structures and simplifies the design space would be welcome.1 and 2 would really be a help for the D/Objective-C integration as well since on 64bit is uses the same exception model as C++. -- /Jacob Carlborg
Sep 11 2014
Am Thu, 11 Sep 2014 17:35:25 -0700 schrieb Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:Hello, We are racking our brains to figure out what to do about exceptions thrown from C++ functions into D code that calls them. A few levels of Nirvana would go like this: 0. Undefined behavior - the only advantage to this is we're there already with no work :o). 1. C++ exceptions may be caught only by C++ code on the call stack; D code does the stack unwinding appropriately (dtors, scope statements) but can't catch stuff. 2. D code can catch exceptions from C++ (e.g. via a CppException wrapper class) and give some info on them, e.g. the what() string if any. Making any progress on this is likely to be hard work, so any idea that structures and simplifies the design space would be welcome. AndreiI would say aim for 1. I wouldn't expect any less or any more. Exception handling seems to have a platform wide standard on major OSs that D should follow (e.g. libunwind helps with this on GCC dominated systems), but dealing with C++'s "throw anything" seems overkill to me for the next milestone in C++ interop. After all there could be exceptions using multiple inheritance, templated objects or basic data types thrown from the C++ side. -- Marco
Sep 12 2014