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