You've already forked pgbackrest
							
							
				mirror of
				https://github.com/pgbackrest/pgbackrest.git
				synced 2025-10-30 23:37:45 +02:00 
			
		
		
		
	Perl error handler recognizes errors thrown from the C library.
This commit is contained in:
		| @@ -336,7 +336,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; | ||||
|   | ||||
| @@ -196,7 +196,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; | ||||
|   | ||||
| @@ -32,6 +32,10 @@ | ||||
|                     <release-item> | ||||
|                         <p>Add C error handler.</p> | ||||
|                     </release-item> | ||||
|  | ||||
|                     <release-item> | ||||
|                         <p>Perl error handler recognizes errors thrown from the C library.</p> | ||||
|                     </release-item> | ||||
|                 </release-refactor-list> | ||||
|             </release-core-list> | ||||
|  | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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); | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -73,7 +73,7 @@ sub exitSafe | ||||
|     if (!defined($iExitCode)) | ||||
|     { | ||||
|         # If a backrest exception | ||||
|         if (isException($oException)) | ||||
|         if (isException(\$oException)) | ||||
|         { | ||||
|             $iExitCode = $oException->code(); | ||||
|             logException($oException); | ||||
|   | ||||
| @@ -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()); | ||||
|         } | ||||
|   | ||||
| @@ -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(); | ||||
|             } | ||||
|   | ||||
| @@ -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())) | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										62
									
								
								libc/LibC.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								libc/LibC.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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();                                                                                                                \ | ||||
|     } | ||||
| @@ -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 | ||||
|  | ||||
|   | ||||
| @@ -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}" : ''); | ||||
|         } | ||||
|   | ||||
| @@ -158,7 +158,7 @@ sub configTestLoadExpect | ||||
|  | ||||
|         $bErrorFound = true; | ||||
|  | ||||
|         if (isException($oException)) | ||||
|         if (isException(\$oException)) | ||||
|         { | ||||
|             if ($oException->code() != $iExpectedError) | ||||
|             { | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user