1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-12 10:04:14 +02:00

Add configurable error handlers.

The stackTrace and memContext error handlers were hard-coded which made testing the error module in isolation impossible.

Making the error handlers configurable also makes adding new ones in the future easier.
This commit is contained in:
David Steele 2021-01-27 17:25:13 -05:00
parent 8e9f04cc32
commit 5281e31422
6 changed files with 74 additions and 6 deletions

View File

@ -3,13 +3,13 @@ Error Handler
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
#include "build.auto.h" #include "build.auto.h"
#include <assert.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "common/error.h" #include "common/error.h"
#include "common/memContext.h"
#include "common/stackTrace.h" #include "common/stackTrace.h"
/*********************************************************************************************************************************** /***********************************************************************************************************************************
@ -52,6 +52,10 @@ static struct
// Array of jump buffers // Array of jump buffers
jmp_buf jumpList[ERROR_TRY_MAX]; jmp_buf jumpList[ERROR_TRY_MAX];
// Handler list
const ErrorHandlerFunction *handlerList;
unsigned int handlerTotal;
// State of each try // State of each try
int tryTotal; int tryTotal;
@ -88,6 +92,15 @@ static char messageBuffer[ERROR_MESSAGE_BUFFER_SIZE];
static char messageBufferTemp[ERROR_MESSAGE_BUFFER_SIZE]; static char messageBufferTemp[ERROR_MESSAGE_BUFFER_SIZE];
static char stackTraceBuffer[ERROR_MESSAGE_BUFFER_SIZE]; static char stackTraceBuffer[ERROR_MESSAGE_BUFFER_SIZE];
/**********************************************************************************************************************************/
void errorHandlerSet(ErrorHandlerFunction *list, unsigned int total)
{
assert(total == 0 || list != NULL);
errorContext.handlerList = list;
errorContext.handlerTotal = total;
}
/**********************************************************************************************************************************/ /**********************************************************************************************************************************/
int int
errorTypeCode(const ErrorType *errorType) errorTypeCode(const ErrorType *errorType)
@ -312,8 +325,8 @@ errorInternalProcess(bool catch)
// Else if just entering error state clean up the stack // Else if just entering error state clean up the stack
else if (errorContext.tryList[errorContext.tryTotal].state == errorStateTry) else if (errorContext.tryList[errorContext.tryTotal].state == errorStateTry)
{ {
stackTraceClean(errorTryDepth()); for (unsigned int handlerIdx = 0; handlerIdx < errorContext.handlerTotal; handlerIdx++)
memContextClean(errorTryDepth()); errorContext.handlerList[handlerIdx](errorTryDepth());
} }
// Increment the state // Increment the state

View File

@ -110,11 +110,16 @@ const char *errorName(void);
const char *errorStackTrace(void); const char *errorStackTrace(void);
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Functions to get information about the try stack Try stack getters/setters
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
// Get the depth of the current try statement (0 if none) // Get the depth of the current try statement (0 if none)
unsigned int errorTryDepth(void); unsigned int errorTryDepth(void);
// Add a handler to be called when an error occurs
typedef void (*const ErrorHandlerFunction)(unsigned int);
void errorHandlerSet(const ErrorHandlerFunction *list, unsigned int total);
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Begin a block where errors can be thrown Begin a block where errors can be thrown
***********************************************************************************************************************************/ ***********************************************************************************************************************************/

View File

@ -42,6 +42,10 @@ Main
int int
main(int argListSize, const char *argList[]) main(int argListSize, const char *argList[])
{ {
// Set stack trace and mem context error cleanup handlers
static const ErrorHandlerFunction errorHandlerList[] = {stackTraceClean, memContextClean};
errorHandlerSet(errorHandlerList, sizeof(errorHandlerList) / sizeof(ErrorHandlerFunction));
#ifdef WITH_BACKTRACE #ifdef WITH_BACKTRACE
stackTraceInit(argList[0]); stackTraceInit(argList[0]);
#endif #endif

View File

@ -50,17 +50,19 @@ unit:
- common/error.auto: noCode - common/error.auto: noCode
depend: depend:
- common/debug
- common/memContext
- common/stackTrace - common/stackTrace
# ---------------------------------------------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------------------------------------------
- name: stack-trace - name: stack-trace
total: 4 total: 4
feature: stackTrace
coverage: coverage:
- common/stackTrace - common/stackTrace
depend:
- common/debug
# ---------------------------------------------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------------------------------------------
- name: type-convert - name: type-convert
total: 11 total: 11

View File

@ -44,6 +44,17 @@ testTryRecurse(void)
TRY_END(); TRY_END();
} // {uncoverable - function throws error, never returns} } // {uncoverable - function throws error, never returns}
/***********************************************************************************************************************************
Test error handler
***********************************************************************************************************************************/
static unsigned int testErrorHandlerTryDepth;
static void
testErrorHandler(unsigned int tryDepth)
{
testErrorHandlerTryDepth = tryDepth;
}
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Test Run Test Run
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
@ -103,6 +114,16 @@ testRun(void)
volatile bool catchDone = false; volatile bool catchDone = false;
volatile bool finallyDone = false; volatile bool finallyDone = false;
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("set error handler");
static const ErrorHandlerFunction testErrorHandlerList[] = {testErrorHandler};
errorHandlerSet(testErrorHandlerList, sizeof(testErrorHandlerList) / sizeof(ErrorHandlerFunction));
assert(errorContext.handlerList[0] == testErrorHandler);
assert(errorContext.handlerTotal == 1);
// -------------------------------------------------------------------------------------------------------------------------
assert(errorTryDepth() == 0); assert(errorTryDepth() == 0);
TRY_BEGIN() TRY_BEGIN()
@ -131,6 +152,8 @@ testRun(void)
} }
CATCH(AssertError) CATCH(AssertError)
{ {
assert(testErrorHandlerTryDepth == 3);
// Finally below should run even though this error has been rethrown // Finally below should run even though this error has been rethrown
RETHROW(); RETHROW();
} }
@ -142,6 +165,8 @@ testRun(void)
} }
CATCH_ANY() CATCH_ANY()
{ {
assert(testErrorHandlerTryDepth == 2);
RETHROW(); RETHROW();
} }
TRY_END(); TRY_END();
@ -152,6 +177,7 @@ testRun(void)
} }
CATCH(RuntimeError) CATCH(RuntimeError)
{ {
assert(testErrorHandlerTryDepth == 1);
assert(errorTryDepth() == 1); assert(errorTryDepth() == 1);
assert(errorContext.tryList[1].state == errorStateCatch); assert(errorContext.tryList[1].state == errorStateCatch);
assert(strlen(errorMessage()) == sizeof(messageBuffer) - 1); assert(strlen(errorMessage()) == sizeof(messageBuffer) - 1);

View File

@ -61,6 +61,10 @@ Includes that are not generally used by tests
#include "common/stat.h" #include "common/stat.h"
#endif #endif
#ifdef HRN_IN_STACKTRACE
#include "common/stackTrace.h"
#endif
/*********************************************************************************************************************************** /***********************************************************************************************************************************
main - run the tests main - run the tests
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
@ -85,6 +89,20 @@ main(int argListSize, const char *argList[])
int result = 0; int result = 0;
#ifdef HRN_FEATURE_ERROR
static const ErrorHandlerFunction handlerList[] =
{
#if defined(HRN_INTEST_STACKTRACE) || defined(HRN_FEATURE_STACKTRACE)
stackTraceClean,
#endif
#if defined(HRN_INTEST_MEMCONTEXT) || defined(HRN_FEATURE_MEMCONTEXT)
memContextClean,
#endif
};
errorHandlerSet(handlerList, sizeof(handlerList) / sizeof(ErrorHandlerFunction));
#endif
// Initialize statistics // Initialize statistics
#if defined(HRN_INTEST_STAT) || defined(HRN_FEATURE_STAT) #if defined(HRN_INTEST_STAT) || defined(HRN_FEATURE_STAT)
statInit(); statInit();