From 95b1391fe3d3192abdfbad4140513b2112cfa02a Mon Sep 17 00:00:00 2001 From: Jon TURNEY Date: Mon, 5 Apr 2010 13:57:24 +0100 Subject: [PATCH] hw/xwin: Chain IOError handlers to avoid longjmp across threads Avoid crashes on shutdown due to the undefined behaviour of calling longjmp() on the result of setjmp() from a different thread, by chaining IOError handlers and only jumping back up to the frame for this thread Signed-off-by: Jon TURNEY Reviewed-by: Colin Harrison --- hw/xwin/winclipboardthread.c | 23 ++++++++++----- hw/xwin/winmultiwindowwm.c | 54 ++++++++++++++++++++++++------------ 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/hw/xwin/winclipboardthread.c b/hw/xwin/winclipboardthread.c index 890a15bc3..bc4bc3059 100644 --- a/hw/xwin/winclipboardthread.c +++ b/hw/xwin/winclipboardthread.c @@ -63,6 +63,8 @@ extern Window g_iClipboardWindow; static jmp_buf g_jmpEntry; static int clipboardRestarts = 0; +static XIOErrorHandler g_winClipboardOldIOErrorHandler; +static pthread_t g_winClipboardProcThread; Bool g_fUnicodeSupport = FALSE; Bool g_fUseUnicode = FALSE; @@ -128,6 +130,11 @@ winClipboardProc (void *pvNotUsed) ErrorF ("winClipboardProc - Warning: Locale not supported by X.\n"); } + /* Set error handler */ + XSetErrorHandler (winClipboardErrorHandler); + g_winClipboardProcThread = pthread_self(); + g_winClipboardOldIOErrorHandler = XSetIOErrorHandler (winClipboardIOErrorHandler); + /* Set jump point for Error exits */ iReturn = setjmp (g_jmpEntry); @@ -150,10 +157,6 @@ winClipboardProc (void *pvNotUsed) /* Use our generated cookie for authentication */ winSetAuthorization(); - /* Set error handler */ - XSetErrorHandler (winClipboardErrorHandler); - XSetIOErrorHandler (winClipboardIOErrorHandler); - /* Initialize retry count */ iRetries = 0; @@ -511,8 +514,14 @@ winClipboardIOErrorHandler (Display *pDisplay) { ErrorF ("winClipboardIOErrorHandler!\n\n"); - /* Restart at the main entry point */ - longjmp (g_jmpEntry, WIN_JMP_ERROR_IO); - + if (pthread_equal(pthread_self(),g_winClipboardProcThread)) + { + /* Restart at the main entry point */ + longjmp (g_jmpEntry, WIN_JMP_ERROR_IO); + } + + if (g_winClipboardOldIOErrorHandler) + g_winClipboardOldIOErrorHandler(pDisplay); + return 0; } diff --git a/hw/xwin/winmultiwindowwm.c b/hw/xwin/winmultiwindowwm.c index 7c4056388..c82ffa5f9 100644 --- a/hw/xwin/winmultiwindowwm.c +++ b/hw/xwin/winmultiwindowwm.c @@ -204,7 +204,11 @@ winUpdateWindowPosition (HWND hWnd, Bool reshape, HWND *zstyle); */ static jmp_buf g_jmpWMEntry; +static XIOErrorHandler g_winMultiWindowWMOldIOErrorHandler; +static pthread_t g_winMultiWindowWMThread; static jmp_buf g_jmpXMsgProcEntry; +static XIOErrorHandler g_winMultiWindowXMsgProcOldIOErrorHandler; +static pthread_t g_winMultiWindowXMsgProcThread; static Bool g_shutdown = FALSE; static Bool redirectError = FALSE; static Bool g_fAnotherWMRunning = FALSE; @@ -901,9 +905,14 @@ winMultiWindowXMsgProc (void *pArg) ErrorF ("winMultiWindowXMsgProc - pthread_mutex_unlock () returned.\n"); + /* Install our error handler */ + XSetErrorHandler (winMultiWindowXMsgProcErrorHandler); + g_winMultiWindowXMsgProcThread = pthread_self(); + g_winMultiWindowXMsgProcOldIOErrorHandler = XSetIOErrorHandler (winMultiWindowXMsgProcIOErrorHandler); + /* Set jump point for IO Error exits */ iReturn = setjmp (g_jmpXMsgProcEntry); - + /* Check if we should continue operations */ if (iReturn != WIN_JMP_ERROR_IO && iReturn != WIN_JMP_OKAY) @@ -919,10 +928,6 @@ winMultiWindowXMsgProc (void *pArg) pthread_exit (NULL); } - /* Install our error handler */ - XSetErrorHandler (winMultiWindowXMsgProcErrorHandler); - XSetIOErrorHandler (winMultiWindowXMsgProcIOErrorHandler); - /* Setup the display connection string x */ snprintf (pszDisplay, 512, "127.0.0.1:%s.%d", display, (int)pProcArg->dwScreen); @@ -1310,9 +1315,14 @@ winInitMultiWindowWM (WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) ErrorF ("winInitMultiWindowWM - pthread_mutex_unlock () returned.\n"); + /* Install our error handler */ + XSetErrorHandler (winMultiWindowWMErrorHandler); + g_winMultiWindowWMThread = pthread_self(); + g_winMultiWindowWMOldIOErrorHandler = XSetIOErrorHandler (winMultiWindowWMIOErrorHandler); + /* Set jump point for IO Error exits */ iReturn = setjmp (g_jmpWMEntry); - + /* Check if we should continue operations */ if (iReturn != WIN_JMP_ERROR_IO && iReturn != WIN_JMP_OKAY) @@ -1328,10 +1338,6 @@ winInitMultiWindowWM (WMInfoPtr pWMInfo, WMProcArgPtr pProcArg) pthread_exit (NULL); } - /* Install our error handler */ - XSetErrorHandler (winMultiWindowWMErrorHandler); - XSetIOErrorHandler (winMultiWindowWMIOErrorHandler); - /* Setup the display connection string x */ snprintf (pszDisplay, 512, @@ -1458,12 +1464,18 @@ winMultiWindowWMIOErrorHandler (Display *pDisplay) { ErrorF ("winMultiWindowWMIOErrorHandler!\n\n"); - if (g_shutdown) - pthread_exit(NULL); + if (pthread_equal(pthread_self(),g_winMultiWindowWMThread)) + { + if (g_shutdown) + pthread_exit(NULL); + + /* Restart at the main entry point */ + longjmp (g_jmpWMEntry, WIN_JMP_ERROR_IO); + } + + if (g_winMultiWindowWMOldIOErrorHandler) + g_winMultiWindowWMOldIOErrorHandler(pDisplay); - /* Restart at the main entry point */ - longjmp (g_jmpWMEntry, WIN_JMP_ERROR_IO); - return 0; } @@ -1498,9 +1510,15 @@ winMultiWindowXMsgProcIOErrorHandler (Display *pDisplay) { ErrorF ("winMultiWindowXMsgProcIOErrorHandler!\n\n"); - /* Restart at the main entry point */ - longjmp (g_jmpXMsgProcEntry, WIN_JMP_ERROR_IO); - + if (pthread_equal(pthread_self(),g_winMultiWindowXMsgProcThread)) + { + /* Restart at the main entry point */ + longjmp (g_jmpXMsgProcEntry, WIN_JMP_ERROR_IO); + } + + if (g_winMultiWindowXMsgProcOldIOErrorHandler) + g_winMultiWindowXMsgProcOldIOErrorHandler(pDisplay); + return 0; }