Catching and Throwing Exceptions in C

For methods that can throw exceptions, there is an extra out argument in the generated code that holds the exception. For maximum backward compatibility and consistency, the extra argument is of type sidl.BaseInterface. When the exception parameter is not NULL, it indicates that an exception has been thrown. When an exception is thrown, the caller should ignore the value of the other out parameters as well as the function's return value. Every time you call a method that potentially can throw an exception, you must check the result. Otherwise, those exceptions will be utterly ignored and leak memory. There are are four macros provided in sidl_Exception.h to help with exception checking. Their use is fairly obvious from their names. They are:


SIDL_THROW(EX_VAR,EX_CLS,MSG)
SIDL_CHECK(EX_VAR)
SIDL_CLEAR(EX_VAR) 
SIDL_CATCH(EX_VAR,sidl_NAME)

In these macros, EX_VAR is the exception object itself, EX_CLS is the name of the SIDL type we wish the exception to be in a string, MSG is the message we wish to include with the exception and a string, and sidl_NAME is the type of the exception we expect to catch, as a string.

The following SIDL method taken from the Babel regression tests demonstrates how exceptions are handled.


int getFib(in int n, in int max_depth, in int max_value, in int depth)
  throws NegativeValueException, FibException;

Here is the C binding for this method:


int32_t
ExceptionTest_Fib_getFib(
  ExceptionTest_Fib self,
  int32_t n,
  int32_t max_depth,
  int32_t max_value,
  int32_t depth,
  sidl_BaseInterface *_ex);

Here is an example of how to perform exception handling in C using a package of macros defined in sidl_Exception.h. Note that the macros assume the exception class that is being thrown and caught inherits from or implements
sidl.BaseException -- something guaranteed by Babel.


#include "sidl_Exception.h"
/* ...numerous lines deleted... */
  int x;
  sidl_BaseInterface _ex = NULL;

  x = ExceptionTest_Fib_getFib(f, 10, 1, 100, 0, &_ex);
  if (SIDL_CATCH(_ex, "ExceptionTest.TooDeepException")) {
    traceback(_ex);
    SIDL_CLEAR(_ex);
  }
  else if (SIDL_CATCH(_ex, "ExceptionTest.TooBigException")) {
    traceback(_ex);
    SIDL_CLEAR(_ex);
  }
  else if (_ex == NULL) {
    return FALSE;
  }
  SIDL_CHECK(_ex);
  return TRUE;

  EXIT:;
    traceback(_ex);
    SIDL_CLEAR(_ex);
    return FALSE;

You do not have to use the macros provided in sidl_Exception.h if you do no want to. You can check _ex by checking if it is not NULL and then trying to cast it to the various potential exception types.

The following code snippet shows how to throw an exception in C using the macros from sidl_Exception.h. The first argument to SIDL_THROW is the exception output parameter, and the second argument is the type of exception being thrown. The third argument provides a textual description of the exception.


#include "sidl_Exception.h"
/* ...numerous lines deleted... */
int32_t
impl_ExceptionTest_Fib_getFib(
  ExceptionTest_Fib self, int32_t n, int32_t max_depth, int32_t max_value,
    int32_t depth, sidl_BaseInterface* _ex)
{
  /* DO-NOT-DELETE splicer.begin(ExceptionTest.Fib.getFib) */
  if (n < 0) {
    SIDL_THROW(*_ex,
               ExceptionTest_NegativeValueException,
               "called with negative n");
  }
  /* ...lines deleted... */
  EXIT:;
    /* SIDL_THROW macro will jump here. */
    /* Clean up code should be here. */
    return theValue;
  /* DO-NOT-DELETE splicer.end(ExceptionTest.Fib.getFib) */
}

The code section labeled EXIT is where you should put clean up code. The caller will ignore all the values leaving your C function (i.e., out or inout parameters) because you have thrown an exception, so your code should delete any references you were planning to return to the caller. It's good practice to set all inout and out array, interface or class pointers to NULL. This makes things work out better for clients who forget to check if an exception occurred or willfully choose to ignore it.



babel-0.10.2
users_guide Last Modified 2005-03-23

http://www.llnl.gov/CASC/components
components@llnl.gov