xref: /AOO41X/main/sal/osl/w32/signal.cxx (revision e1c63fd964ba130fb7c33234fe0d975ac26c34e8)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 /* system headers */
25 #include "system.h"
26 #include <tchar.h>
27 
28 #include "file_url.h"
29 #include "path_helper.hxx"
30 
31 #include <osl/diagnose.h>
32 #include <osl/mutex.h>
33 #include <osl/signal.h>
34 #ifndef __MINGW32__
35 #include <DbgHelp.h>
36 #endif
37 #include <ErrorRep.h>
38 #include <systools/win32/uwinapi.h>
39 #include <eh.h>
40 #include <stdexcept>
41 
42 typedef struct _oslSignalHandlerImpl
43 {
44     oslSignalHandlerFunction      Handler;
45     void*                         pData;
46     struct _oslSignalHandlerImpl* pNext;
47 } oslSignalHandlerImpl;
48 
49 static sal_Bool               bErrorReportingEnabled = sal_True;
50 static sal_Bool               bInitSignal = sal_False;
51 static oslMutex               SignalListMutex;
52 static oslSignalHandlerImpl*  SignalList;
53 
54 static long WINAPI SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP);
55 
56 static _invalid_parameter_handler pPreviousInvalidParameterHandler = NULL;
57 static void InvalidParameterHandlerFunction(
58     const wchar_t* expression,
59     const wchar_t* function,
60     const wchar_t* file,
61     unsigned int line,
62     uintptr_t pReserved );
63 
InitSignal(void)64 static sal_Bool InitSignal(void)
65 {
66     HMODULE hFaultRep;
67 
68     SignalListMutex = osl_createMutex();
69 
70     SetUnhandledExceptionFilter(SignalHandlerFunction);
71     if ( pPreviousInvalidParameterHandler == NULL )
72     {
73         pPreviousInvalidParameterHandler = _set_invalid_parameter_handler( InvalidParameterHandlerFunction );
74     }
75 
76     hFaultRep = LoadLibrary( "faultrep.dll" );
77     if ( hFaultRep )
78     {
79 #ifdef __MINGW32__
80 typedef BOOL (WINAPI *pfn_ADDEREXCLUDEDAPPLICATIONW)(LPCWSTR);
81 #endif
82         pfn_ADDEREXCLUDEDAPPLICATIONW       pfn = (pfn_ADDEREXCLUDEDAPPLICATIONW)GetProcAddress( hFaultRep, "AddERExcludedApplicationW" );
83         if ( pfn )
84             pfn( L"SOFFICE.EXE" );
85         FreeLibrary( hFaultRep );
86     }
87 
88     return sal_True;
89 }
90 
DeInitSignal(void)91 static sal_Bool DeInitSignal(void)
92 {
93     SetUnhandledExceptionFilter(NULL);
94 
95     if ( pPreviousInvalidParameterHandler )
96     {
97         _set_invalid_parameter_handler( pPreviousInvalidParameterHandler );
98         pPreviousInvalidParameterHandler = NULL;
99     }
100     osl_destroyMutex(SignalListMutex);
101 
102     return sal_False;
103 }
104 
CallSignalHandler(oslSignalInfo * pInfo)105 static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo)
106 {
107     oslSignalHandlerImpl* pHandler = SignalList;
108     oslSignalAction Action = osl_Signal_ActCallNextHdl;
109 
110     while (pHandler != NULL)
111     {
112         if ((Action = pHandler->Handler(pHandler->pData, pInfo)) != osl_Signal_ActCallNextHdl)
113             break;
114 
115         pHandler = pHandler->pNext;
116     }
117 
118     return Action;
119 }
120 
121 /*****************************************************************************/
122 /* SignalHandlerFunction    */
123 /*****************************************************************************/
124 
125 #define REPORTENV_PARAM     "-crashreportenv:"
126 #define REPORTENV_PARAM2    "/crashreportenv:"
127 
ReportCrash(LPEXCEPTION_POINTERS lpEP)128 static BOOL ReportCrash( LPEXCEPTION_POINTERS lpEP )
129 {
130     BOOL    fSuccess = FALSE;
131     BOOL    fAutoReport = FALSE;
132     TCHAR   szBuffer[1024];
133     ::osl::LongPathBuffer< sal_Char > aPath( MAX_LONG_PATH );
134     LPTSTR  lpFilePart;
135     PROCESS_INFORMATION ProcessInfo;
136     STARTUPINFO StartupInfo;
137     int     argi;
138 
139     if ( !bErrorReportingEnabled )
140         return FALSE;
141 
142     /* Check if crash reporter was disabled by command line */
143 
144     for ( argi = 1; argi < __argc; argi++ )
145     {
146         if (
147             0 == stricmp( __argv[argi], "-nocrashreport" ) ||
148             0 == stricmp( __argv[argi], "/nocrashreport" )
149             )
150             return FALSE;
151         else if (
152             0 == stricmp( __argv[argi], "-autocrashreport" ) ||
153             0 == stricmp( __argv[argi], "/autocrashreport" )
154             )
155             fAutoReport = TRUE;
156         else if (
157             0 == strnicmp( __argv[argi], REPORTENV_PARAM, strlen(REPORTENV_PARAM) ) ||
158             0 == strnicmp( __argv[argi], REPORTENV_PARAM2, strlen(REPORTENV_PARAM2) )
159             )
160         {
161             const char *envparam = __argv[argi] + strlen(REPORTENV_PARAM);
162             const char *delim = strchr(envparam, '=' );
163 
164             if ( delim )
165             {
166                 CHAR    *lpVariable;
167                 CHAR    *lpValue;
168                 const char *variable = envparam;
169                 size_t variable_len = delim - envparam;
170                 const char *value = delim + 1;
171                 size_t value_len = strlen(envparam) - variable_len - 1;
172 
173                 if ( '\"' == *value )
174                 {
175                     const char *quote;
176 
177                     value++;
178                     value_len--;
179 
180                     quote = strchr( value, '\"' );
181                     if ( quote )
182                         value_len = quote - value;
183                 }
184 
185                 lpVariable = reinterpret_cast< CHAR* >( _alloca( variable_len + 1 ) );
186                 memcpy( lpVariable, variable, variable_len );
187                 lpVariable[variable_len] = 0;
188 
189                 lpValue = reinterpret_cast< CHAR* >( _alloca( value_len + 1) );
190                 memcpy( lpValue, value, value_len );
191                 lpValue[value_len] = 0;
192 
193                 SetEnvironmentVariable( lpVariable, lpValue );
194             }
195         }
196     }
197 
198     if ( SearchPath( NULL, TEXT( "crashrep.exe" ), NULL, aPath.getBufSizeInSymbols(), aPath, &lpFilePart ) )
199     {
200         ZeroMemory( &StartupInfo, sizeof(StartupInfo) );
201         StartupInfo.cb = sizeof(StartupInfo.cb);
202 
203 
204         sntprintf( szBuffer, elementsof(szBuffer),
205             _T("%s -p %u -excp 0x%p -t %u%s"),
206             static_cast<sal_Char*>( aPath ),
207             GetCurrentProcessId(),
208             lpEP,
209             GetCurrentThreadId(),
210             fAutoReport ? _T(" -noui -send") : _T(" -noui") );
211 
212         if (
213             CreateProcess(
214                 NULL,
215                 szBuffer,
216                 NULL,
217                 NULL,
218                 FALSE,
219 #ifdef UNICODE
220                 CREATE_UNICODE_ENVIRONMENT,
221 #else
222                 0,
223 #endif
224                 NULL, NULL, &StartupInfo, &ProcessInfo )
225             )
226         {
227             DWORD   dwExitCode;
228 
229             WaitForSingleObject( ProcessInfo.hProcess, INFINITE );
230             if ( GetExitCodeProcess( ProcessInfo.hProcess, &dwExitCode ) && 0 == dwExitCode )
231 
232             fSuccess = TRUE;
233 
234         }
235     }
236 
237     return fSuccess;
238 }
239 
240 /*****************************************************************************/
241 /* SignalHandlerFunction    */
242 /*****************************************************************************/
243 
IsWin95A(void)244 static BOOL WINAPI IsWin95A(void)
245 {
246     OSVERSIONINFO   ovi;
247 
248     ZeroMemory( &ovi, sizeof(ovi) );
249     ovi.dwOSVersionInfoSize = sizeof(ovi);
250 
251     if ( GetVersionEx( &ovi ) )
252         /* See MSDN January 2000 documentation of GetVersionEx */
253         return  (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) &&
254                 (ovi.dwMajorVersion <= 4) &&
255                 (ovi.dwMinorVersion == 0) &&
256                 (ovi.dwBuildNumber == 0x040003B6);
257 
258     /* Something wrent wrong. So assume we have an older operating prior Win95 */
259 
260     return TRUE;
261 }
262 
263 /* magic Microsoft C++ compiler exception constant */
264 #define EXCEPTION_MSC_CPP_EXCEPTION 0xe06d7363
265 
SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP)266 static long WINAPI SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP)
267 {
268     static sal_Bool     bNested = sal_False;
269     sal_Bool        bRaiseCrashReporter = sal_False;
270     oslSignalInfo   Info;
271     oslSignalAction Action;
272 
273     Info.UserSignal = lpEP->ExceptionRecord->ExceptionCode;
274     Info.UserData   = NULL;
275 
276     switch (lpEP->ExceptionRecord->ExceptionCode)
277     {
278         /* Transform unhandled exceptions into access violations.
279            Microsoft C++ compiler (add more for other compilers if necessary).
280          */
281         case EXCEPTION_MSC_CPP_EXCEPTION:
282         case EXCEPTION_ACCESS_VIOLATION:
283             Info.Signal = osl_Signal_AccessViolation;
284             bRaiseCrashReporter = sal_True;
285             break;
286 
287         case EXCEPTION_INT_DIVIDE_BY_ZERO:
288             Info.Signal = osl_Signal_IntegerDivideByZero;
289             bRaiseCrashReporter = sal_True;
290             break;
291 
292         case EXCEPTION_FLT_DIVIDE_BY_ZERO:
293             Info.Signal = osl_Signal_FloatDivideByZero;
294             bRaiseCrashReporter = sal_True;
295             break;
296 
297         case EXCEPTION_BREAKPOINT:
298             Info.Signal = osl_Signal_DebugBreak;
299             break;
300 
301         default:
302             Info.Signal = osl_Signal_System;
303             bRaiseCrashReporter = sal_True;
304             break;
305     }
306 
307     if ( !bNested )
308     {
309         bNested = sal_True;
310 
311         if ( bRaiseCrashReporter && ReportCrash( lpEP ) || IsWin95A() )
312         {
313             CallSignalHandler(&Info);
314             Action = osl_Signal_ActKillApp;
315         }
316         else
317             Action = CallSignalHandler(&Info);
318     }
319     else
320         Action = osl_Signal_ActKillApp;
321 
322 
323     switch ( Action )
324     {
325         case osl_Signal_ActCallNextHdl:
326             return (EXCEPTION_CONTINUE_SEARCH);
327 
328         case osl_Signal_ActAbortApp:
329             return (EXCEPTION_EXECUTE_HANDLER);
330 
331         case osl_Signal_ActKillApp:
332             SetErrorMode(SEM_NOGPFAULTERRORBOX);
333             exit(255);
334             break;
335         default:
336             break;
337     }
338 
339     return (EXCEPTION_CONTINUE_EXECUTION);
340 }
341 
InvalidParameterHandlerFunction(const wchar_t * expression,const wchar_t * function,const wchar_t * file,unsigned int line,uintptr_t pReserved)342 static void InvalidParameterHandlerFunction(
343     const wchar_t* expression,
344     const wchar_t* function,
345     const wchar_t* file,
346     unsigned int line,
347     uintptr_t pReserved )
348 {
349     oslSignalInfo   Info;
350 
351     fwprintf(stderr, L"Invalid parameter detected in function %s.\n"
352              L"File: %s\n"
353              L"Line: %u\n"
354              L"Expression: %s\n"
355              L"pReserved: %p\n", function, file, line, expression, pReserved);
356 
357     Info.Signal = osl_Signal_AccessViolation;
358     Info.UserSignal = 0;
359     Info.UserData = NULL;
360     if ( ReportCrash( NULL ) || IsWin95A() )
361     {
362         CallSignalHandler(&Info);
363         abort(); // Equivalent of osl_Signal_ActAbortApp
364     } else {
365         // Equivalent of osl_Signal_ActKillApp
366         SetErrorMode(SEM_NOGPFAULTERRORBOX);
367         exit(255);
368     }
369     // We will never reach this point
370 }
371 
372 /*****************************************************************************/
373 /* osl_addSignalHandler */
374 /*****************************************************************************/
osl_addSignalHandler(oslSignalHandlerFunction Handler,void * pData)375 oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData)
376 {
377     oslSignalHandlerImpl* pHandler;
378 
379     OSL_ASSERT(Handler != NULL);
380 
381     if (! bInitSignal)
382         bInitSignal = InitSignal();
383 
384     pHandler = reinterpret_cast< oslSignalHandlerImpl* >( calloc( 1, sizeof(oslSignalHandlerImpl) ) );
385 
386     if (pHandler != NULL)
387     {
388         pHandler->Handler = Handler;
389         pHandler->pData   = pData;
390 
391         osl_acquireMutex(SignalListMutex);
392 
393         pHandler->pNext = SignalList;
394         SignalList      = pHandler;
395 
396         osl_releaseMutex(SignalListMutex);
397 
398         return (pHandler);
399     }
400 
401     return (NULL);
402 }
403 
404 /*****************************************************************************/
405 /* osl_removeSignalHandler */
406 /*****************************************************************************/
osl_removeSignalHandler(oslSignalHandler Handler)407 sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler)
408 {
409     oslSignalHandlerImpl *pHandler, *pPrevious = NULL;
410 
411     OSL_ASSERT(Handler != NULL);
412 
413     if (! bInitSignal)
414         bInitSignal = InitSignal();
415 
416     osl_acquireMutex(SignalListMutex);
417 
418     pHandler = SignalList;
419 
420     while (pHandler != NULL)
421     {
422         if (pHandler == Handler)
423         {
424             if (pPrevious)
425                 pPrevious->pNext = pHandler->pNext;
426             else
427                 SignalList = pHandler->pNext;
428 
429             osl_releaseMutex(SignalListMutex);
430 
431             if (SignalList == NULL)
432                 bInitSignal = DeInitSignal();
433 
434             free(pHandler);
435 
436             return (sal_True);
437         }
438 
439         pPrevious = pHandler;
440         pHandler  = pHandler->pNext;
441     }
442 
443     osl_releaseMutex(SignalListMutex);
444 
445     return (sal_False);
446 }
447 
448 /*****************************************************************************/
449 /* osl_raiseSignal */
450 /*****************************************************************************/
osl_raiseSignal(sal_Int32 UserSignal,void * UserData)451 oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData)
452 {
453     oslSignalInfo   Info;
454     oslSignalAction Action;
455 
456     if (! bInitSignal)
457         bInitSignal = InitSignal();
458 
459     osl_acquireMutex(SignalListMutex);
460 
461     Info.Signal     = osl_Signal_User;
462     Info.UserSignal = UserSignal;
463     Info.UserData   = UserData;
464 
465     Action = CallSignalHandler(&Info);
466 
467     osl_releaseMutex(SignalListMutex);
468 
469     return (Action);
470 }
471 
472 /*****************************************************************************/
473 /* osl_setErrorReporting */
474 /*****************************************************************************/
475 
win_seh_translator(unsigned nSEHCode,_EXCEPTION_POINTERS * pExcPtrs)476 void win_seh_translator( unsigned nSEHCode, _EXCEPTION_POINTERS* pExcPtrs)
477 {
478     (void*)pExcPtrs; // currently unused, but useful inside a debugger
479     const char* pSEHName = NULL;
480     switch( nSEHCode)
481     {
482         case EXCEPTION_ACCESS_VIOLATION:         pSEHName = "SEH Exception: ACCESS VIOLATION"; break;
483         case EXCEPTION_DATATYPE_MISALIGNMENT:    pSEHName = "SEH Exception: DATATYPE MISALIGNMENT"; break;
484         case EXCEPTION_BREAKPOINT:               /*pSEHName = "SEH Exception: BREAKPOINT";*/ break;
485         case EXCEPTION_SINGLE_STEP:              /*pSEHName = "SEH Exception: SINGLE STEP";*/ break;
486         case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:    pSEHName = "SEH Exception: ARRAY BOUNDS EXCEEDED"; break;
487         case EXCEPTION_FLT_DENORMAL_OPERAND:     pSEHName = "SEH Exception: DENORMAL FLOAT OPERAND"; break;
488         case EXCEPTION_FLT_DIVIDE_BY_ZERO:       pSEHName = "SEH Exception: FLOAT DIVIDE_BY_ZERO"; break;
489         case EXCEPTION_FLT_INEXACT_RESULT:       pSEHName = "SEH Exception: FLOAT INEXACT RESULT"; break;
490         case EXCEPTION_FLT_INVALID_OPERATION:    pSEHName = "SEH Exception: INVALID FLOAT OPERATION"; break;
491         case EXCEPTION_FLT_OVERFLOW:             pSEHName = "SEH Exception: FLOAT OVERFLOW"; break;
492         case EXCEPTION_FLT_STACK_CHECK:          pSEHName = "SEH Exception: FLOAT STACK_CHECK"; break;
493         case EXCEPTION_FLT_UNDERFLOW:            pSEHName = "SEH Exception: FLOAT UNDERFLOW"; break;
494         case EXCEPTION_INT_DIVIDE_BY_ZERO:       pSEHName = "SEH Exception: INTEGER DIVIDE_BY_ZERO"; break;
495         case EXCEPTION_INT_OVERFLOW:             pSEHName = "SEH Exception: INTEGER OVERFLOW"; break;
496         case EXCEPTION_PRIV_INSTRUCTION:         pSEHName = "SEH Exception: PRIVILEDGED INSTRUCTION"; break;
497         case EXCEPTION_IN_PAGE_ERROR:            pSEHName = "SEH Exception: IN_PAGE_ERROR"; break;
498         case EXCEPTION_ILLEGAL_INSTRUCTION:      pSEHName = "SEH Exception: ILLEGAL INSTRUCTION"; break;
499         case EXCEPTION_NONCONTINUABLE_EXCEPTION: pSEHName = "SEH Exception: NONCONTINUABLE EXCEPTION"; break;
500         case EXCEPTION_STACK_OVERFLOW:           pSEHName = "SEH Exception: STACK OVERFLOW"; break;
501         case EXCEPTION_INVALID_DISPOSITION:      pSEHName = "SEH Exception: INVALID DISPOSITION"; break;
502         case EXCEPTION_GUARD_PAGE:               pSEHName = "SEH Exception: GUARD PAGE"; break;
503         case EXCEPTION_INVALID_HANDLE:           pSEHName = "SEH Exception: INVALID HANDLE"; break;
504 //      case EXCEPTION_POSSIBLE_DEADLOCK:        pSEHName = "SEH Exception: POSSIBLE DEADLOCK"; break;
505         default:                                 pSEHName = "Unknown SEH Exception"; break;
506     }
507 
508     if( pSEHName)
509         throw std::runtime_error( pSEHName);
510 }
511 
osl_setErrorReporting(sal_Bool bEnable)512 sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable )
513 {
514     sal_Bool bOld = bErrorReportingEnabled;
515     bErrorReportingEnabled = bEnable;
516 
517     if( !bEnable) // if the crash reporter is disabled
518     {
519         // fall back to handle Window's SEH events as C++ exceptions
520         _set_se_translator( win_seh_translator);
521     }
522 
523     return bOld;
524 }
525