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 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 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 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 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 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 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 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 /*****************************************************************************/ 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 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 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