[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

#### 3.9.3.3 Suicidal exception handling

An inconvenient characteristic of some external library functions is to terminate the program rather than returning an error status to the caller for routine events such as a failure of memory allocation. Although in many cases there is no simple workaround for this behavior, memory allocation failures at least can be detected and preventive action taken by using the functions described in this section.

The general approach is to use memory management functions from ‘`mwrap.h`’ as described previously (Memory leaks), while additionally registering a return destination for a non-local jump to be taken in the event of a memory overflow. The jump is taken when an external library function calls `malloc` or `realloc` unsuccessfully. The jump avoids passing control back to the library function, thereby denying it the opportunity to abort, but restores the context to that of the jump destination almost as if the library function and all of its intervening callers had returned normally.

The interface is similar to that of the standard `setjmp` function defined in the system header file `setjmp.h`, and in fact is built on it, but differs in that the client module does not explicitly refer to jump buffers. Instead, the `mwrap` module internally maintains a stack of return destinations.

If a jump is taken, it always goes to the most recently registered destination. It may revert to the previously registered destination only when the current one is cleared. This organization provides the necessary flexibility for multiple clients and recursion, but it necessitates a protocol whereby each registration of a destination must be explicitly cleared exactly once.

The following functions implement these two features.

Function: int avm_setjmp ()

  This function specifies the point to which control will pass by a non-local jump if there is insufficient memory to complete a subsequent `malloc` or `realloc` operation. Only the operations that take place while memory is being managed due to `avm_manage_memory` are affected (Memory leaks).

  The function returns zero when it is called normally and successfully registers the return point.

  It returns a non-zero value when it has been entered by a non-local jump (i.e., when `malloc` or `realloc` has reported insufficient memory while memory management is active), or when the return point could not be successfully registered due to insufficient memory. The client need not distinguish between these two cases, because both correspond to memory overflows and the destination must be cleared by `avm_clearjmp` regardless.

  When a non-zero value is returned due to this function being reached by a non-local jump, it has the side effects of reclaiming all managed memory by calling `avm_free_managed_memory` and disabling memory management by calling `avm_dont_manage_memory`.

Function: void avm_clearjmp ()

  This function cancels the effect of `avm_setjmp ()` by preventing further non-local jumps to its destination if the destination was successfully registered, or by acknowledging unsuccessful registration otherwise. It should be called before exiting any function that calls `avm_setjmp ()` or anomalous results may ensue.

The memory management functions `avm_manage_memory` and `avm_dont_manage_memory` can be useful with or without `avm_setjmp`, depending on how much of a workaround is needed for a given library. If a library does not abort on memory overflows, there is no need to use `avm_setjmp`, while it may still be appropriate to use the other functions against memory leaks.

Calling `avm_clearjmp` is particularly important if a client module with memory management that doesn’t use `avm_setjmp` is invoked subsequently to one that does, so that memory overflows in the latter won’t cause an attempted jump to a stale destination.

A further complication that arises from careful consideration of these issues is the situation of a client module that does not intend to use `avm_setjmp` but is called (perhaps indirectly) by one that does. The latter will have registered a return destination that remains active and valid even if the former refrains from doing so, thereby allowing a branch to be taken that should have been prevented. Although it is an unusual situation, it can be accommodated by the following function.

Function: void avm_setnonjump ()

  This function temporarily inhibits non-local jumps to destinations previously registered by `avm_setjmp` until the next time `avm_clearjmp` is called. Thereafter, any previously registered destinations are reinstated.

A sketch of how some of these functions might be used to cope with library functions that would otherwise terminate the program in the event of a memory overflow is shown below. The GNU `libc` reference manual contains a related discussion of non-local jumps.

    #include <avm/mwrap.h>
    ...

    int
    function foobar (foo, bar)
    ...
    {
    char *my_data;

      my_data = (char *) malloc (100);
      if (avm_setjmp () != 0)
        {
          avm_clearjmp ();
          avm_turn_on_stdout ();       /* reaching here */
          free (my_data);              /* means malloc  */
          return ABNORMAL_STATUS;      /* failed below  */
        }
      avm_turn_off_stdout ();
      avm_manage_memory ();
      ...
      call_library_functions (foo, bar);    /* may jump */
      ...                                   /* to above */
      avm_free_managed_memory ();
      avm_turn_on_stdout ();
      avm_clearjmp ();
      free (my_data);            /* reaching here means */
      return OK_STATUS;          /* jumping wasn't done */
    }

Portability issues with these functions are not well known at this writing. If the configuration script for `avram` fails to detect the required features in `setjmp.h` on the host system, conditional compilation directives will disable the functions `avm_setjmp`, `avm_clearjmp`, and `avm_setnonjmp`. However, it may still be possible for the other `avm_`* memory management functions to be configured.

If `setjmp` is not configured, the `avm_setjmp` function is still callable but will always return a value of zero, and will provide no protection against external library functions aborting the program. The other two will perform no operation and return.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

This document was generated on November 8, 2012 using texi2html 1.82.