From 244956f090b3f46570f6b0ddacf50118b187a7e6 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 17 Mar 2023 21:01:56 +0100 Subject: [PATCH] python_exceptions.i: revise logic to use Push/PopErrorHandler instead of setting a global error handler --- swig/include/python/python_exceptions.i | 94 +++++++++++++------------ 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/swig/include/python/python_exceptions.i b/swig/include/python/python_exceptions.i index a2bfb9436d63..a5b1251ae5b0 100644 --- a/swig/include/python/python_exceptions.i +++ b/swig/include/python/python_exceptions.i @@ -5,6 +5,7 @@ */ %{ static int bUseExceptions=0; +static void* pPreviousHandlerUserData = NULL; static CPLErrorHandler pfnPreviousHandler = CPLDefaultErrorHandler; static void CPL_STDCALL @@ -58,14 +59,6 @@ void UseExceptions() { if( !bUseExceptions ) { bUseExceptions = 1; - char* pszNewValue = CPLStrdup(CPLSPrintf("%s %s", - MODULE_NAME, - CPLGetConfigOption("__chain_python_error_handlers", ""))); - CPLSetConfigOption("__chain_python_error_handlers", pszNewValue); - CPLFree(pszNewValue); - // if the previous logger was custom, we need the user data available - pfnPreviousHandler = - CPLSetErrorHandlerEx( (CPLErrorHandler) PythonBindingErrorHandler, CPLGetErrorHandlerUserData() ); } } @@ -74,26 +67,7 @@ void DontUseExceptions() { CPLErrorReset(); if( bUseExceptions ) { - const char* pszValue = CPLGetConfigOption("__chain_python_error_handlers", ""); - if( strncmp(pszValue, MODULE_NAME, strlen(MODULE_NAME)) != 0 || - pszValue[strlen(MODULE_NAME)] != ' ') - { - CPLError(CE_Failure, CPLE_NotSupported, - "Cannot call %s.DontUseExceptions() at that point since the " - "stack of error handlers is: %s", MODULE_NAME, pszValue); - return; - } - char* pszNewValue = CPLStrdup(pszValue + strlen(MODULE_NAME) + 1); - if( pszNewValue[0] == ' ' && pszNewValue[1] == '\0' ) - { - CPLFree(pszNewValue); - pszNewValue = NULL; - } - CPLSetConfigOption("__chain_python_error_handlers", pszNewValue); - CPLFree(pszNewValue); bUseExceptions = 0; - // if the previous logger was custom, we need the user data available. Preserve it. - CPLSetErrorHandlerEx( pfnPreviousHandler, CPLGetErrorHandlerUserData()); } } %} @@ -124,7 +98,6 @@ static void ClearErrorState() static void StoreLastException() CPL_UNUSED; -// Note: this is also copy&pasted in gdal_array.i static void StoreLastException() { const char* pszLastErrorMessage = @@ -139,18 +112,39 @@ static void StoreLastException() } } +static void pushErrorHandler() +{ + ClearErrorState(); + pfnPreviousHandler = CPLGetErrorHandler(&pPreviousHandlerUserData); + if(pfnPreviousHandler == PythonBindingErrorHandler) + { + fprintf(stderr, "BUG: pushErrorHandler(): previous handler is PythonBindingErrorHandler\n"); + // to avoid infinite recursion + pfnPreviousHandler = CPLDefaultErrorHandler; + } + CPLPushErrorHandlerEx(PythonBindingErrorHandler, pPreviousHandlerUserData); +} + +static void popErrorHandler() +{ + CPLPopErrorHandler(); +} + %} %include exception.i %exception { - - if ( bUseExceptions ) { - ClearErrorState(); + const int bLocalUseExceptions = bUseExceptions; + if ( bLocalUseExceptions ) { + pushErrorHandler(); } $action + if ( bLocalUseExceptions ) { + popErrorHandler(); + } %#ifndef SED_HACKS - if ( bUseExceptions ) { + if ( bLocalUseExceptions ) { CPLErr eclass = CPLGetLastErrorType(); if ( eclass == CE_Failure || eclass == CE_Fatal ) { SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() ); @@ -160,19 +154,23 @@ static void StoreLastException() } %feature("except") Open { - if ( bUseExceptions ) { - ClearErrorState(); + const int bLocalUseExceptions = bUseExceptions; + if ( bLocalUseExceptions ) { + pushErrorHandler(); } $action + if ( bLocalUseExceptions ) { + popErrorHandler(); + } %#ifndef SED_HACKS - if( result == NULL && bUseExceptions ) { + if( result == NULL && bLocalUseExceptions ) { CPLErr eclass = CPLGetLastErrorType(); if ( eclass == CE_Failure || eclass == CE_Fatal ) { SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() ); } } %#endif - if( result != NULL && bUseExceptions ) { + if( result != NULL && bLocalUseExceptions ) { StoreLastException(); %#ifdef SED_HACKS bLocalUseExceptionsCode = FALSE; @@ -181,19 +179,23 @@ static void StoreLastException() } %feature("except") OpenShared { - if ( bUseExceptions ) { - ClearErrorState(); + const int bLocalUseExceptions = bUseExceptions; + if ( bLocalUseExceptions ) { + pushErrorHandler(); } $action + if ( bLocalUseExceptions ) { + popErrorHandler(); + } %#ifndef SED_HACKS - if( result == NULL && bUseExceptions ) { + if( result == NULL && bLocalUseExceptions ) { CPLErr eclass = CPLGetLastErrorType(); if ( eclass == CE_Failure || eclass == CE_Fatal ) { SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() ); } } %#endif - if( result != NULL && bUseExceptions ) { + if( result != NULL && bLocalUseExceptions ) { StoreLastException(); %#ifdef SED_HACKS bLocalUseExceptionsCode = FALSE; @@ -202,19 +204,23 @@ static void StoreLastException() } %feature("except") OpenEx { - if ( bUseExceptions ) { - ClearErrorState(); + const int bLocalUseExceptions = bUseExceptions; + if ( bLocalUseExceptions ) { + pushErrorHandler(); } $action + if ( bLocalUseExceptions ) { + popErrorHandler(); + } %#ifndef SED_HACKS - if( result == NULL && bUseExceptions ) { + if( result == NULL && bLocalUseExceptions ) { CPLErr eclass = CPLGetLastErrorType(); if ( eclass == CE_Failure || eclass == CE_Fatal ) { SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() ); } } %#endif - if( result != NULL && bUseExceptions ) { + if( result != NULL && bLocalUseExceptions ) { StoreLastException(); %#ifdef SED_HACKS bLocalUseExceptionsCode = FALSE;