![]() |
propagation of exceptions over module/language boundaries
Hi
I hope you'll see this cross-post (c/c++) as appropriate. I also admit immediately that the question *may* turn out to be compiler-/os-specific, in which case I apologize. But I wonder if there's an underlying truth. We are writing a (cross-platform) 'framework' application (in C++, as it happens) that allows users to author 'plugins' (as shared library modules). Since the lifetime of plugins is expected to be long, and the framework may be updated using a later compiler version, we have chosen to offer a C interface to those plugins to avoid issues with changing ABIs (as far as I understand it). Plugins are expected to export a single undecorated function, Event(EventData* data), and may call back to the framework through a number of undecorated functions exported from an API module, 'api', also authored in C++. Commonly, then, the framework will load a plugin, call its Event() function, and that function will call one of these callback functions on the API. At this point I have to own up and say I don't fully understand linking or calling conventions, so when I say we "offer a C interface" what I mean is that api is compiled to export its functions undecorated (sort of with the use of extern "C", though actually there's some other stuff going on that I'd rather not get into so I'm hoping that's a sufficiently good approximation - api is a C++ module but its exports are undecorated). Also, plugins export their Event() function as extern "C". Motivation: It would be convenient if the api could throw an exception that the framework would recognise. It would pass painlessly up through any user code without the user having to do anything, and the framework could find out what happened and generate a useful error report. The alternative is that we enforce that all API functions do not throw and instead return error codes - the onus is then on the plugin author to catch the error and return it to the framework (or, if they are authoring in C++, they could throw an exception themselves, but i'm not sure if that's not the same question again). Now, 'api' is authored in C++, and so is the framework, but user plugins may be authored in C or C++ (or, in fact, any other language that can meet the requirements of the interface). So my initial thinking was that we couldn't use exceptions, much as they're great imho. However, in my current dev copy, i'm finding exceptions work fine. My worry is that in my current dev copy i'm compiling the framework, the api, *and* the test plugin, all with the same compiler (cl v14, win xp), which may be hiding problems that would arise once we go more mix and match. In addition, I'm writing this particular plugin in C++, so everything is C++ save the actual exported function declarations. So... the question is, should we avoid throwing exceptions across these module boundaries, or is it ok to do so? I could actually test this to some extent by installing some other compilers, but I'm thinking that that's not going to be a thorough test anyway, so I'd rather reach some understanding. For instance... * framework loads "plugin" * framework calls plugin::Event() * plugin calls api::Sum() * error condition occurs in Sum() * Sum() throws exception of type X or, to put that another way, the call stack looks like: framework::main() (C++) --> plugin::Event() (C) --> api::Sum() (C++) throw X; Now, if X is, say, an int, will it pass safely back up through "plugin" in all cases, even if plugin is compiled with an (old, perhaps) C compiler that is strictly not aware of exceptions? Is this a compiler-/os-specific question? what if X is a C struct defined in api.h? From what I have learned about exceptions and how they are implemented, I don't immediately see a problem with passing one 'through' exception-unaware code in this way. There will be no handlers on the stack associated with the C-code, but I'm supposing that this means that control will just pass (effectively) directly from the "throw" statement in api to the "catch" block in framework. But I'm worried that the way the stack is arranged to accomodate the two cross-module-boundary calls will somehow interfere with this mechanism. I am also worried that the type of the object will not be recognised when it reaches framework - I am fine with sticking with const char* as an exception type if that's the only reliable option, but a struct with a code, a message, and some source information would be preferable, of course. Phew. I hope that's clear. Thanks in advance for any comments. Ben Mitch |
Re: propagation of exceptions over module/language boundaries
ben mitch wrote:
> Hi > > I hope you'll see this cross-post (c/c++) as appropriate. I also admit > immediately that the question *may* turn out to be > compiler-/os-specific, in which case I apologize. But I wonder if > there's an underlying truth. > > We are writing a (cross-platform) 'framework' application (in C++, as it > happens) that allows users to author 'plugins' (as shared library > modules). Since the lifetime of plugins is expected to be long, and the > framework may be updated using a later compiler version, we have chosen > to offer a C interface to those plugins to avoid issues with changing > ABIs (as far as I understand it). Plugins are expected to export a > single undecorated function, Event(EventData* data), and may call back > to the framework through a number of undecorated functions exported from > an API module, 'api', also authored in C++. Commonly, then, the > framework will load a plugin, call its Event() function, and that > function will call one of these callback functions on the API. > > At this point I have to own up and say I don't fully understand linking > or calling conventions, so when I say we "offer a C interface" what I > mean is that api is compiled to export its functions undecorated (sort > of with the use of extern "C", though actually there's some other stuff > going on that I'd rather not get into so I'm hoping that's a > sufficiently good approximation - api is a C++ module but its exports > are undecorated). Also, plugins export their Event() function as extern > "C". > > Motivation: It would be convenient if the api could throw an exception > that the framework would recognise. It would pass painlessly up through > any user code without the user having to do anything, and the framework > could find out what happened and generate a useful error report. The > alternative is that we enforce that all API functions do not throw and > instead return error codes - the onus is then on the plugin author to > catch the error and return it to the framework (or, if they are > authoring in C++, they could throw an exception themselves, but i'm not > sure if that's not the same question again). > > Now, 'api' is authored in C++, and so is the framework, but user plugins > may be authored in C or C++ (or, in fact, any other language that can > meet the requirements of the interface). So my initial thinking was that > we couldn't use exceptions, much as they're great imho. However, in my > current dev copy, i'm finding exceptions work fine. My worry is that in > my current dev copy i'm compiling the framework, the api, *and* the test > plugin, all with the same compiler (cl v14, win xp), which may be hiding > problems that would arise once we go more mix and match. In addition, > I'm writing this particular plugin in C++, so everything is C++ save the > actual exported function declarations. > > So... the question is, should we avoid throwing exceptions across these > module boundaries, or is it ok to do so? I could actually test this to > some extent by installing some other compilers, but I'm thinking that > that's not going to be a thorough test anyway, so I'd rather reach some > understanding. For instance... > > * framework loads "plugin" > * framework calls plugin::Event() > * plugin calls api::Sum() > * error condition occurs in Sum() > * Sum() throws exception of type X > > or, to put that another way, the call stack looks like: > > framework::main() (C++) > --> plugin::Event() (C) > --> api::Sum() (C++) > throw X; > > Now, if X is, say, an int, will it pass safely back up through "plugin" > in all cases, even if plugin is compiled with an (old, perhaps) C > compiler that is strictly not aware of exceptions? Is this a > compiler-/os-specific question? what if X is a C struct defined in api.h? > > From what I have learned about exceptions and how they are implemented, > I don't immediately see a problem with passing one 'through' > exception-unaware code in this way. There will be no handlers on the > stack associated with the C-code, but I'm supposing that this means that > control will just pass (effectively) directly from the "throw" statement > in api to the "catch" block in framework. But I'm worried that the way > the stack is arranged to accomodate the two cross-module-boundary calls > will somehow interfere with this mechanism. I am also worried that the > type of the object will not be recognised when it reaches framework - I > am fine with sticking with const char* as an exception type if that's > the only reliable option, but a struct with a code, a message, and some > source information would be preferable, of course. > > Phew. I hope that's clear. > > Thanks in advance for any comments. > Ben Mitch I have studied this problem extensively in the context of dynamically generated C code. I will not bore you with the details, but solving the problem you see is not easy at all. 1) Using Microsoft compiler will work if all the "clients" use also the same compiler AND the same version. With different versions of the compiler things could change and you would experience mysterious crashes. 2) Avoid gcc if possible. There is no documentation almost about the exception framework and the documentation available is highly misleading. In any case if you have to use gcc you will want to ALWAYS use gcc ("clients" and API server) and specially, the SAME version of gcc. Do remember that gcc changes its behaviour from version to version without any announcement, since all this is not really documented. -- jacob navia jacob at jacob point remcomp point fr logiciels/informatique http://www.cs.virginia.edu/~lcc-win32 |
Re: propagation of exceptions over module/language boundaries
ben mitch <news@benmitch.net> writes:
> I hope you'll see this cross-post (c/c++) as appropriate. I also admit > immediately that the question *may* turn out to be > compiler-/os-specific, in which case I apologize. But I wonder if > there's an underlying truth. > [SNIP] > > Motivation: It would be convenient if the api could throw an exception > that the framework would recognise. It would pass painlessly up > through any user code without the user having to do anything, and the > framework could find out what happened and generate a useful error > report. The alternative is that we enforce that all API functions do > not throw and instead return error codes - the onus is then on the > plugin author to catch the error and return it to the framework (or, > if they are authoring in C++, they could throw an exception > themselves, but i'm not sure if that's not the same question again). [SNIP] I think this is really a question for comp.lang.c++, not for comp.lang.c (even though it does involve both languages. The C+ standard defines features for interfacing to C, but C doesn't define any features for interfacing to C++. Furthermore, C says nothing about C++-style exceptions. I suspect that exception propagation across C code is system-specific, but the folks in comp.lang.c++ can probably give you more information on that point. -- Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst> Nokia "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister" |
Re: propagation of exceptions over module/language boundaries
On 2008-06-13 15:07, ben mitch wrote:
> Hi > > I hope you'll see this cross-post (c/c++) as appropriate. I also admit > immediately that the question *may* turn out to be > compiler-/os-specific, in which case I apologize. But I wonder if > there's an underlying truth. > > We are writing a (cross-platform) 'framework' application (in C++, as it > happens) that allows users to author 'plugins' (as shared library > modules). If you want it to truly be cross-platform you can not allow exceptions to pass through to/from the plugins. The reason is simple: there is no standardised way of doing this. The only (?) standardised calling convention which will be available on multiple platforms is the C calling convention and it does not support exceptions. -- Erik Wikström |
Re: propagation of exceptions over module/language boundaries
On 2008-06-13 17:59, Erik Wikström wrote:
> On 2008-06-13 15:07, ben mitch wrote: >> Hi >> >> I hope you'll see this cross-post (c/c++) as appropriate. I also admit >> immediately that the question *may* turn out to be >> compiler-/os-specific, in which case I apologize. But I wonder if >> there's an underlying truth. >> >> We are writing a (cross-platform) 'framework' application (in C++, as it >> happens) that allows users to author 'plugins' (as shared library >> modules). > > If you want it to truly be cross-platform you can not allow exceptions > to pass through to/from the plugins. The reason is simple: there is no > standardised way of doing this. The only (?) standardised calling > convention which will be available on multiple platforms is the C > calling convention and it does not support exceptions. Sorry, I should mention that it is possible, but you would have to require that all the code (framework and plugins) is compiled with the same compiler and you will have to use a C++ API. -- Erik Wikström |
Re: propagation of exceptions over module/language boundaries
Erik Wikström wrote:
> On 2008-06-13 15:07, ben mitch wrote: >> Hi >> >> I hope you'll see this cross-post (c/c++) as appropriate. I also admit >> immediately that the question *may* turn out to be >> compiler-/os-specific, in which case I apologize. But I wonder if >> there's an underlying truth. >> >> We are writing a (cross-platform) 'framework' application (in C++, as it >> happens) that allows users to author 'plugins' (as shared library >> modules). > > If you want it to truly be cross-platform you can not allow exceptions > to pass through to/from the plugins. The reason is simple: there is no > standardised way of doing this. The only (?) standardised calling > convention which will be available on multiple platforms is the C > calling convention and it does not support exceptions. > This is not true. Most C++ compilers support C and will allow C and C++ to coexist peacefully. Problems arise when you mix different compilers and versions or you want to generate code dynamically. -- jacob navia jacob at jacob point remcomp point fr logiciels/informatique http://www.cs.virginia.edu/~lcc-win32 |
Re: propagation of exceptions over module/language boundaries
On 2008-06-13 18:04, jacob navia wrote:
> Erik Wikström wrote: >> On 2008-06-13 15:07, ben mitch wrote: >>> Hi >>> >>> I hope you'll see this cross-post (c/c++) as appropriate. I also admit >>> immediately that the question *may* turn out to be >>> compiler-/os-specific, in which case I apologize. But I wonder if >>> there's an underlying truth. >>> >>> We are writing a (cross-platform) 'framework' application (in C++, as it >>> happens) that allows users to author 'plugins' (as shared library >>> modules). >> >> If you want it to truly be cross-platform you can not allow exceptions >> to pass through to/from the plugins. The reason is simple: there is no >> standardised way of doing this. The only (?) standardised calling >> convention which will be available on multiple platforms is the C >> calling convention and it does not support exceptions. >> > > This is not true. Most C++ compilers support C and will allow C and > C++ to coexist peacefully. Problems arise when you mix different > compilers and versions or you want to generate code dynamically. What is not true? To my knowledge there are two ways for C and C++ to coexist: either you compile the C code as C++ (in which case it is no longer C), or you use extern "C", in which case you use the C calling convention. Further mote it is true that there is no standardised cross-platform way of propagating exceptions. An, as far as I know, the C calling convention is the only wide-spread standardised calling convention. -- Erik Wikström |
Re: propagation of exceptions over module/language boundaries
Erik Wikström wrote:
> On 2008-06-13 18:04, jacob navia wrote: >> Erik Wikström wrote: >>> If you want it to truly be cross-platform you can not allow exceptions >>> to pass through to/from the plugins. The reason is simple: there is no >>> standardised way of doing this. The only (?) standardised calling >>> convention which will be available on multiple platforms is the C >>> calling convention and it does not support exceptions. >>> >> This is not true. Most C++ compilers support C and will allow C and >> C++ to coexist peacefully. Problems arise when you mix different >> compilers and versions or you want to generate code dynamically. > > What is not true? To my knowledge there are two ways for C and C++ to > coexist: either you compile the C code as C++ (in which case it is no > longer C), or you use extern "C", in which case you use the C calling > convention. > Calling conventions have nothing to do here. You are confusing calling convention (function call interface) with propagating the exceptions (i.e. letting a throw pass through your code), what is completely different. > Further mote it is true that there is no standardised cross-platform way > of propagating exceptions. Yes. That is why I said that if you stick to the same compiler and version it will work. > An, as far as I know, the C calling > convention is the only wide-spread standardised calling convention. > Again, calling conventions are NOT the issue here. jacob -- jacob navia jacob at jacob point remcomp point fr logiciels/informatique http://www.cs.virginia.edu/~lcc-win32 |
Re: propagation of exceptions over module/language boundaries
jacob navia wrote:
> Erik Wikström wrote: >> On 2008-06-13 15:07, ben mitch wrote: >>> Hi >>> >>> I hope you'll see this cross-post (c/c++) as appropriate. I also >>> admit immediately that the question *may* turn out to be >>> compiler-/os-specific, in which case I apologize. But I wonder if >>> there's an underlying truth. >>> >>> We are writing a (cross-platform) 'framework' application (in C++, as >>> it happens) that allows users to author 'plugins' (as shared library >>> modules). >> >> If you want it to truly be cross-platform you can not allow exceptions >> to pass through to/from the plugins. The reason is simple: there is no >> standardised way of doing this. The only (?) standardised calling >> convention which will be available on multiple platforms is the C >> calling convention and it does not support exceptions. >> > > This is not true. Most C++ compilers support C and will allow C and > C++ to coexist peacefully. They do, provided you use C linkage functions (extern "C" in the C++ world). Exceptions are alien to C, so you simply can't propagate exceptions through a C function. > Problems arise when you mix different > compilers and versions or you want to generate code dynamically. > A problem in C++, but in C? The C ABI is determined by the platform, not the compiler (at least in the Linux/Unix world). If a compiler used a different ABI, how could it link to system libraries? -- Ian Collins. |
Re: propagation of exceptions over module/language boundaries
Ian Collins wrote:
> jacob navia wrote: [snip] >> This is not true. Most C++ compilers support C and will allow C and >> C++ to coexist peacefully. > > They do, provided you use C linkage functions (extern "C" in the C++ > world). Exceptions are alien to C, so you simply can't propagate > exceptions through a C function. > Yes you can. I have done this under gcc and msvc, and I think all C++ compilers will generate compatible code. >> Problems arise when you mix different >> compilers and versions or you want to generate code dynamically. >> > A problem in C++, but in C? The C ABI is determined by the platform, > not the compiler (at least in the Linux/Unix world). If a compiler used > a different ABI, how could it link to system libraries? > If you use different compilers, the throw machinery ill be different and passing throws will just not work. -- jacob navia jacob at jacob point remcomp point fr logiciels/informatique http://www.cs.virginia.edu/~lcc-win32 |
| All times are GMT. The time now is 06:30 PM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.