0030550: Coding - Integer overflow in Standard_CString HashCodes
[occt.git] / src / Standard / Standard_ErrorHandler.cxx
CommitLineData
b311480e 1// Copyright (c) 1998-1999 Matra Datavision
973c2be1 2// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 3//
973c2be1 4// This file is part of Open CASCADE Technology software library.
b311480e 5//
d5f74e42 6// This library is free software; you can redistribute it and/or modify it under
7// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 8// by the Free Software Foundation, with special exception defined in the file
9// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10// distribution for complete text of the license and disclaimer of any warranty.
b311480e 11//
973c2be1 12// Alternatively, this file may be used under the terms of Open CASCADE
13// commercial license or contractual agreement.
b311480e 14
7fd59977 15//============================================================================
16//==== Titre: Standard_ErrorHandler.cxx
17//==== Role : class "Standard_ErrorHandler" implementation.
18//============================================================================
19#include <Standard_ErrorHandler.hxx>
20#include <Standard_Failure.hxx>
7fd59977 21#include <Standard_Mutex.hxx>
22#include <Standard.hxx>
23
57c28b61 24#ifndef _WIN32
7fd59977 25#include <pthread.h>
26#else
27#include <windows.h>
28#endif
29
30// ===========================================================================
31// The class "Standard_ErrorHandler" variables
32// ===========================================================================
33
34// During [sig]setjmp()/[sig]longjmp() K_SETJMP is non zero (try)
35// So if there is an abort request and if K_SETJMP is non zero, the abort
36// request will be ignored. If the abort request do a raise during a setjmp
37// or a longjmp, there will be a "terminating SEGV" impossible to handle.
38
39//==== The top of the Errors Stack ===========================================
40static Standard_ErrorHandler* Top = 0;
41
42// A mutex to protect from concurrent access to Top
43// Note that we should NOT use Sentry while in this class, as Sentry
44// would register mutex as callback in the current exception handler
45static Standard_Mutex theMutex;
46
47static inline Standard_ThreadId GetThreadID()
48{
57c28b61 49#ifndef _WIN32
2b2be3fb 50 return (Standard_ThreadId)pthread_self();
7fd59977 51#else
52 return GetCurrentThreadId();
53#endif
54}
55
56//============================================================================
57//==== Constructor : Create a ErrorHandler structure. And add it at the
58//==== 'Top' of "ErrorHandler's stack".
59//============================================================================
60
61Standard_ErrorHandler::Standard_ErrorHandler () :
62 myStatus(Standard_HandlerVoid), myCallbackPtr(0)
63{
64 myThread = GetThreadID();
c9246067 65 memset (&myLabel, 0, sizeof(myLabel));
7fd59977 66
bd0c22ce 67 theMutex.Lock();
7fd59977 68 myPrevious = Top;
69 Top = this;
bd0c22ce 70 theMutex.Unlock();
7fd59977 71}
72
73
74//============================================================================
75//==== Destructor : Delete the ErrorHandler and Abort if there is a 'Error'.
76//============================================================================
77
78void Standard_ErrorHandler::Destroy()
79{
80 Unlink();
a01039b9 81 if (myStatus == Standard_HandlerJumped)
82 {
83 // jumped, but not caught
84 Abort (myCaughtError);
7fd59977 85 }
86}
87
88
89//=======================================================================
90//function : Unlink
91//purpose :
92//=======================================================================
93
94void Standard_ErrorHandler::Unlink()
95{
96 // put a lock on the stack
bd0c22ce 97 theMutex.Lock();
7fd59977 98
99 Standard_ErrorHandler* aPrevious = 0;
100 Standard_ErrorHandler* aCurrent = Top;
101
102 // locate this handler in the stack
103 while(aCurrent!=0 && this!=aCurrent) {
104 aPrevious = aCurrent;
105 aCurrent = aCurrent->myPrevious;
106 }
107
108 if(aCurrent==0) {
bd0c22ce 109 theMutex.Unlock();
7fd59977 110 return;
111 }
112
113 if(aPrevious==0) {
114 // a top exception taken
115 Top = aCurrent->myPrevious;
116 }
117 else {
118 aPrevious->myPrevious=aCurrent->myPrevious;
119 }
120 myPrevious = 0;
bd0c22ce 121 theMutex.Unlock();
7fd59977 122
123 // unlink and destroy all registered callbacks
124 Standard_Address aPtr = aCurrent->myCallbackPtr;
125 myCallbackPtr = 0;
126 while ( aPtr ) {
536a3cb8 127 Standard_ErrorHandler::Callback* aCallback = (Standard_ErrorHandler::Callback*)aPtr;
7fd59977 128 aPtr = aCallback->myNext;
129 // Call destructor explicitly, as we know that it will not be called automatically
130 aCallback->DestroyCallback();
131 }
132}
133
134//=======================================================================
135//function : IsInTryBlock
136//purpose : test if the code is currently running in
137//=======================================================================
138
139Standard_Boolean Standard_ErrorHandler::IsInTryBlock()
140{
141 Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, Standard_False);
c9246067 142 return anActive != NULL;
7fd59977 143}
144
145
146//============================================================================
147//==== Abort: make a longjmp to the saved Context.
148//==== Abort if there is a non null 'Error'
149//============================================================================
150
a01039b9 151void Standard_ErrorHandler::Abort (const Handle(Standard_Failure)& theError)
7fd59977 152{
153 Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerVoid, Standard_True);
a01039b9 154
7fd59977 155 //==== Check if can do the "longjmp" =======================================
c9246067 156 if(anActive == NULL) {
7fd59977 157 cerr << "*** Abort *** an exception was raised, but no catch was found." << endl;
a01039b9 158 if (!theError.IsNull())
159 cerr << "\t... The exception is:" << theError->GetMessageString() << endl;
7fd59977 160 exit(1);
161 }
a01039b9 162
7fd59977 163 anActive->myStatus = Standard_HandlerJumped;
164 longjmp(anActive->myLabel, Standard_True);
165}
166
167
168//============================================================================
169//==== Catches: If there is a 'Error', and it is in good type
170//==== returns True and clean 'Error', else returns False.
171//============================================================================
172
173Standard_Boolean Standard_ErrorHandler::Catches (const Handle(Standard_Type)& AType)
174{
175 Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerJumped, Standard_False);
176 if(anActive==0)
177 return Standard_False;
178
179 if(anActive->myCaughtError.IsNull())
180 return Standard_False;
181
182 if(anActive->myCaughtError->IsKind(AType)){
183 myStatus=Standard_HandlerProcessed;
184 return Standard_True;
185 } else {
186 return Standard_False;
187 }
188}
189
190Handle(Standard_Failure) Standard_ErrorHandler::LastCaughtError()
191{
192 Handle(Standard_Failure) aHandle;
193 Standard_ErrorHandler* anActive = FindHandler(Standard_HandlerProcessed, Standard_False);
194 if(anActive!=0)
195 aHandle = anActive->myCaughtError;
196
197 return aHandle;
198}
199
200Handle(Standard_Failure) Standard_ErrorHandler::Error() const
201{
202 return myCaughtError;
203}
204
205
a01039b9 206void Standard_ErrorHandler::Error (const Handle(Standard_Failure)& theError)
7fd59977 207{
a01039b9 208 Standard_ErrorHandler* anActive = FindHandler (Standard_HandlerVoid, Standard_False);
209 if (anActive == NULL)
210 Abort (theError);
7fd59977 211
a01039b9 212 anActive->myCaughtError = theError;
213}
7fd59977 214
215
216Standard_ErrorHandler* Standard_ErrorHandler::FindHandler(const Standard_HandlerStatus theStatus,
217 const Standard_Boolean theUnlink)
218{
219 // lock the stack
bd0c22ce 220 theMutex.Lock();
7fd59977 221
222 // Find the current ErrorHandler Accordin tread
223 Standard_ErrorHandler* aPrevious = 0;
224 Standard_ErrorHandler* aCurrent = Top;
225 Standard_ErrorHandler* anActive = 0;
226 Standard_Boolean aStop = Standard_False;
227 Standard_ThreadId aTreadId = GetThreadID();
228
229 // searching an exception with correct ID number
230 // which is not processed for the moment
231 while(!aStop) {
232 while(aCurrent!=NULL && aTreadId!=aCurrent->myThread) {
233 aPrevious = aCurrent;
234 aCurrent = aCurrent->myPrevious;
235 }
236
237 if(aCurrent!=NULL) {
238 if(theStatus!=aCurrent->myStatus) {
239
240 if(theUnlink) {
241 //unlink current
242 if(aPrevious==0) {
243 // a top exception taken
244 Top = aCurrent->myPrevious;
245 }
246 else {
247 aPrevious->myPrevious=aCurrent->myPrevious;
248 }
249 }
250
251 //shift
252 aCurrent = aCurrent->myPrevious;
253 }
254 else {
255 //found one
256 anActive = aCurrent;
257 aStop = Standard_True;
258 }
259 }
260 else {
261 //Current is NULL, means that no handlesr
262 aStop = Standard_True;
263 }
264 }
bd0c22ce 265 theMutex.Unlock();
7fd59977 266
267 return anActive;
268}
536a3cb8 269
9775fa61 270#if defined(OCC_CONVERT_SIGNALS)
536a3cb8 271
272Standard_ErrorHandler::Callback::Callback ()
273 : myHandler(0), myPrev(0), myNext(0)
274{
275}
276
277Standard_ErrorHandler::Callback::~Callback ()
278{
279 UnregisterCallback();
280}
281
282void Standard_ErrorHandler::Callback::RegisterCallback ()
283{
284 if ( myHandler ) return; // already registered
285
286 // find current active exception handler
287 Standard_ErrorHandler *aHandler =
288 Standard_ErrorHandler::FindHandler(Standard_HandlerVoid, Standard_False);
289
290 // if found, add this callback object first to the list
291 if ( aHandler ) {
292 myHandler = aHandler;
293 myNext = aHandler->myCallbackPtr;
294 if ( myNext ) ((Standard_ErrorHandler::Callback*)myNext)->myPrev = this;
295 aHandler->myCallbackPtr = this;
296 }
297}
298
299void Standard_ErrorHandler::Callback::UnregisterCallback ()
300{
301 if ( ! myHandler ) return;
302 if ( myNext )
303 ((Standard_ErrorHandler::Callback*)myNext)->myPrev = myPrev;
304 if ( myPrev )
305 ((Standard_ErrorHandler::Callback*)myPrev)->myNext = myNext;
306 else if ( ((Standard_ErrorHandler*)myHandler)->myCallbackPtr == this)
307 ((Standard_ErrorHandler*)myHandler)->myCallbackPtr = (Standard_ErrorHandler::Callback*)myNext;
308 myHandler = myNext = myPrev = 0;
309}
310#endif