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

View File

@ -110,11 +110,16 @@ const char *errorName(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)
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
***********************************************************************************************************************************/

View File

@ -42,6 +42,10 @@ Main
int
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
stackTraceInit(argList[0]);
#endif

View File

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

View File

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

View File

@ -61,6 +61,10 @@ Includes that are not generally used by tests
#include "common/stat.h"
#endif
#ifdef HRN_IN_STACKTRACE
#include "common/stackTrace.h"
#endif
/***********************************************************************************************************************************
main - run the tests
***********************************************************************************************************************************/
@ -85,6 +89,20 @@ main(int argListSize, const char *argList[])
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
#if defined(HRN_INTEST_STAT) || defined(HRN_FEATURE_STAT)
statInit();