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