xref: /AOO41X/main/sal/osl/w32/signal.cxx (revision 3752b850d37499faee95da05d8f1997a7bbcdbb0)
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 
InitSignal(void)56 static sal_Bool InitSignal(void)
57 {
58     HMODULE hFaultRep;
59 
60     SignalListMutex = osl_createMutex();
61 
62     SetUnhandledExceptionFilter(SignalHandlerFunction);
63 
64     hFaultRep = LoadLibrary( "faultrep.dll" );
65     if ( hFaultRep )
66     {
67 #ifdef __MINGW32__
68 typedef BOOL (WINAPI *pfn_ADDEREXCLUDEDAPPLICATIONW)(LPCWSTR);
69 #endif
70         pfn_ADDEREXCLUDEDAPPLICATIONW       pfn = (pfn_ADDEREXCLUDEDAPPLICATIONW)GetProcAddress( hFaultRep, "AddERExcludedApplicationW" );
71         if ( pfn )
72             pfn( L"SOFFICE.EXE" );
73         FreeLibrary( hFaultRep );
74     }
75 
76     return sal_True;
77 }
78 
DeInitSignal(void)79 static sal_Bool DeInitSignal(void)
80 {
81     SetUnhandledExceptionFilter(NULL);
82 
83     osl_destroyMutex(SignalListMutex);
84 
85     return sal_False;
86 }
87 
CallSignalHandler(oslSignalInfo * pInfo)88 static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo)
89 {
90     oslSignalHandlerImpl* pHandler = SignalList;
91     oslSignalAction Action = osl_Signal_ActCallNextHdl;
92 
93     while (pHandler != NULL)
94     {
95         if ((Action = pHandler->Handler(pHandler->pData, pInfo)) != osl_Signal_ActCallNextHdl)
96             break;
97 
98         pHandler = pHandler->pNext;
99     }
100 
101     return Action;
102 }
103 
104 /*****************************************************************************/
105 /* SignalHandlerFunction    */
106 /*****************************************************************************/
107 
108 #define REPORTENV_PARAM     "-crashreportenv:"
109 #define REPORTENV_PARAM2    "/crashreportenv:"
110 
ReportCrash(LPEXCEPTION_POINTERS lpEP)111 static BOOL ReportCrash( LPEXCEPTION_POINTERS lpEP )
112 {
113     BOOL    fSuccess = FALSE;
114     BOOL    fAutoReport = FALSE;
115     TCHAR   szBuffer[1024];
116     ::osl::LongPathBuffer< sal_Char > aPath( MAX_LONG_PATH );
117     LPTSTR  lpFilePart;
118     PROCESS_INFORMATION ProcessInfo;
119     STARTUPINFO StartupInfo;
120     int     argi;
121 
122     if ( !bErrorReportingEnabled )
123         return FALSE;
124 
125     /* Check if crash reporter was disabled by command line */
126 
127     for ( argi = 1; argi < __argc; argi++ )
128     {
129         if (
130             0 == stricmp( __argv[argi], "-nocrashreport" ) ||
131             0 == stricmp( __argv[argi], "/nocrashreport" )
132             )
133             return FALSE;
134         else if (
135             0 == stricmp( __argv[argi], "-autocrashreport" ) ||
136             0 == stricmp( __argv[argi], "/autocrashreport" )
137             )
138             fAutoReport = TRUE;
139         else if (
140             0 == strnicmp( __argv[argi], REPORTENV_PARAM, strlen(REPORTENV_PARAM) ) ||
141             0 == strnicmp( __argv[argi], REPORTENV_PARAM2, strlen(REPORTENV_PARAM2) )
142             )
143         {
144             const char *envparam = __argv[argi] + strlen(REPORTENV_PARAM);
145             const char *delim = strchr(envparam, '=' );
146 
147             if ( delim )
148             {
149                 CHAR    *lpVariable;
150                 CHAR    *lpValue;
151                 const char *variable = envparam;
152                 size_t variable_len = delim - envparam;
153                 const char *value = delim + 1;
154                 size_t value_len = strlen(envparam) - variable_len - 1;
155 
156                 if ( '\"' == *value )
157                 {
158                     const char *quote;
159 
160                     value++;
161                     value_len--;
162 
163                     quote = strchr( value, '\"' );
164                     if ( quote )
165                         value_len = quote - value;
166                 }
167 
168                 lpVariable = reinterpret_cast< CHAR* >( _alloca( variable_len + 1 ) );
169                 memcpy( lpVariable, variable, variable_len );
170                 lpVariable[variable_len] = 0;
171 
172                 lpValue = reinterpret_cast< CHAR* >( _alloca( value_len + 1) );
173                 memcpy( lpValue, value, value_len );
174                 lpValue[value_len] = 0;
175 
176                 SetEnvironmentVariable( lpVariable, lpValue );
177             }
178         }
179     }
180 
181     if ( SearchPath( NULL, TEXT( "crashrep.exe" ), NULL, aPath.getBufSizeInSymbols(), aPath, &lpFilePart ) )
182     {
183         ZeroMemory( &StartupInfo, sizeof(StartupInfo) );
184         StartupInfo.cb = sizeof(StartupInfo.cb);
185 
186 
187         sntprintf( szBuffer, elementsof(szBuffer),
188             _T("%s -p %u -excp 0x%p -t %u%s"),
189             static_cast<sal_Char*>( aPath ),
190             GetCurrentProcessId(),
191             lpEP,
192             GetCurrentThreadId(),
193             fAutoReport ? _T(" -noui -send") : _T(" -noui") );
194 
195         if (
196             CreateProcess(
197                 NULL,
198                 szBuffer,
199                 NULL,
200                 NULL,
201                 FALSE,
202 #ifdef UNICODE
203                 CREATE_UNICODE_ENVIRONMENT,
204 #else
205                 0,
206 #endif
207                 NULL, NULL, &StartupInfo, &ProcessInfo )
208             )
209         {
210             DWORD   dwExitCode;
211 
212             WaitForSingleObject( ProcessInfo.hProcess, INFINITE );
213             if ( GetExitCodeProcess( ProcessInfo.hProcess, &dwExitCode ) && 0 == dwExitCode )
214 
215             fSuccess = TRUE;
216 
217         }
218     }
219 
220     return fSuccess;
221 }
222 
223 /*****************************************************************************/
224 /* SignalHandlerFunction    */
225 /*****************************************************************************/
226 
IsWin95A(void)227 static BOOL WINAPI IsWin95A(void)
228 {
229     OSVERSIONINFO   ovi;
230 
231     ZeroMemory( &ovi, sizeof(ovi) );
232     ovi.dwOSVersionInfoSize = sizeof(ovi);
233 
234     if ( GetVersionEx( &ovi ) )
235         /* See MSDN January 2000 documentation of GetVersionEx */
236         return  (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) &&
237                 (ovi.dwMajorVersion <= 4) &&
238                 (ovi.dwMinorVersion == 0) &&
239                 (ovi.dwBuildNumber == 0x040003B6);
240 
241     /* Something wrent wrong. So assume we have an older operating prior Win95 */
242 
243     return TRUE;
244 }
245 
246 /* magic Microsoft C++ compiler exception constant */
247 #define EXCEPTION_MSC_CPP_EXCEPTION 0xe06d7363
248 
SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP)249 static long WINAPI SignalHandlerFunction(LPEXCEPTION_POINTERS lpEP)
250 {
251     static sal_Bool     bNested = sal_False;
252     sal_Bool        bRaiseCrashReporter = sal_False;
253     oslSignalInfo   Info;
254     oslSignalAction Action;
255 
256     Info.UserSignal = lpEP->ExceptionRecord->ExceptionCode;
257     Info.UserData   = NULL;
258 
259     switch (lpEP->ExceptionRecord->ExceptionCode)
260     {
261         /* Transform unhandled exceptions into access violations.
262            Microsoft C++ compiler (add more for other compilers if necessary).
263          */
264         case EXCEPTION_MSC_CPP_EXCEPTION:
265         case EXCEPTION_ACCESS_VIOLATION:
266             Info.Signal = osl_Signal_AccessViolation;
267             bRaiseCrashReporter = sal_True;
268             break;
269 
270         case EXCEPTION_INT_DIVIDE_BY_ZERO:
271             Info.Signal = osl_Signal_IntegerDivideByZero;
272             bRaiseCrashReporter = sal_True;
273             break;
274 
275         case EXCEPTION_FLT_DIVIDE_BY_ZERO:
276             Info.Signal = osl_Signal_FloatDivideByZero;
277             bRaiseCrashReporter = sal_True;
278             break;
279 
280         case EXCEPTION_BREAKPOINT:
281             Info.Signal = osl_Signal_DebugBreak;
282             break;
283 
284         default:
285             Info.Signal = osl_Signal_System;
286             bRaiseCrashReporter = sal_True;
287             break;
288     }
289 
290     if ( !bNested )
291     {
292         bNested = sal_True;
293 
294         if ( bRaiseCrashReporter && ReportCrash( lpEP ) || IsWin95A() )
295         {
296             CallSignalHandler(&Info);
297             Action = osl_Signal_ActKillApp;
298         }
299         else
300             Action = CallSignalHandler(&Info);
301     }
302     else
303         Action = osl_Signal_ActKillApp;
304 
305 
306     switch ( Action )
307     {
308         case osl_Signal_ActCallNextHdl:
309             return (EXCEPTION_CONTINUE_SEARCH);
310 
311         case osl_Signal_ActAbortApp:
312             return (EXCEPTION_EXECUTE_HANDLER);
313 
314         case osl_Signal_ActKillApp:
315             SetErrorMode(SEM_NOGPFAULTERRORBOX);
316             exit(255);
317             break;
318         default:
319             break;
320     }
321 
322     return (EXCEPTION_CONTINUE_EXECUTION);
323 }
324 
325 /*****************************************************************************/
326 /* osl_addSignalHandler */
327 /*****************************************************************************/
osl_addSignalHandler(oslSignalHandlerFunction Handler,void * pData)328 oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData)
329 {
330     oslSignalHandlerImpl* pHandler;
331 
332     OSL_ASSERT(Handler != NULL);
333 
334     if (! bInitSignal)
335         bInitSignal = InitSignal();
336 
337     pHandler = reinterpret_cast< oslSignalHandlerImpl* >( calloc( 1, sizeof(oslSignalHandlerImpl) ) );
338 
339     if (pHandler != NULL)
340     {
341         pHandler->Handler = Handler;
342         pHandler->pData   = pData;
343 
344         osl_acquireMutex(SignalListMutex);
345 
346         pHandler->pNext = SignalList;
347         SignalList      = pHandler;
348 
349         osl_releaseMutex(SignalListMutex);
350 
351         return (pHandler);
352     }
353 
354     return (NULL);
355 }
356 
357 /*****************************************************************************/
358 /* osl_removeSignalHandler */
359 /*****************************************************************************/
osl_removeSignalHandler(oslSignalHandler Handler)360 sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler)
361 {
362     oslSignalHandlerImpl *pHandler, *pPrevious = NULL;
363 
364     OSL_ASSERT(Handler != NULL);
365 
366     if (! bInitSignal)
367         bInitSignal = InitSignal();
368 
369     osl_acquireMutex(SignalListMutex);
370 
371     pHandler = SignalList;
372 
373     while (pHandler != NULL)
374     {
375         if (pHandler == Handler)
376         {
377             if (pPrevious)
378                 pPrevious->pNext = pHandler->pNext;
379             else
380                 SignalList = pHandler->pNext;
381 
382             osl_releaseMutex(SignalListMutex);
383 
384             if (SignalList == NULL)
385                 bInitSignal = DeInitSignal();
386 
387             free(pHandler);
388 
389             return (sal_True);
390         }
391 
392         pPrevious = pHandler;
393         pHandler  = pHandler->pNext;
394     }
395 
396     osl_releaseMutex(SignalListMutex);
397 
398     return (sal_False);
399 }
400 
401 /*****************************************************************************/
402 /* osl_raiseSignal */
403 /*****************************************************************************/
osl_raiseSignal(sal_Int32 UserSignal,void * UserData)404 oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData)
405 {
406     oslSignalInfo   Info;
407     oslSignalAction Action;
408 
409     if (! bInitSignal)
410         bInitSignal = InitSignal();
411 
412     osl_acquireMutex(SignalListMutex);
413 
414     Info.Signal     = osl_Signal_User;
415     Info.UserSignal = UserSignal;
416     Info.UserData   = UserData;
417 
418     Action = CallSignalHandler(&Info);
419 
420     osl_releaseMutex(SignalListMutex);
421 
422     return (Action);
423 }
424 
425 /*****************************************************************************/
426 /* osl_setErrorReporting */
427 /*****************************************************************************/
428 
win_seh_translator(unsigned nSEHCode,_EXCEPTION_POINTERS * pExcPtrs)429 void win_seh_translator( unsigned nSEHCode, _EXCEPTION_POINTERS* pExcPtrs)
430 {
431     (void*)pExcPtrs; // currently unused, but useful inside a debugger
432     const char* pSEHName = NULL;
433     switch( nSEHCode)
434     {
435         case EXCEPTION_ACCESS_VIOLATION:         pSEHName = "SEH Exception: ACCESS VIOLATION"; break;
436         case EXCEPTION_DATATYPE_MISALIGNMENT:    pSEHName = "SEH Exception: DATATYPE MISALIGNMENT"; break;
437         case EXCEPTION_BREAKPOINT:               /*pSEHName = "SEH Exception: BREAKPOINT";*/ break;
438         case EXCEPTION_SINGLE_STEP:              /*pSEHName = "SEH Exception: SINGLE STEP";*/ break;
439         case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:    pSEHName = "SEH Exception: ARRAY BOUNDS EXCEEDED"; break;
440         case EXCEPTION_FLT_DENORMAL_OPERAND:     pSEHName = "SEH Exception: DENORMAL FLOAT OPERAND"; break;
441         case EXCEPTION_FLT_DIVIDE_BY_ZERO:       pSEHName = "SEH Exception: FLOAT DIVIDE_BY_ZERO"; break;
442         case EXCEPTION_FLT_INEXACT_RESULT:       pSEHName = "SEH Exception: FLOAT INEXACT RESULT"; break;
443         case EXCEPTION_FLT_INVALID_OPERATION:    pSEHName = "SEH Exception: INVALID FLOAT OPERATION"; break;
444         case EXCEPTION_FLT_OVERFLOW:             pSEHName = "SEH Exception: FLOAT OVERFLOW"; break;
445         case EXCEPTION_FLT_STACK_CHECK:          pSEHName = "SEH Exception: FLOAT STACK_CHECK"; break;
446         case EXCEPTION_FLT_UNDERFLOW:            pSEHName = "SEH Exception: FLOAT UNDERFLOW"; break;
447         case EXCEPTION_INT_DIVIDE_BY_ZERO:       pSEHName = "SEH Exception: INTEGER DIVIDE_BY_ZERO"; break;
448         case EXCEPTION_INT_OVERFLOW:             pSEHName = "SEH Exception: INTEGER OVERFLOW"; break;
449         case EXCEPTION_PRIV_INSTRUCTION:         pSEHName = "SEH Exception: PRIVILEDGED INSTRUCTION"; break;
450         case EXCEPTION_IN_PAGE_ERROR:            pSEHName = "SEH Exception: IN_PAGE_ERROR"; break;
451         case EXCEPTION_ILLEGAL_INSTRUCTION:      pSEHName = "SEH Exception: ILLEGAL INSTRUCTION"; break;
452         case EXCEPTION_NONCONTINUABLE_EXCEPTION: pSEHName = "SEH Exception: NONCONTINUABLE EXCEPTION"; break;
453         case EXCEPTION_STACK_OVERFLOW:           pSEHName = "SEH Exception: STACK OVERFLOW"; break;
454         case EXCEPTION_INVALID_DISPOSITION:      pSEHName = "SEH Exception: INVALID DISPOSITION"; break;
455         case EXCEPTION_GUARD_PAGE:               pSEHName = "SEH Exception: GUARD PAGE"; break;
456         case EXCEPTION_INVALID_HANDLE:           pSEHName = "SEH Exception: INVALID HANDLE"; break;
457 //      case EXCEPTION_POSSIBLE_DEADLOCK:        pSEHName = "SEH Exception: POSSIBLE DEADLOCK"; break;
458         default:                                 pSEHName = "Unknown SEH Exception"; break;
459     }
460 
461     if( pSEHName)
462         throw std::runtime_error( pSEHName);
463 }
464 
osl_setErrorReporting(sal_Bool bEnable)465 sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable )
466 {
467     sal_Bool bOld = bErrorReportingEnabled;
468     bErrorReportingEnabled = bEnable;
469 
470     if( !bEnable) // if the crash reporter is disabled
471     {
472         // fall back to handle Window's SEH events as C++ exceptions
473         _set_se_translator( win_seh_translator);
474     }
475 
476     return bOld;
477 }
478