+ Perl error handler recognizes errors thrown from the C library.
+
diff --git a/lib/pgBackRest/Archive/Info.pm b/lib/pgBackRest/Archive/Info.pm
index dc449904c..233d689f4 100644
--- a/lib/pgBackRest/Archive/Info.pm
+++ b/lib/pgBackRest/Archive/Info.pm
@@ -102,7 +102,7 @@ sub new
{
# Capture error information
$iResult = exceptionCode($EVAL_ERROR);
- $strResultMessage = exceptionMessage($EVAL_ERROR->message());
+ $strResultMessage = exceptionMessage($EVAL_ERROR);
};
if ($iResult != 0)
diff --git a/lib/pgBackRest/Backup/Info.pm b/lib/pgBackRest/Backup/Info.pm
index 0cfcbd6e0..8672e6e52 100644
--- a/lib/pgBackRest/Backup/Info.pm
+++ b/lib/pgBackRest/Backup/Info.pm
@@ -146,7 +146,7 @@ sub new
{
# Capture error information
$iResult = exceptionCode($EVAL_ERROR);
- $strResultMessage = exceptionMessage($EVAL_ERROR->message());
+ $strResultMessage = exceptionMessage($EVAL_ERROR);
};
if ($iResult != 0)
diff --git a/lib/pgBackRest/Check/Check.pm b/lib/pgBackRest/Check/Check.pm
index db51d8150..3b241c7f6 100644
--- a/lib/pgBackRest/Check/Check.pm
+++ b/lib/pgBackRest/Check/Check.pm
@@ -88,7 +88,7 @@ sub process
{
# Capture error information
$iResult = exceptionCode($EVAL_ERROR);
- $strResultMessage = exceptionMessage($EVAL_ERROR->message());
+ $strResultMessage = exceptionMessage($EVAL_ERROR);
};
# Check archive.info
@@ -104,7 +104,7 @@ sub process
{
# Capture error information
$iResult = exceptionCode($EVAL_ERROR);
- $strResultMessage = exceptionMessage($EVAL_ERROR->message());
+ $strResultMessage = exceptionMessage($EVAL_ERROR);
};
}
@@ -123,7 +123,7 @@ sub process
{
# Capture error information
$iResult = exceptionCode($EVAL_ERROR);
- $strResultMessage = exceptionMessage($EVAL_ERROR->message());
+ $strResultMessage = exceptionMessage($EVAL_ERROR);
};
}
diff --git a/lib/pgBackRest/Common/Exception.pm b/lib/pgBackRest/Common/Exception.pm
index debba809a..92450e34f 100644
--- a/lib/pgBackRest/Common/Exception.pm
+++ b/lib/pgBackRest/Common/Exception.pm
@@ -248,15 +248,32 @@ sub trace
}
####################################################################################################################################
-# isException
-#
-# Is this a structured exception?
+# isException - is this a structured exception or a default Perl exception?
####################################################################################################################################
sub isException
{
- my $oException = shift;
+ my $roException = shift;
- return defined($oException) && blessed($oException) && $oException->isa('pgBackRest::Common::Exception') ? 1 : 0;
+ # Only check if defined
+ if (defined($roException) && defined($$roException))
+ {
+ # If a standard Exception
+ if (blessed($$roException))
+ {
+ return $$roException->isa('pgBackRest::Common::Exception') ? 1 : 0;
+ }
+ # Else if a specially formatted string from the C library
+ elsif ($$roException =~ /^PGBRCLIB\:[0-9]+\:/)
+ {
+ my @stryException = split(/\:/, $$roException);
+ $$roException = new pgBackRest::Common::Exception(
+ "ERROR", $stryException[1] + 0, $stryException[4], $stryException[2] . qw{:} . $stryException[3]);
+
+ return 1;
+ }
+ }
+
+ return 0;
}
push @EXPORT, qw(isException);
@@ -270,7 +287,7 @@ sub exceptionCode
{
my $oException = shift;
- return isException($oException) ? $oException->code() : ERROR_UNKNOWN;
+ return isException(\$oException) ? $oException->code() : ERROR_UNKNOWN;
}
push @EXPORT, qw(exceptionCode);
@@ -284,7 +301,7 @@ sub exceptionMessage
{
my $oException = shift;
- return isException($oException) ? $oException->message() : $oException;
+ return isException(\$oException) ? $oException->message() : $oException;
}
push @EXPORT, qw(exceptionMessage);
diff --git a/lib/pgBackRest/Common/Exit.pm b/lib/pgBackRest/Common/Exit.pm
index e6e950c49..4c958a467 100644
--- a/lib/pgBackRest/Common/Exit.pm
+++ b/lib/pgBackRest/Common/Exit.pm
@@ -73,7 +73,7 @@ sub exitSafe
if (!defined($iExitCode))
{
# If a backrest exception
- if (isException($oException))
+ if (isException(\$oException))
{
$iExitCode = $oException->code();
logException($oException);
diff --git a/lib/pgBackRest/Protocol/Base/Minion.pm b/lib/pgBackRest/Protocol/Base/Minion.pm
index 1b8c6c325..692ba01c6 100644
--- a/lib/pgBackRest/Protocol/Base/Minion.pm
+++ b/lib/pgBackRest/Protocol/Base/Minion.pm
@@ -92,7 +92,7 @@ sub errorWrite
my $oException = shift;
# Throw hard error if this is not a standard exception
- if (!isException($oException))
+ if (!isException(\$oException))
{
confess &log(ERROR, 'unknown error: ' . $oException, ERROR_UNKNOWN);
}
@@ -189,7 +189,7 @@ sub process
logLevelSet(undef, undef, PROTOCOL);
# If standard exception
- if (isException($oException))
+ if (isException(\$oException))
{
confess &log($oException->level(), $oException->message(), $oException->code());
}
diff --git a/lib/pgBackRest/Protocol/Command/Master.pm b/lib/pgBackRest/Protocol/Command/Master.pm
index 4afa792f6..ab0ba61b1 100644
--- a/lib/pgBackRest/Protocol/Command/Master.pm
+++ b/lib/pgBackRest/Protocol/Command/Master.pm
@@ -112,7 +112,7 @@ sub close
my $strError = 'unable to shutdown protocol';
my $strHint = 'HINT: the process completed all operations successfully but protocol-timeout may need to be increased.';
- if (isException($oException))
+ if (isException(\$oException))
{
$iExitStatus = $oException->code();
}
diff --git a/lib/pgBackRest/Protocol/Local/Process.pm b/lib/pgBackRest/Protocol/Local/Process.pm
index 77def927e..a2564635c 100644
--- a/lib/pgBackRest/Protocol/Local/Process.pm
+++ b/lib/pgBackRest/Protocol/Local/Process.pm
@@ -334,7 +334,7 @@ sub process
my $oException = $EVAL_ERROR;
# If not a backrest exception then always confess it - something has gone very wrong
- confess $oException if (!isException($oException));
+ confess $oException if (!isException(\$oException));
# If the process is has terminated throw the exception
if (!defined($hLocal->{oLocal}->io()->processId()))
diff --git a/lib/pgBackRest/Stanza.pm b/lib/pgBackRest/Stanza.pm
index 64bd40157..b0a25add2 100644
--- a/lib/pgBackRest/Stanza.pm
+++ b/lib/pgBackRest/Stanza.pm
@@ -322,7 +322,7 @@ sub infoObject
# Reset console logging and capture error information
logEnable();
$iResult = exceptionCode($EVAL_ERROR);
- $strResultMessage = exceptionMessage($EVAL_ERROR->message());
+ $strResultMessage = exceptionMessage($EVAL_ERROR);
};
if ($iResult != 0)
@@ -445,7 +445,7 @@ sub infoFileCreate
# Reset console logging and capture error information
logEnable();
$iResult = exceptionCode($EVAL_ERROR);
- $strResultMessage = exceptionMessage($EVAL_ERROR->message());
+ $strResultMessage = exceptionMessage($EVAL_ERROR);
};
# If we got here without error then save the reconstructed file
diff --git a/libc/LibC.h b/libc/LibC.h
new file mode 100644
index 000000000..80c7dd01e
--- /dev/null
+++ b/libc/LibC.h
@@ -0,0 +1,62 @@
+/***********************************************************************************************************************************
+Helper macros for LibC.xs
+***********************************************************************************************************************************/
+
+/***********************************************************************************************************************************
+Package Names
+***********************************************************************************************************************************/
+#define PACKAGE_NAME "pgBackRest"
+#define PACKAGE_NAME_LIBC PACKAGE_NAME "::LibC"
+
+/***********************************************************************************************************************************
+Load C error into ERROR_SV_error
+
+#define FUNCTION_NAME_ERROR "libcExceptionNew"
+
+#define ERROR_SV() \
+ SV *ERROR_SV_error; \
+ \
+ { \
+ // Push parameters onto the Perl stack \
+ ENTER; \
+ SAVETMPS; \
+ PUSHMARK(SP); \
+ EXTEND(SP, 2); \
+ PUSHs(sv_2mortal(newSViv(errorCode()))); \
+ PUSHs(sv_2mortal(newSVpv(errorMessage(), 0))); \
+ PUTBACK; \
+ \
+ // Call error function \
+ int count = call_pv(PACKAGE_NAME_LIBC "::" FUNCTION_NAME_ERROR, G_SCALAR); \
+ SPAGAIN; \
+ \
+ // Check that correct number of parameters was returned \
+ if (count != 1) \
+ croak("expected 1 return value from " FUNCTION_NAME_ERROR "()"); \
+ \
+ // Make a copy of the error that can be returned \
+ ERROR_SV_error = newSVsv(POPs); \
+ \
+ // Clean up the stack \
+ PUTBACK; \
+ FREETMPS; \
+ LEAVE; \
+ }
+
+This turned out to be a dead end because Perl 5.10 does not support croak_sv(), but this code has been kept for example purposes.
+***********************************************************************************************************************************/
+
+/***********************************************************************************************************************************
+Error handling macros that throw a Perl error when a C error is caught
+***********************************************************************************************************************************/
+#define ERROR_XS_BEGIN() \
+ ERROR_TRY()
+
+#define ERROR_XS() \
+ croak("PGBRCLIB:%d:%s:%d:%s", errorCode(), errorFileName(), errorFileLine(), errorMessage());
+
+#define ERROR_XS_END() \
+ ERROR_CATCH_ANY() \
+ { \
+ ERROR_XS(); \
+ }
diff --git a/libc/LibC.xs b/libc/LibC.xs
index 962c8a182..0ff4e6d95 100644
--- a/libc/LibC.xs
+++ b/libc/LibC.xs
@@ -26,11 +26,15 @@ C includes
These includes are from the src directory. There is no Perl-specific code in them.
***********************************************************************************************************************************/
#include "common/error.h"
-#include "common/type.h"
#include "config/config.h"
#include "config/configRule.h"
#include "postgres/pageChecksum.h"
+/***********************************************************************************************************************************
+Helper macros
+***********************************************************************************************************************************/
+#include "LibC.h"
+
/***********************************************************************************************************************************
Constant include
diff --git a/test/lib/pgBackRestTest/Common/RunTest.pm b/test/lib/pgBackRestTest/Common/RunTest.pm
index 87eb389e3..7d15ab059 100644
--- a/test/lib/pgBackRestTest/Common/RunTest.pm
+++ b/test/lib/pgBackRestTest/Common/RunTest.pm
@@ -344,7 +344,7 @@ sub testResult
# Restore the log level
logLevelSet($strLogLevelFile, $strLogLevelConsole, $strLogLevelStdErr, $bLogTimestamp);
- if (!isException($EVAL_ERROR))
+ if (!isException(\$EVAL_ERROR))
{
confess "unexpected standard Perl exception" . (defined($EVAL_ERROR) ? ": ${EVAL_ERROR}" : '');
}
@@ -421,7 +421,7 @@ sub testException
{
logEnable();
- if (!isException($EVAL_ERROR))
+ if (!isException(\$EVAL_ERROR))
{
confess "${strError} but actual was standard Perl exception" . (defined($EVAL_ERROR) ? ": ${EVAL_ERROR}" : '');
}
diff --git a/test/lib/pgBackRestTest/Env/ConfigEnvTest.pm b/test/lib/pgBackRestTest/Env/ConfigEnvTest.pm
index 62a580d6c..1b1380013 100644
--- a/test/lib/pgBackRestTest/Env/ConfigEnvTest.pm
+++ b/test/lib/pgBackRestTest/Env/ConfigEnvTest.pm
@@ -158,7 +158,7 @@ sub configTestLoadExpect
$bErrorFound = true;
- if (isException($oException))
+ if (isException(\$oException))
{
if ($oException->code() != $iExpectedError)
{
diff --git a/test/test.pl b/test/test.pl
index 3ed64bbae..9927d61cd 100755
--- a/test/test.pl
+++ b/test/test.pl
@@ -968,7 +968,7 @@ eval
or do
{
# If a backrest exception then return the code
- exit $EVAL_ERROR->code() if (isException($EVAL_ERROR));
+ exit $EVAL_ERROR->code() if (isException(\$EVAL_ERROR));
# Else output the unhandled error
syswrite(*STDOUT, $EVAL_ERROR);
diff --git a/test/travis.pl b/test/travis.pl
index 2fdd057e3..c8f3e7a6f 100755
--- a/test/travis.pl
+++ b/test/travis.pl
@@ -181,7 +181,7 @@ eval
or do
{
# If a backrest exception then return the code
- exit $EVAL_ERROR->code() if (isException($EVAL_ERROR));
+ exit $EVAL_ERROR->code() if (isException(\$EVAL_ERROR));
# Else output the unhandled error
print $EVAL_ERROR;