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