28

Possible Duplicate:
Will C++ exceptions safely propagate through C code?

If you have c code, for example the png lib, with your own io handlers which are written in c++ and an exception gets thrown due to some io error. is it ok to let it go through the c code and catch it outside of the c code? i know that care has to be taken with memory leaks but typically all structures get pre-allocated.

Community
  • 1
  • 1
Jochen_0x90h
  • 311
  • 3
  • 5
  • If you want to use C library which calls your C++ callback in which you throw an exception and you make sure you catch it somewhere in your own code, then you can enable exception handling in GCC with `-fexceptions` when compiling your C library and it should work. – Kerrek SB Jun 21 '11 at 14:24
  • I think this invokes undefined behavior. The very least is that C code isn't exception-safe, so it will leak resources left and right. See also this answer: http://stackoverflow.com/questions/6253574/uncaught-exception-in-a-callback-from-a-3rd-party-static-library/6253614#6253614 – sbi Jun 21 '11 at 14:31
  • 14
    +1 for the only question I've seen yet that can legitimately use both [c] and [c++] tags. – Justin ᚅᚔᚈᚄᚒᚔ Jun 21 '11 at 14:41
  • @sbi: Sure, you'd be taking full responsibility for the failings of the C code should an exception occur. I guess it's just for weird scenarios where you really want to write your own C library for other purposes but also want to pass C++ functions through it and everything is under your control... – Kerrek SB Jun 21 '11 at 14:50
  • 1
    @Kerrek: But it isn't under your control. There is no way you can clean up after yourself in C code if C++ exceptions come whooshing by. You lack the tools to do so in C. That's why there's only one legitimate answer to such questions: Do not let C++ exceptions pass through code in other languages, be it C or anything else. – sbi Jun 21 '11 at 14:57
  • @sbi: Practically you're right of course, and I can't really think of situations where you could meaningfully allow this. Perhaps if your own library didn't allocate anything non-automatic. – Kerrek SB Jun 21 '11 at 15:00
  • @Kerrek: Now that's quite a convoluted set of requirements, don't you think? The code _must_ be written in C, C++ won't do, but at the same time the code must not acquire any resources that must be released. How often do you think we'd run in such a scenario? – sbi Jun 21 '11 at 15:05
  • @sbi: Indeed, as I said, I can't think of a non-contrived situation where this would be useful. Hmm... Maybe if you don't care about memory management because you have a one-off command-line tool, and you just want convenient error handling... I don't know. I just noticed that GCC is able to construct the relevant code to keep your exceptions alive :-) – Kerrek SB Jun 21 '11 at 15:12
  • @sbi, @Kerreck: regardless of what you can conceive, the question says "typically all structures get pre-allocated", so leaks have already been considered and ruled out. That's not uncommon for certain kinds of high-performance code in C or C++, although (a) I wonder whether the exception will remain as high-performance, if that matters, and (b) there also has to be a good reason to mix them, as opposed to porting the C code to C++. – Steve Jessop Jun 21 '11 at 15:34
  • is it then possible to store an exception somewhere and rethrow it outside of the c code? and what about visual c++? does it have an -fexceptions equivalent? – Jochen_0x90h Jun 21 '11 at 16:57
  • @Jochen: This is what I have done before: Catch an exception before the transition to C takes place and store it. After leaving the C part check for a stored exception and, if present, re-throw it. However, note that `std::exception` doesn't have a `rethrow()` method, so this is impossible to do polymorphically unless you use your own hierarchy that implements such a virtual member function. – sbi Jun 21 '11 at 17:31
  • I don't believe this is a duplicate, because the other question is narrower: although not tagged with `SQLite`, it asks about it specifically, and the top answers rely on that assumption. – Kyle Strand Apr 23 '19 at 19:04

5 Answers5

9

It is entirely up to the compiler if this will work or not. None of the language standards can obviously say anything about what the other language should do.

In the best case, the exception will pass the C code and get back to the next C++ level while possibly leaking any dynamically allocated C structures. In the less good case, it will crash and burn!

One possibilty is of course to compile the C code as C++, while also checking that it is exception neutral.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • The language standard can't say what other languages should do, but they _can_ say what the _implementation_ should do, and that includes the language-agnostic runtime ABI. At a minimum, the standard could make this implementation-defined behavior. – Kyle Strand Apr 23 '19 at 19:05
7

The answer to your question is implementation-defined.

For GCC, as @Kerrek says, compiling the C code with -fexceptions will ensure the run-time remains consistent when an exception is thrown through C code. (Note that modern exception mechanisms are not just implemented via setjmp/longjmp; they actually unwind the stack frame by frame in order to handle destructors and try/catch blocks properly.)

However, the C code itself may not be expecting to have exceptions thrown through it. Lots of C code is written like this:

acquire a resource
do some stuff
release resource

Here "acquire a resource" could mean malloc, or pthread_mutex_lock, or fopen. If your C++ code is part of the "do some stuff", and it throws an exception, well... Whoops.

Resource leaks are not the only problem; so is correctness is general. Imagine:

subtract $100 from savings account
add $100 to checking account

Now imagine an exception gets thrown after the first step finishes but before the second one does.

In short, although your implementation may provide a way to let you throw exceptions through C code, it is a bad idea unless you also wrote that C code knowing exactly where an exception might be thrown.

Nemo
  • 70,042
  • 10
  • 116
  • 153
  • 1
    A little late, but your banking example isn't very good, as you don't want to handle such things like that anyway. You want to use transactions, so you can always rollback states. Which means that the `subtract` is nothing, but a temporarily state and thus isn't a real issue as you can just rollback the subtractions. Now that's when your example is taken into real life situation. – Bauss Jan 31 '17 at 13:15
  • Thank you so much. This was the answer that solved the question "can you throw an exception from your main program, through a shared library written in C, and catch it in your main program again?" - Yes you can! – gonzo Dec 26 '20 at 01:08
5

It's okay for your C++ code if it's:

  1. Compiled with exceptions enabled.
  2. Exception safe.

It's okay for your C or C++ code if:

  1. No resources need to be collected explicitly between the throwing of the exception, and its being caught.

Code compiled with C++ exception support adds special hooks to clean up when exceptions are thrown and not caught in that scope. C++ objects allocated on the stack will have their destructors invoked.

The only resource reclaimed in C (or C++ without exception support) when an exception is thrown is the space allocated in each stack frame.

This section of the GCC manual is quite helpful:

       -fexceptions
           Enable exception handling.  Generates extra code needed to
           propagate exceptions.  For some targets, this implies GCC will
           generate frame unwind information for all functions, which can
           produce significant data size overhead, although it does not affect
           execution.  If you do not specify this option, GCC will enable it
           by default for languages like C++ which normally require exception
           handling, and disable it for languages like C that do not normally
           require it.  However, you may need to enable this option when
           compiling C code that needs to interoperate properly with exception
           handlers written in C++.  You may also wish to disable this option
           if you are compiling older C++ programs that don't use exception
           handling.
Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
  • Your C code can hold resources if your code calls a resource-allocation function in the destructor of a RAII class at the last point of your C++ code before returning. This is what the libjpeg API does. When the runtime finds that the exception will be caught the C++ stack frames unwind and when the last one unwinds the error callback is called, releasing all the C resources and resetting state, then the exception passes over the C code landing in C++ to continue unwinding. All as one would desire. – codeshot Oct 19 '17 at 23:29
4

Exceptions aren't usually really thrown "through" code; as the action implies, they are thrown "over" code.

As a forinstance; at least old-school Objective-C exceptions are usually implemented with setjmp and longjmp; essentially storing the addresses of code for later use.

It makes sense for C++ exceptions to be implemented with similar mechanisms; and as such; the type of code the exception is thrown "through", or more accurately, "over" matters little, if at all. One could even imagine a setting where an Objective-C exception is thrown over a C++ catch, or vice versa.

Edit: As Bo Persson mentiones; this is not to say that a C++ exception interrupting C code wouldn't cause havoc and leaks; but exceptions being thrown is usually a Bad Thing™ all round; so it's not likely to matter much.

PS: Kudos on actually asking a question where using both C and C++ tags is relevant. ;)

Williham Totland
  • 28,471
  • 6
  • 52
  • 68
1

C doesn't know anything about exceptions so it's not possible to say what would happen.

To write conforming code you'd need to catch exceptions prior to returning into the C library, translate to error codes, and then translate the C-library error back into an exception on the other end.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • "doesn't know" isn't really the reason for the behaviour. – Matt Joiner Jun 21 '11 at 14:31
  • @Matt: but it is the reason for not being possible to say what would happen. – Dennis Zickefoose Jun 21 '11 at 16:29
  • I recall that the GCC ABI defines that the exception right over C's head although I can no longer find a reference for that detail and I found this " C language code that is expecting to interoperate with C++ should be compiled with -fexceptions. This will make debugging a C language function called as part of C++-induced stack unwinding possible. In particular, unwinding into a frame with no exception handling data will cause a runtime abort. If the unwinder runs out of unwind info before it finds a handler, std::terminate() is called. " – codeshot Oct 19 '17 at 23:36
  • As a result I allow c++ exceptions to pass right over libjpeg to maximise information about the throw site at all points, and I call the jpeg error callback in the destructor of a RAII class in the C++ callback to release all of C's resources. I didn't experience any debugging problems. – codeshot Oct 19 '17 at 23:38
  • for GCC on x86-64, the documentation is incorrect. -fno-asynchronous-unwind-tables is needed to cause an abort in this situation. – codeshot Oct 20 '17 at 00:14