mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-02-21 19:48:29 +02:00
Use __noreturn_ on error functions when coverage testing.
The errorInternalThrowSys*() functions were marked as returning during coverage testing even when they had no possibility to return, i.e. the error parameter was set to constant true. This meant the compiler would treat the functions as returning even when they would not. Instead create completely separate functions for coverage to use for THROW_ON_SYS_ERROR*() that can return and leave the regular functions marked __noreturn__.
This commit is contained in:
parent
b7d8d61526
commit
f03d1b5b7b
@ -41,6 +41,14 @@
|
||||
|
||||
<p>Split session functionality of <code>SocketClient</code> out into <code>SocketSession</code>.</p>
|
||||
</release-item>
|
||||
|
||||
<release-item>
|
||||
<release-item-contributor-list>
|
||||
<release-item-reviewer id="cynthia.shang"/>
|
||||
</release-item-contributor-list>
|
||||
|
||||
<p>Use <code>__noreturn_</code> on error functions when coverage testing.</p>
|
||||
</release-item>
|
||||
</release-development-list>
|
||||
</release-core-list>
|
||||
</release>
|
||||
|
@ -386,16 +386,8 @@ errorInternalThrowFmt(
|
||||
/**********************************************************************************************************************************/
|
||||
void
|
||||
errorInternalThrowSys(
|
||||
#ifdef DEBUG_COVERAGE
|
||||
bool error,
|
||||
#endif
|
||||
int errNo, const ErrorType *errorType, const char *fileName, const char *functionName, int fileLine, const char *message)
|
||||
{
|
||||
#ifdef DEBUG_COVERAGE
|
||||
if (error)
|
||||
{
|
||||
#endif
|
||||
|
||||
// Format message with system message appended
|
||||
if (errNo == 0)
|
||||
{
|
||||
@ -406,24 +398,23 @@ errorInternalThrowSys(
|
||||
snprintf(messageBufferTemp, ERROR_MESSAGE_BUFFER_SIZE - 1, "%s: [%d] %s", message, errNo, strerror(errNo));
|
||||
|
||||
errorInternalThrow(errorType, fileName, functionName, fileLine, messageBufferTemp);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_COVERAGE
|
||||
}
|
||||
#endif
|
||||
void
|
||||
errorInternalThrowOnSys(
|
||||
bool error, int errNo, const ErrorType *errorType, const char *fileName, const char *functionName, int fileLine,
|
||||
const char *message)
|
||||
{
|
||||
if (error)
|
||||
errorInternalThrowSys(errNo, errorType, fileName, functionName, fileLine, message);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
errorInternalThrowSysFmt(
|
||||
#ifdef DEBUG_COVERAGE
|
||||
bool error,
|
||||
#endif
|
||||
int errNo, const ErrorType *errorType, const char *fileName, const char *functionName, int fileLine, const char *format, ...)
|
||||
{
|
||||
#ifdef DEBUG_COVERAGE
|
||||
if (error)
|
||||
{
|
||||
#endif
|
||||
|
||||
// Format message
|
||||
va_list argument;
|
||||
va_start(argument, format);
|
||||
@ -435,8 +426,30 @@ errorInternalThrowSysFmt(
|
||||
snprintf(messageBufferTemp + messageSize, ERROR_MESSAGE_BUFFER_SIZE - 1 - messageSize, ": [%d] %s", errNo, strerror(errNo));
|
||||
|
||||
errorInternalThrow(errorType, fileName, functionName, fileLine, messageBufferTemp);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_COVERAGE
|
||||
void
|
||||
errorInternalThrowOnSysFmt(
|
||||
bool error, int errNo, const ErrorType *errorType, const char *fileName, const char *functionName, int fileLine,
|
||||
const char *format, ...)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
// Format message
|
||||
va_list argument;
|
||||
va_start(argument, format);
|
||||
size_t messageSize = (size_t)vsnprintf(messageBufferTemp, ERROR_MESSAGE_BUFFER_SIZE - 1, format, argument);
|
||||
va_end(argument);
|
||||
|
||||
// Append the system message
|
||||
if (errNo != 0)
|
||||
{
|
||||
snprintf(
|
||||
messageBufferTemp + messageSize, ERROR_MESSAGE_BUFFER_SIZE - 1 - messageSize, ": [%d] %s", errNo, strerror(errNo));
|
||||
}
|
||||
|
||||
errorInternalThrow(errorType, fileName, functionName, fileLine, messageBufferTemp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
@ -175,18 +175,28 @@ The seldom used "THROWP" variants allow an error to be thrown with a pointer to
|
||||
/***********************************************************************************************************************************
|
||||
Throw an error when a system call fails
|
||||
***********************************************************************************************************************************/
|
||||
// When coverage testing define special versions of the macros that don't contain branches. These macros are less efficient because
|
||||
// they need to call errorInternalThrowSys*() before determining if there is an error or not, but they allow coverage testing for
|
||||
#define THROW_SYS_ERROR(errorType, message) \
|
||||
errorInternalThrowSys(errno, &errorType, __FILE__, __func__, __LINE__, message)
|
||||
#define THROW_SYS_ERROR_FMT(errorType, ...) \
|
||||
errorInternalThrowSysFmt(errno, &errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
#define THROWP_SYS_ERROR(errorType, message) \
|
||||
errorInternalThrowSys(errno, errorType, __FILE__, __func__, __LINE__, message)
|
||||
#define THROWP_SYS_ERROR_FMT(errorType, ...) \
|
||||
errorInternalThrowSysFmt(errno, errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
|
||||
#define THROW_SYS_ERROR_CODE(errNo, errorType, message) \
|
||||
errorInternalThrowSys(errNo, &errorType, __FILE__, __func__, __LINE__, message)
|
||||
#define THROW_SYS_ERROR_CODE_FMT(errNo, errorType, ...) \
|
||||
errorInternalThrowSysFmt(errNo, &errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
#define THROWP_SYS_ERROR_CODE(errNo, errorType, message) \
|
||||
errorInternalThrowSys(errNo, errorType, __FILE__, __func__, __LINE__, message)
|
||||
#define THROWP_SYS_ERROR_CODE_FMT(errNo, errorType, ...) \
|
||||
errorInternalThrowSysFmt(errNo, errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
|
||||
// When coverage testing, define special versions of the macros that don't contain branches. These macros are less efficient because
|
||||
// they need to call errorInternalThrowOnSys*() before determining if there is an error or not, but they allow coverage testing for
|
||||
// THROW*_ON*() calls that contain conditionals.
|
||||
#ifdef DEBUG_COVERAGE
|
||||
#define THROW_SYS_ERROR(errorType, message) \
|
||||
errorInternalThrowSys(true, errno, &errorType, __FILE__, __func__, __LINE__, message)
|
||||
#define THROW_SYS_ERROR_FMT(errorType, ...) \
|
||||
errorInternalThrowSysFmt(true, errno, &errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
#define THROWP_SYS_ERROR(errorType, message) \
|
||||
errorInternalThrowSys(true, errno, errorType, __FILE__, __func__, __LINE__, message)
|
||||
#define THROWP_SYS_ERROR_FMT(errorType, ...) \
|
||||
errorInternalThrowSysFmt(true, errno, errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
|
||||
// The expression can't be passed directly to errorInternalThrowSys*() because we need to be sure it is evaluated before passing
|
||||
// errno. Depending on optimization that might not happen.
|
||||
@ -194,50 +204,32 @@ Throw an error when a system call fails
|
||||
do \
|
||||
{ \
|
||||
bool error = expression; \
|
||||
errorInternalThrowSys(error, errno, &errorType, __FILE__, __func__, __LINE__, message); \
|
||||
errorInternalThrowOnSys(error, errno, &errorType, __FILE__, __func__, __LINE__, message); \
|
||||
} while(0)
|
||||
|
||||
#define THROW_ON_SYS_ERROR_FMT(expression, errorType, ...) \
|
||||
do \
|
||||
{ \
|
||||
bool error = expression; \
|
||||
errorInternalThrowSysFmt(error, errno, &errorType, __FILE__, __func__, __LINE__, __VA_ARGS__); \
|
||||
errorInternalThrowOnSysFmt(error, errno, &errorType, __FILE__, __func__, __LINE__, __VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
#define THROWP_ON_SYS_ERROR(expression, errorType, message) \
|
||||
do \
|
||||
{ \
|
||||
bool error = expression; \
|
||||
errorInternalThrowSys(error, errno, errorType, __FILE__, __func__, __LINE__, message); \
|
||||
errorInternalThrowOnSys(error, errno, errorType, __FILE__, __func__, __LINE__, message); \
|
||||
} while(0)
|
||||
|
||||
#define THROWP_ON_SYS_ERROR_FMT(expression, errorType, ...) \
|
||||
do \
|
||||
{ \
|
||||
bool error = expression; \
|
||||
errorInternalThrowSysFmt(error, errno, errorType, __FILE__, __func__, __LINE__, __VA_ARGS__); \
|
||||
errorInternalThrowOnSysFmt(error, errno, errorType, __FILE__, __func__, __LINE__, __VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
#define THROW_SYS_ERROR_CODE(errNo, errorType, message) \
|
||||
errorInternalThrowSys(true, errNo, &errorType, __FILE__, __func__, __LINE__, message)
|
||||
#define THROW_SYS_ERROR_CODE_FMT(errNo, errorType, ...) \
|
||||
errorInternalThrowSysFmt(true, errNo, &errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
#define THROWP_SYS_ERROR_CODE(errNo, errorType, message) \
|
||||
errorInternalThrowSys(true, errNo, errorType, __FILE__, __func__, __LINE__, message)
|
||||
#define THROWP_SYS_ERROR_CODE_FMT(errNo, errorType, ...) \
|
||||
errorInternalThrowSysFmt(true, errNo, errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
|
||||
// Else define the normal macros which check for an error first
|
||||
#else
|
||||
#define THROW_SYS_ERROR(errorType, message) \
|
||||
errorInternalThrowSys(errno, &errorType, __FILE__, __func__, __LINE__, message)
|
||||
#define THROW_SYS_ERROR_FMT(errorType, ...) \
|
||||
errorInternalThrowSysFmt(errno, &errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
#define THROWP_SYS_ERROR(errorType, message) \
|
||||
errorInternalThrowSys(errno, errorType, __FILE__, __func__, __LINE__, message)
|
||||
#define THROWP_SYS_ERROR_FMT(errorType, ...) \
|
||||
errorInternalThrowSysFmt(errno, errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
|
||||
#define THROW_ON_SYS_ERROR(expression, errorType, message) \
|
||||
do \
|
||||
{ \
|
||||
@ -265,15 +257,6 @@ Throw an error when a system call fails
|
||||
if (expression) \
|
||||
errorInternalThrowSysFmt(errno, errorType, __FILE__, __func__, __LINE__, __VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
#define THROW_SYS_ERROR_CODE(errNo, errorType, message) \
|
||||
errorInternalThrowSys(errNo, &errorType, __FILE__, __func__, __LINE__, message)
|
||||
#define THROW_SYS_ERROR_CODE_FMT(errNo, errorType, ...) \
|
||||
errorInternalThrowSysFmt(errNo, &errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
#define THROWP_SYS_ERROR_CODE(errNo, errorType, message) \
|
||||
errorInternalThrowSys(errNo, errorType, __FILE__, __func__, __LINE__, message)
|
||||
#define THROWP_SYS_ERROR_CODE_FMT(errNo, errorType, ...) \
|
||||
errorInternalThrowSysFmt(errNo, errorType, __FILE__, __func__, __LINE__, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@ -318,25 +301,23 @@ void errorInternalThrowFmt(
|
||||
|
||||
// Throw a system error
|
||||
void errorInternalThrowSys(
|
||||
#ifdef DEBUG_COVERAGE
|
||||
bool error,
|
||||
#endif
|
||||
int errNo, const ErrorType *errorType, const char *fileName, const char *functionName, int fileLine, const char *message)
|
||||
#ifdef DEBUG_COVERAGE
|
||||
;
|
||||
#else
|
||||
__attribute__((__noreturn__));
|
||||
#endif
|
||||
|
||||
// Throw a formatted system error
|
||||
void errorInternalThrowSysFmt(
|
||||
#ifdef DEBUG_COVERAGE
|
||||
bool error,
|
||||
#endif
|
||||
int errNo, const ErrorType *errorType, const char *fileName, const char *functionName, int fileLine, const char *format, ...)
|
||||
#ifdef DEBUG_COVERAGE
|
||||
__attribute__((format(printf, 7, 8)));
|
||||
#else
|
||||
__attribute__((format(printf, 6, 7))) __attribute__((__noreturn__));
|
||||
|
||||
// Versions of the above for coverage testing which checks the error condition inside the function
|
||||
#ifdef DEBUG_COVERAGE
|
||||
void errorInternalThrowOnSys(
|
||||
bool error, int errNo, const ErrorType *errorType, const char *fileName, const char *functionName, int fileLine,
|
||||
const char *message);
|
||||
|
||||
void errorInternalThrowOnSysFmt(
|
||||
bool error, int errNo, const ErrorType *errorType, const char *fileName, const char *functionName, int fileLine,
|
||||
const char *format, ...) __attribute__((format(printf, 7, 8)));
|
||||
#endif
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
|
@ -261,7 +261,7 @@ testRun(void)
|
||||
TRY_BEGIN()
|
||||
{
|
||||
errno = E2BIG;
|
||||
THROW_SYS_ERROR(AssertError, "message");
|
||||
THROW_ON_SYS_ERROR(true, AssertError, "message");
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
@ -271,6 +271,34 @@ testRun(void)
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TRY_BEGIN()
|
||||
{
|
||||
errno = 0;
|
||||
THROW_ON_SYS_ERROR_FMT(true, AssertError, "message %d", 77);
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
printf("%s\n", errorMessage());
|
||||
assert(errorCode() == AssertError.code);
|
||||
assert(strcmp(errorMessage(), "message 77") == 0);
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TRY_BEGIN()
|
||||
{
|
||||
errno = E2BIG;
|
||||
THROW_ON_SYS_ERROR_FMT(true, AssertError, "message %d", 77);
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
printf("%s\n", errorMessage());
|
||||
assert(errorCode() == AssertError.code);
|
||||
assert(strcmp(errorMessage(), "message 77: [7] Argument list too long") == 0);
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TRY_BEGIN()
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user