# Error handling in C libraries

Some C libraries can produce errors and use some sort of callback mechanism to report errors: an external error handling function needs to be set up which will be called by the C library if an error occurs.

The function `sig_error()` can be used to deal with these errors. This function may only be called within a `sig_on()` block (otherwise the Python interpreter will crash hard) after raising a Python exception. You need to use the Python/C API for this and call `sig_error()` after calling some variant of `PyErr_SetObject()`. Even within Cython, you cannot use the `raise` statement, because then the `sig_error()` will never be executed. The call to `sig_error()` will use the `sig_on()` machinery such that the exception will be seen by `sig_on()`.

A typical error handler implemented in Cython would look as follows:

    from cysignals.signals cimport sig_error
    from cpython.exc cimport PyErr_SetString

    cdef void error_handler(char *msg):
        PyErr_SetString(RuntimeError, msg)
        sig_error()

Exceptions which are raised this way can be handled as usual by putting the `sig_on()` in a `try`/`except` block. For example, the package cypari2 provides a wrapper around the number theory library PARI/GP. The error handler has a callback which turns errors from PARI/GP into Python exceptions of type `PariError`. This can be handled as follows:

    from cysignals.signals cimport sig_on, sig_off
    def handle_pari_error():
        try:
            sig_on()  # This must be INSIDE the try
            # (call to PARI)
            sig_off()
        except PariError:
            # (handle error)

SageMath uses this mechanism for libGAP, GLPK, NTL and PARI.