mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-12 10:04:14 +02:00
Wrap try in a do...while loop to make sure that no random else is attached to the main if block.
This commit is contained in:
parent
9395ad7043
commit
dc1a5c18ac
@ -72,7 +72,7 @@
|
||||
</release-item>
|
||||
|
||||
<release-item>
|
||||
<p>Simplify try..catch..finally names.</p>
|
||||
<p>Simplify try..catch..finally names. Also wrap in a do...while loop to make sure that no random else is attached to the main if block.</p>
|
||||
</release-item>
|
||||
|
||||
<release-item>
|
||||
|
13
libc/LibC.h
13
libc/LibC.h
@ -50,7 +50,7 @@ This turned out to be a dead end because Perl 5.10 does not support croak_sv(),
|
||||
Error handling macros that throw a Perl error when a C error is caught
|
||||
***********************************************************************************************************************************/
|
||||
#define ERROR_XS_BEGIN() \
|
||||
TRY()
|
||||
TRY_BEGIN()
|
||||
|
||||
#define ERROR_XS() \
|
||||
croak("PGBRCLIB:%d:%s:%d:%s", errorCode(), errorFileName(), errorFileLine(), errorMessage());
|
||||
@ -59,7 +59,8 @@ Error handling macros that throw a Perl error when a C error is caught
|
||||
CATCH_ANY() \
|
||||
{ \
|
||||
ERROR_XS(); \
|
||||
}
|
||||
} \
|
||||
TRY_END();
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Core context handling macros, only intended to be called from other macros
|
||||
@ -72,7 +73,7 @@ Core context handling macros, only intended to be called from other macros
|
||||
volatile bool MEM_CONTEXT_XS_croak = false; \
|
||||
\
|
||||
/* Try the statement block */ \
|
||||
TRY()
|
||||
TRY_BEGIN()
|
||||
|
||||
#define MEM_CONTEXT_XS_CORE_END() \
|
||||
/* Set error to be croak to Perl later */ \
|
||||
@ -84,7 +85,8 @@ Core context handling macros, only intended to be called from other macros
|
||||
FINALLY() \
|
||||
{ \
|
||||
memContextSwitch(MEM_CONTEXT_XS_memContextOld); \
|
||||
}
|
||||
} \
|
||||
TRY_END();
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Simplifies creation of the memory context in contructors and includes error handling
|
||||
@ -94,7 +96,7 @@ Simplifies creation of the memory context in contructors and includes error hand
|
||||
/* Attempt to create the memory context */ \
|
||||
MemContext *MEM_CONTEXT_XS_memContext = NULL; \
|
||||
\
|
||||
TRY() \
|
||||
TRY_BEGIN() \
|
||||
{ \
|
||||
MEM_CONTEXT_XS_memContext = memContextNew(contextName); \
|
||||
} \
|
||||
@ -102,6 +104,7 @@ Simplifies creation of the memory context in contructors and includes error hand
|
||||
{ \
|
||||
ERROR_XS() \
|
||||
} \
|
||||
TRY_END(); \
|
||||
\
|
||||
MEM_CONTEXT_XS_CORE_BEGIN(MEM_CONTEXT_XS_memContext)
|
||||
|
||||
|
@ -77,7 +77,7 @@ decodeToBinValid(EncodeType encodeType, const char *source)
|
||||
{
|
||||
volatile bool valid = true;
|
||||
|
||||
TRY()
|
||||
TRY_BEGIN()
|
||||
{
|
||||
decodeToBinValidate(encodeType, source);
|
||||
}
|
||||
@ -85,6 +85,7 @@ decodeToBinValid(EncodeType encodeType, const char *source)
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ Error Handler
|
||||
|
||||
Implement a try ... catch ... finally error handler.
|
||||
|
||||
TRY()
|
||||
TRY_BEGIN()
|
||||
{
|
||||
<Do something that might throw an error>
|
||||
}
|
||||
@ -23,11 +23,16 @@ FINALLY()
|
||||
{
|
||||
<Cleanup code that runs in all cases>
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
The CATCH() and FINALLY() blocks are optional but at least one must be specified. There is no need for an TRY block by itself
|
||||
The CATCH() and FINALLY() blocks are optional but at least one must be specified. There is no need for a TRY block by itself
|
||||
because errors will automatically be propagated to the nearest try block in the call stack.
|
||||
|
||||
Never call return from within any of the error-handling blocks.
|
||||
IMPORTANT: If a local variable of the function containing a TRY block is modified in the TRY_BEGIN() block and used later in the
|
||||
function after an error is thrown, that variable must be declared "volatile" if the preserving the value is important. Beware that
|
||||
gcc's -Wclobbered warnings are almost entirely useless for catching such issues.
|
||||
|
||||
IMPORTANT: Never call return from within any of the error-handling blocks.
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef ERROR_H
|
||||
#define ERROR_H
|
||||
@ -51,8 +56,11 @@ bool errorInstanceOf(const ErrorType *errorTypeTest);
|
||||
/***********************************************************************************************************************************
|
||||
Begin a block where errors can be thrown
|
||||
***********************************************************************************************************************************/
|
||||
#define TRY() \
|
||||
#define TRY_BEGIN() \
|
||||
do \
|
||||
{ \
|
||||
if (errorInternalTry(__FILE__, __LINE__) && setjmp(*errorInternalJump()) >= 0) \
|
||||
{ \
|
||||
while (errorInternalProcess(false)) \
|
||||
if (errorInternalStateTry())
|
||||
|
||||
@ -74,6 +82,13 @@ Code to run whether the try block was successful or not
|
||||
#define FINALLY() \
|
||||
else if (errorInternalStateFinal())
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
End the try block
|
||||
***********************************************************************************************************************************/
|
||||
#define TRY_END() \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Throw an error
|
||||
|
||||
|
@ -43,7 +43,7 @@ Memory context management functions
|
||||
MemContext *context = memContextNew();
|
||||
MemContext *contextOld = memContextSwitch(context);
|
||||
|
||||
TRY()
|
||||
TRY_BEGIN()
|
||||
{
|
||||
<Do something with the memory context>
|
||||
}
|
||||
@ -58,6 +58,7 @@ FINALLY
|
||||
{
|
||||
memContextSwitch(context);
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
Use the MEM_CONTEXT*() macros when possible rather than implement error-handling for every memory context block.
|
||||
***********************************************************************************************************************************/
|
||||
@ -100,7 +101,7 @@ MEM_CONTEXT_END();
|
||||
MemContext *MEM_CONTEXT_memContextOld = memContextSwitch(memContext); \
|
||||
\
|
||||
/* Try the statement block */ \
|
||||
TRY()
|
||||
TRY_BEGIN()
|
||||
|
||||
#define MEM_CONTEXT_OLD() \
|
||||
MEM_CONTEXT_memContextOld
|
||||
@ -111,6 +112,7 @@ MEM_CONTEXT_END();
|
||||
{ \
|
||||
memContextSwitch(MEM_CONTEXT_OLD()); \
|
||||
} \
|
||||
TRY_END(); \
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
|
@ -30,7 +30,7 @@ Test that an expected error is actually thrown and error when it isn't.
|
||||
printf(" l%04d - expect error: %s\n", __LINE__, errorMessageExpected); \
|
||||
fflush(stdout); \
|
||||
\
|
||||
TRY() \
|
||||
TRY_BEGIN() \
|
||||
{ \
|
||||
statement; \
|
||||
} \
|
||||
@ -43,6 +43,7 @@ Test that an expected error is actually thrown and error when it isn't.
|
||||
AssertError, "expected error %s, '%s' but got %s, '%s'", errorTypeName(&errorTypeExpected), errorMessageExpected, \
|
||||
errorName(), errorMessage()); \
|
||||
} \
|
||||
TRY_END(); \
|
||||
\
|
||||
if (!TEST_ERROR_catch) \
|
||||
THROW( \
|
||||
@ -99,7 +100,7 @@ parameters.
|
||||
/* Try to run the statement */ \
|
||||
type TEST_RESULT_result; \
|
||||
\
|
||||
TRY() \
|
||||
TRY_BEGIN() \
|
||||
{ \
|
||||
TEST_RESULT_result = (type)(statement); \
|
||||
} \
|
||||
@ -111,6 +112,7 @@ parameters.
|
||||
AssertError, "statement '%s' threw error %s, '%s' but result <%s> expected", \
|
||||
#statement, errorName(), errorMessage(), TEST_RESULT_resultExpectedStr); \
|
||||
} \
|
||||
TRY_END(); \
|
||||
\
|
||||
/* Test the type operator */ \
|
||||
bool TEST_RESULT_resultOp = false; \
|
||||
|
@ -11,7 +11,7 @@ bool testTryRecurseFinally = false;
|
||||
|
||||
void testTryRecurse()
|
||||
{
|
||||
TRY()
|
||||
TRY_BEGIN()
|
||||
{
|
||||
testTryRecurseTotal++;
|
||||
assert(errorContext.tryTotal == testTryRecurseTotal + 1);
|
||||
@ -26,6 +26,7 @@ void testTryRecurse()
|
||||
{
|
||||
testTryRecurseFinally = true;
|
||||
}
|
||||
TRY_END();
|
||||
} // {uncoverable - function throws error, never returns}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@ -40,13 +41,13 @@ void testRun()
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
if (testBegin("TRY() with no errors"))
|
||||
if (testBegin("TRY with no errors"))
|
||||
{
|
||||
bool tryDone = false;
|
||||
bool catchDone = false;
|
||||
bool finallyDone = false;
|
||||
|
||||
TRY()
|
||||
TRY_BEGIN()
|
||||
{
|
||||
assert(errorContext.tryTotal == 1);
|
||||
tryDone = true;
|
||||
@ -60,6 +61,7 @@ void testRun()
|
||||
assert(errorContext.tryList[1].state == errorStateFinal);
|
||||
finallyDone = true;
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
assert(tryDone);
|
||||
assert(!catchDone);
|
||||
@ -68,31 +70,32 @@ void testRun()
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
if (testBegin("TRY() with multiple catches"))
|
||||
if (testBegin("TRY with multiple catches"))
|
||||
{
|
||||
bool tryDone = false;
|
||||
bool catchDone = false;
|
||||
bool finallyDone = false;
|
||||
|
||||
TRY()
|
||||
TRY_BEGIN()
|
||||
{
|
||||
assert(errorContext.tryTotal == 1);
|
||||
|
||||
TRY()
|
||||
TRY_BEGIN()
|
||||
{
|
||||
assert(errorContext.tryTotal == 2);
|
||||
|
||||
TRY()
|
||||
TRY_BEGIN()
|
||||
{
|
||||
assert(errorContext.tryTotal == 3);
|
||||
|
||||
TRY()
|
||||
TRY_BEGIN()
|
||||
{
|
||||
assert(errorContext.tryTotal == 4);
|
||||
tryDone = true;
|
||||
|
||||
THROW(AssertError, BOGUS_STR);
|
||||
}
|
||||
TRY_END();
|
||||
}
|
||||
CATCH(AssertError)
|
||||
{
|
||||
@ -103,11 +106,13 @@ void testRun()
|
||||
{
|
||||
finallyDone = true;
|
||||
}
|
||||
TRY_END();
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
RETHROW();
|
||||
}
|
||||
TRY_END();
|
||||
}
|
||||
CATCH(MemoryError)
|
||||
{
|
||||
@ -120,6 +125,7 @@ void testRun()
|
||||
|
||||
catchDone = true;
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
assert(tryDone);
|
||||
assert(catchDone);
|
||||
@ -134,7 +140,7 @@ void testRun()
|
||||
bool catchDone = false;
|
||||
bool finallyDone = false;
|
||||
|
||||
TRY()
|
||||
TRY_BEGIN()
|
||||
{
|
||||
tryDone = true;
|
||||
testTryRecurse();
|
||||
@ -155,6 +161,7 @@ void testRun()
|
||||
{
|
||||
finallyDone = true;
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
assert(tryDone);
|
||||
assert(catchDone);
|
||||
|
@ -263,7 +263,7 @@ void testRun()
|
||||
memContextTestName = "test-new-failed-block";
|
||||
bool bCatch = false;
|
||||
|
||||
TRY()
|
||||
TRY_BEGIN()
|
||||
{
|
||||
MEM_CONTEXT_NEW_BEGIN(memContextTestName)
|
||||
{
|
||||
@ -277,6 +277,7 @@ void testRun()
|
||||
{
|
||||
bCatch = true;
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
TEST_RESULT_BOOL(bCatch, true, "new context error was caught");
|
||||
TEST_RESULT_PTR(memContextCurrent(), memContextTop(), "context is now 'TOP'");
|
||||
|
Loading…
Reference in New Issue
Block a user