mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-14 10:13:05 +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>
|
||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
<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
|
Error handling macros that throw a Perl error when a C error is caught
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
#define ERROR_XS_BEGIN() \
|
#define ERROR_XS_BEGIN() \
|
||||||
TRY()
|
TRY_BEGIN()
|
||||||
|
|
||||||
#define ERROR_XS() \
|
#define ERROR_XS() \
|
||||||
croak("PGBRCLIB:%d:%s:%d:%s", errorCode(), errorFileName(), errorFileLine(), errorMessage());
|
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() \
|
CATCH_ANY() \
|
||||||
{ \
|
{ \
|
||||||
ERROR_XS(); \
|
ERROR_XS(); \
|
||||||
}
|
} \
|
||||||
|
TRY_END();
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Core context handling macros, only intended to be called from other macros
|
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; \
|
volatile bool MEM_CONTEXT_XS_croak = false; \
|
||||||
\
|
\
|
||||||
/* Try the statement block */ \
|
/* Try the statement block */ \
|
||||||
TRY()
|
TRY_BEGIN()
|
||||||
|
|
||||||
#define MEM_CONTEXT_XS_CORE_END() \
|
#define MEM_CONTEXT_XS_CORE_END() \
|
||||||
/* Set error to be croak to Perl later */ \
|
/* 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() \
|
FINALLY() \
|
||||||
{ \
|
{ \
|
||||||
memContextSwitch(MEM_CONTEXT_XS_memContextOld); \
|
memContextSwitch(MEM_CONTEXT_XS_memContextOld); \
|
||||||
}
|
} \
|
||||||
|
TRY_END();
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Simplifies creation of the memory context in contructors and includes error handling
|
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 */ \
|
/* Attempt to create the memory context */ \
|
||||||
MemContext *MEM_CONTEXT_XS_memContext = NULL; \
|
MemContext *MEM_CONTEXT_XS_memContext = NULL; \
|
||||||
\
|
\
|
||||||
TRY() \
|
TRY_BEGIN() \
|
||||||
{ \
|
{ \
|
||||||
MEM_CONTEXT_XS_memContext = memContextNew(contextName); \
|
MEM_CONTEXT_XS_memContext = memContextNew(contextName); \
|
||||||
} \
|
} \
|
||||||
@ -102,6 +104,7 @@ Simplifies creation of the memory context in contructors and includes error hand
|
|||||||
{ \
|
{ \
|
||||||
ERROR_XS() \
|
ERROR_XS() \
|
||||||
} \
|
} \
|
||||||
|
TRY_END(); \
|
||||||
\
|
\
|
||||||
MEM_CONTEXT_XS_CORE_BEGIN(MEM_CONTEXT_XS_memContext)
|
MEM_CONTEXT_XS_CORE_BEGIN(MEM_CONTEXT_XS_memContext)
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ decodeToBinValid(EncodeType encodeType, const char *source)
|
|||||||
{
|
{
|
||||||
volatile bool valid = true;
|
volatile bool valid = true;
|
||||||
|
|
||||||
TRY()
|
TRY_BEGIN()
|
||||||
{
|
{
|
||||||
decodeToBinValidate(encodeType, source);
|
decodeToBinValidate(encodeType, source);
|
||||||
}
|
}
|
||||||
@ -85,6 +85,7 @@ decodeToBinValid(EncodeType encodeType, const char *source)
|
|||||||
{
|
{
|
||||||
valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
|
TRY_END();
|
||||||
|
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ Error Handler
|
|||||||
|
|
||||||
Implement a try ... catch ... finally error handler.
|
Implement a try ... catch ... finally error handler.
|
||||||
|
|
||||||
TRY()
|
TRY_BEGIN()
|
||||||
{
|
{
|
||||||
<Do something that might throw an error>
|
<Do something that might throw an error>
|
||||||
}
|
}
|
||||||
@ -23,11 +23,16 @@ FINALLY()
|
|||||||
{
|
{
|
||||||
<Cleanup code that runs in all cases>
|
<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.
|
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
|
#ifndef ERROR_H
|
||||||
#define ERROR_H
|
#define ERROR_H
|
||||||
@ -51,8 +56,11 @@ bool errorInstanceOf(const ErrorType *errorTypeTest);
|
|||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Begin a block where errors can be thrown
|
Begin a block where errors can be thrown
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
#define TRY() \
|
#define TRY_BEGIN() \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
if (errorInternalTry(__FILE__, __LINE__) && setjmp(*errorInternalJump()) >= 0) \
|
if (errorInternalTry(__FILE__, __LINE__) && setjmp(*errorInternalJump()) >= 0) \
|
||||||
|
{ \
|
||||||
while (errorInternalProcess(false)) \
|
while (errorInternalProcess(false)) \
|
||||||
if (errorInternalStateTry())
|
if (errorInternalStateTry())
|
||||||
|
|
||||||
@ -74,6 +82,13 @@ Code to run whether the try block was successful or not
|
|||||||
#define FINALLY() \
|
#define FINALLY() \
|
||||||
else if (errorInternalStateFinal())
|
else if (errorInternalStateFinal())
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
End the try block
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
#define TRY_END() \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Throw an error
|
Throw an error
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ Memory context management functions
|
|||||||
MemContext *context = memContextNew();
|
MemContext *context = memContextNew();
|
||||||
MemContext *contextOld = memContextSwitch(context);
|
MemContext *contextOld = memContextSwitch(context);
|
||||||
|
|
||||||
TRY()
|
TRY_BEGIN()
|
||||||
{
|
{
|
||||||
<Do something with the memory context>
|
<Do something with the memory context>
|
||||||
}
|
}
|
||||||
@ -58,6 +58,7 @@ FINALLY
|
|||||||
{
|
{
|
||||||
memContextSwitch(context);
|
memContextSwitch(context);
|
||||||
}
|
}
|
||||||
|
TRY_END();
|
||||||
|
|
||||||
Use the MEM_CONTEXT*() macros when possible rather than implement error-handling for every memory context block.
|
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); \
|
MemContext *MEM_CONTEXT_memContextOld = memContextSwitch(memContext); \
|
||||||
\
|
\
|
||||||
/* Try the statement block */ \
|
/* Try the statement block */ \
|
||||||
TRY()
|
TRY_BEGIN()
|
||||||
|
|
||||||
#define MEM_CONTEXT_OLD() \
|
#define MEM_CONTEXT_OLD() \
|
||||||
MEM_CONTEXT_memContextOld
|
MEM_CONTEXT_memContextOld
|
||||||
@ -111,6 +112,7 @@ MEM_CONTEXT_END();
|
|||||||
{ \
|
{ \
|
||||||
memContextSwitch(MEM_CONTEXT_OLD()); \
|
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); \
|
printf(" l%04d - expect error: %s\n", __LINE__, errorMessageExpected); \
|
||||||
fflush(stdout); \
|
fflush(stdout); \
|
||||||
\
|
\
|
||||||
TRY() \
|
TRY_BEGIN() \
|
||||||
{ \
|
{ \
|
||||||
statement; \
|
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, \
|
AssertError, "expected error %s, '%s' but got %s, '%s'", errorTypeName(&errorTypeExpected), errorMessageExpected, \
|
||||||
errorName(), errorMessage()); \
|
errorName(), errorMessage()); \
|
||||||
} \
|
} \
|
||||||
|
TRY_END(); \
|
||||||
\
|
\
|
||||||
if (!TEST_ERROR_catch) \
|
if (!TEST_ERROR_catch) \
|
||||||
THROW( \
|
THROW( \
|
||||||
@ -99,7 +100,7 @@ parameters.
|
|||||||
/* Try to run the statement */ \
|
/* Try to run the statement */ \
|
||||||
type TEST_RESULT_result; \
|
type TEST_RESULT_result; \
|
||||||
\
|
\
|
||||||
TRY() \
|
TRY_BEGIN() \
|
||||||
{ \
|
{ \
|
||||||
TEST_RESULT_result = (type)(statement); \
|
TEST_RESULT_result = (type)(statement); \
|
||||||
} \
|
} \
|
||||||
@ -111,6 +112,7 @@ parameters.
|
|||||||
AssertError, "statement '%s' threw error %s, '%s' but result <%s> expected", \
|
AssertError, "statement '%s' threw error %s, '%s' but result <%s> expected", \
|
||||||
#statement, errorName(), errorMessage(), TEST_RESULT_resultExpectedStr); \
|
#statement, errorName(), errorMessage(), TEST_RESULT_resultExpectedStr); \
|
||||||
} \
|
} \
|
||||||
|
TRY_END(); \
|
||||||
\
|
\
|
||||||
/* Test the type operator */ \
|
/* Test the type operator */ \
|
||||||
bool TEST_RESULT_resultOp = false; \
|
bool TEST_RESULT_resultOp = false; \
|
||||||
|
@ -11,7 +11,7 @@ bool testTryRecurseFinally = false;
|
|||||||
|
|
||||||
void testTryRecurse()
|
void testTryRecurse()
|
||||||
{
|
{
|
||||||
TRY()
|
TRY_BEGIN()
|
||||||
{
|
{
|
||||||
testTryRecurseTotal++;
|
testTryRecurseTotal++;
|
||||||
assert(errorContext.tryTotal == testTryRecurseTotal + 1);
|
assert(errorContext.tryTotal == testTryRecurseTotal + 1);
|
||||||
@ -26,6 +26,7 @@ void testTryRecurse()
|
|||||||
{
|
{
|
||||||
testTryRecurseFinally = true;
|
testTryRecurseFinally = true;
|
||||||
}
|
}
|
||||||
|
TRY_END();
|
||||||
} // {uncoverable - function throws error, never returns}
|
} // {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 tryDone = false;
|
||||||
bool catchDone = false;
|
bool catchDone = false;
|
||||||
bool finallyDone = false;
|
bool finallyDone = false;
|
||||||
|
|
||||||
TRY()
|
TRY_BEGIN()
|
||||||
{
|
{
|
||||||
assert(errorContext.tryTotal == 1);
|
assert(errorContext.tryTotal == 1);
|
||||||
tryDone = true;
|
tryDone = true;
|
||||||
@ -60,6 +61,7 @@ void testRun()
|
|||||||
assert(errorContext.tryList[1].state == errorStateFinal);
|
assert(errorContext.tryList[1].state == errorStateFinal);
|
||||||
finallyDone = true;
|
finallyDone = true;
|
||||||
}
|
}
|
||||||
|
TRY_END();
|
||||||
|
|
||||||
assert(tryDone);
|
assert(tryDone);
|
||||||
assert(!catchDone);
|
assert(!catchDone);
|
||||||
@ -68,31 +70,32 @@ void testRun()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------------------------
|
||||||
if (testBegin("TRY() with multiple catches"))
|
if (testBegin("TRY with multiple catches"))
|
||||||
{
|
{
|
||||||
bool tryDone = false;
|
bool tryDone = false;
|
||||||
bool catchDone = false;
|
bool catchDone = false;
|
||||||
bool finallyDone = false;
|
bool finallyDone = false;
|
||||||
|
|
||||||
TRY()
|
TRY_BEGIN()
|
||||||
{
|
{
|
||||||
assert(errorContext.tryTotal == 1);
|
assert(errorContext.tryTotal == 1);
|
||||||
|
|
||||||
TRY()
|
TRY_BEGIN()
|
||||||
{
|
{
|
||||||
assert(errorContext.tryTotal == 2);
|
assert(errorContext.tryTotal == 2);
|
||||||
|
|
||||||
TRY()
|
TRY_BEGIN()
|
||||||
{
|
{
|
||||||
assert(errorContext.tryTotal == 3);
|
assert(errorContext.tryTotal == 3);
|
||||||
|
|
||||||
TRY()
|
TRY_BEGIN()
|
||||||
{
|
{
|
||||||
assert(errorContext.tryTotal == 4);
|
assert(errorContext.tryTotal == 4);
|
||||||
tryDone = true;
|
tryDone = true;
|
||||||
|
|
||||||
THROW(AssertError, BOGUS_STR);
|
THROW(AssertError, BOGUS_STR);
|
||||||
}
|
}
|
||||||
|
TRY_END();
|
||||||
}
|
}
|
||||||
CATCH(AssertError)
|
CATCH(AssertError)
|
||||||
{
|
{
|
||||||
@ -103,11 +106,13 @@ void testRun()
|
|||||||
{
|
{
|
||||||
finallyDone = true;
|
finallyDone = true;
|
||||||
}
|
}
|
||||||
|
TRY_END();
|
||||||
}
|
}
|
||||||
CATCH_ANY()
|
CATCH_ANY()
|
||||||
{
|
{
|
||||||
RETHROW();
|
RETHROW();
|
||||||
}
|
}
|
||||||
|
TRY_END();
|
||||||
}
|
}
|
||||||
CATCH(MemoryError)
|
CATCH(MemoryError)
|
||||||
{
|
{
|
||||||
@ -120,6 +125,7 @@ void testRun()
|
|||||||
|
|
||||||
catchDone = true;
|
catchDone = true;
|
||||||
}
|
}
|
||||||
|
TRY_END();
|
||||||
|
|
||||||
assert(tryDone);
|
assert(tryDone);
|
||||||
assert(catchDone);
|
assert(catchDone);
|
||||||
@ -134,7 +140,7 @@ void testRun()
|
|||||||
bool catchDone = false;
|
bool catchDone = false;
|
||||||
bool finallyDone = false;
|
bool finallyDone = false;
|
||||||
|
|
||||||
TRY()
|
TRY_BEGIN()
|
||||||
{
|
{
|
||||||
tryDone = true;
|
tryDone = true;
|
||||||
testTryRecurse();
|
testTryRecurse();
|
||||||
@ -155,6 +161,7 @@ void testRun()
|
|||||||
{
|
{
|
||||||
finallyDone = true;
|
finallyDone = true;
|
||||||
}
|
}
|
||||||
|
TRY_END();
|
||||||
|
|
||||||
assert(tryDone);
|
assert(tryDone);
|
||||||
assert(catchDone);
|
assert(catchDone);
|
||||||
|
@ -263,7 +263,7 @@ void testRun()
|
|||||||
memContextTestName = "test-new-failed-block";
|
memContextTestName = "test-new-failed-block";
|
||||||
bool bCatch = false;
|
bool bCatch = false;
|
||||||
|
|
||||||
TRY()
|
TRY_BEGIN()
|
||||||
{
|
{
|
||||||
MEM_CONTEXT_NEW_BEGIN(memContextTestName)
|
MEM_CONTEXT_NEW_BEGIN(memContextTestName)
|
||||||
{
|
{
|
||||||
@ -277,6 +277,7 @@ void testRun()
|
|||||||
{
|
{
|
||||||
bCatch = true;
|
bCatch = true;
|
||||||
}
|
}
|
||||||
|
TRY_END();
|
||||||
|
|
||||||
TEST_RESULT_BOOL(bCatch, true, "new context error was caught");
|
TEST_RESULT_BOOL(bCatch, true, "new context error was caught");
|
||||||
TEST_RESULT_PTR(memContextCurrent(), memContextTop(), "context is now 'TOP'");
|
TEST_RESULT_PTR(memContextCurrent(), memContextTop(), "context is now 'TOP'");
|
||||||
|
Loading…
Reference in New Issue
Block a user