/* * RELIC is an Efficient LIbrary for Cryptography * Copyright (c) 2013 RELIC Authors * * This file is part of RELIC. RELIC is legal property of its developers, * whose names are not listed here. Please refer to the COPYRIGHT file * for contact information. * * RELIC is free software; you can redistribute it and/or modify it under the * terms of the version 2.1 (or later) of the GNU Lesser General Public License * as published by the Free Software Foundation; or version 2.0 of the Apache * License as published by the Apache Software Foundation. See the LICENSE files * for more details. * * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the LICENSE files for more details. * * You should have received a copy of the GNU Lesser General Public or the * Apache License along with RELIC. If not, see * or . */ /** * @file * * Interface of the error-handling functions. * * @ingroup relic */ #ifndef RLC_ERR_H #define RLC_ERR_H #include #include #include #include #include #include "relic_core.h" #include "relic_conf.h" #include "relic_util.h" #include "relic_label.h" /*============================================================================*/ /* Constant definitions */ /*============================================================================*/ /** * List of possible errors generated by the library. */ enum errors { /** Constant to indicate the first an error already catched. */ ERR_CAUGHT = 1, /** Occurs when memory-allocating functions fail. */ ERR_NO_MEMORY, /** Occcurs when the library precision is not sufficient. */ ERR_NO_PRECI, /** Occurs when a file is not found. */ ERR_NO_FILE, /** Occurs when the specified number of bytes cannot be read from source. */ ERR_NO_READ, /** Occurs when an invalid value is passed as input. */ ERR_NO_VALID, /** Occurs when a buffer capacity is insufficient. */ ERR_NO_BUFFER, /** Occurs when there is not a supported field in the security level. */ ERR_NO_FIELD, /** Occurs when there is not a supported curve in the security level. */ ERR_NO_CURVE, /** Occurs when the library configuration is incorrect. */ ERR_NO_CONFIG, /** Constant to indicate the number of errors. */ ERR_MAX }; /** Truncate file name if verbosity is turned off. */ #ifdef VERBS #define RLC_FILE RLC_STR(__FILE__) #else #define RLC_FILE \ ((strrchr(RLC_STR(__FILE__), '/') ? : RLC_STR(__FILE__) - 1) + 1) #endif /*============================================================================*/ /* Type definitions */ /*============================================================================*/ /** * Type that represents an error. */ typedef int err_t; /** * Type that describes an error status, including the error code and the program * location where the error occurred. */ typedef struct _sts_t { /** Error occurred. */ err_t *error; /** Pointer to the program location where the error occurred. */ jmp_buf addr; /** Flag to tell if there is a surrounding try-catch block. */ int block; } sts_t; /*============================================================================*/ /* Macro definitions */ /*============================================================================*/ /** * Implements the TRY clause of the error-handling routines. * * This macro copies the last error from the current library context to * a temporary variable and handles the current error. The loop is used so * the CATCH facility is called first to store the address of the error * being caught. The setjmp() function is then called to store the current * program location in the current error field. The program block can now be * executed. If an error is thrown inside the program block, the setjmp() * function is called again and the return value is non-zero. */ #define RLC_ERR_TRY \ { \ sts_t *_last, _this; \ ctx_t *_ctx = core_get(); \ _last = _ctx->last; \ _this.block = 1; \ _ctx->last = &_this; \ for (int _z = 0; ; _z = 1) \ if (_z) { \ if (setjmp(_this.addr) == 0) { \ if (1) \ /** * Implements the CATCH clause of the error-handling routines. * * First, the address of the error is stored and the execution resumes * on the RLC_ERR_TRY macro. If an error is thrown inside the program block, * the caught flag is updated and the last error is restored. If some error * was caught, the execution is resumed inside the RLC_CATCH block. * * @param[in] ADDR - the address of the exception being caught */ #define RLC_ERR_CATCH(ADDR) \ else { } \ _ctx->caught = 0; \ } else { \ _ctx->caught = 1; \ } \ _ctx->last = _last; \ break; \ } else { \ _this.error = ADDR; \ } \ } \ for (int _z = 0; _z < 2; _z++) \ if (_z == 1 && core_get()->caught) \ /** * Implements the THROW clause of the error-handling routines. * * If the error pointer is not NULL but there is no surrounding TRY-CATCH * block, then the code threw an exception after an exception was thrown. * In this case, we finish execution. * * If the error pointer is NULL, the error was thrown outside of a TRY-CATCH * block. An error message is printed and the function returns. * * If the error pointer is valid, the longjmp() function is called to return to * the program location where setjmp() was last called. An error message * respective to the error is then printed and the current error pointer is * updated to store the error. * * @param[in] E - the exception being caught. */ #define RLC_ERR_THROW(E) \ { \ ctx_t *_ctx = core_get(); \ _ctx->code = RLC_ERR; \ if (_ctx->last != NULL && _ctx->last->block == 0) { \ exit(E); \ } \ if (_ctx->last == NULL) { \ _ctx->last = &(_ctx->error); \ _ctx->error.error = &(_ctx->number); \ _ctx->error.block = 0; \ _ctx->number = E; \ RLC_ERR_PRINT(E); \ } else { \ for (; ; longjmp(_ctx->last->addr, 1)) { \ RLC_ERR_PRINT(E); \ if (_ctx->last->error) { \ if (E != ERR_CAUGHT) { \ *(_ctx->last->error) = E; \ } \ } \ } \ } \ } \ #ifdef CHECK /** * Implements a TRY clause. */ #define RLC_TRY RLC_ERR_TRY #else /** * Stub for the TRY clause. */ #define RLC_TRY if (1) #endif #ifdef CHECK /** * Implements a CATCH clause. */ #define RLC_CATCH(E) RLC_ERR_CATCH(&(E)) #else /** * Stub for the CATCH clause. */ #define RLC_CATCH(E) else #endif #ifdef CHECK /** * Implements a CATCH clause for any possible error. * * If this macro is used the error type is not available inside the CATCH * block. */ #define RLC_CATCH_ANY RLC_ERR_CATCH(NULL) #else /** * Stub for the RLC_CATCH_ANY clause. */ #define RLC_CATCH_ANY if (0) #endif #ifdef CHECK /** * Implements the RLC_FINALLY clause. */ #define RLC_FINALLY else if (_z == 0) #else #define RLC_FINALLY if (1) #endif #ifdef CHECK /** * Implements a THROW clause. */ #define RLC_THROW RLC_ERR_THROW #else /** * Stub for the THROW clause. */ #ifdef QUIET #define RLC_THROW(E) core_get()->code = RLC_ERR; #else #define RLC_THROW(E) \ core_get()->code = RLC_ERR; \ util_print("FATAL ERROR in %s:%d\n", RLC_FILE, __LINE__); \ #endif #endif /** * Treats an error jumping to the argument. * * @param[in] LABEL - the label to jump */ #define RLC_ERROR(LABEL) goto LABEL #ifdef QUIET /** * Stub for the error printing function. * * @param[in] ERROR - the error code. */ #define RLC_ERR_PRINT(ERROR) /* empty */ #else #ifdef VERBS /** * Prints the current error message in a complete format. * * @param[in] ERROR - the error code. */ #define RLC_ERR_PRINT(ERROR) \ err_full_msg(__func__, RLC_FILE, __LINE__, ERROR) \ #else /* VERBS */ /** * Prints the current error message. * * @param[in] ERROR - the error code. */ #define RLC_ERR_PRINT(ERROR) \ err_simple_msg(ERROR) \ #endif /* VERBS */ #endif /* QUIET */ /*============================================================================*/ /* Function prototypes */ /*============================================================================*/ #ifdef CHECK /** * Prints the error message with little information. * * @param[in] error - the error code. */ void err_simple_msg(int error); /** * Prints the error message with detailed information. * * @param[in] function - the function where the error occurred. * @param[in] file - the source file where the error occurred. * @param[in] line - the line in the file where the error occurred. * @param[in] error - the error code. */ void err_full_msg(const char *function, const char *file, int line, int error); /** * Prints the error message respective to an error code. * * @param[out] e - the error occurred. * @param[out] msg - the error message. */ void err_get_msg(err_t *e, char **msg); #endif /** * Returns the code returned by the last function call and resets the current * code. * * @returns ERR_OK if no errors occurred in the function, ERR_ERR otherwise. */ int err_get_code(void); #endif /* !RLC_ERR_H */