1 //$$myexcept.cpp                        Exception handler
2 
3 // Copyright (C) 1993,4,6: R B Davies
4 
5 
6 #define WANT_STREAM                    // include.h will get stream fns
7 #define WANT_STRING
8 
9 #include "include.h"                   // include standard files
10 
11 
12 #include "myexcept.h"                  // for exception handling
13 
14 #ifdef use_namespace
15 namespace RBD_COMMON {
16 #endif
17 
18 
19 //#define REG_DEREG                    // for print out uses of new/delete
20 //#define CLEAN_LIST                   // to print entries being added to
21                                        // or deleted from cleanup list
22 
23 #ifdef SimulateExceptions
24 
Throw()25 void Throw()
26 {
27    for (Janitor* jan = JumpBase::jl->janitor; jan; jan = jan->NextJanitor)
28       jan->CleanUp();
29    JumpItem* jx = JumpBase::jl->ji;    // previous jumpbase;
30    if ( !jx ) { Terminate(); }         // jl was initial JumpItem
31    JumpBase::jl = jx;                  // drop down a level; cannot be in front
32                                        // of previous line
33    Tracer::last = JumpBase::jl->trace;
34    longjmp(JumpBase::jl->env, 1);
35 }
36 
37 #endif                                 // end of simulate exceptions
38 
39 
40 unsigned long BaseException::Select;
41 char* BaseException::what_error;
42 int BaseException::SoFar;
43 int BaseException::LastOne;
44 
BaseException(const char * a_what)45 BaseException::BaseException(const char* a_what)
46 {
47    Select++; SoFar = 0;
48    if (!what_error)                   // make space for exception message
49    {
50       LastOne = 511;
51       what_error = new char[512];
52       if (!what_error)                // fail to make space
53       {
54          LastOne = 0;
55          what_error = (char *)"No heap space for exception message\n";
56       }
57    }
58    AddMessage("\n\nAn exception has been thrown\n");
59    AddMessage(a_what);
60    if (a_what) Tracer::AddTrace();
61 }
62 
AddMessage(const char * a_what)63 void BaseException::AddMessage(const char* a_what)
64 {
65    if (a_what)
66    {
67       int l = strlen(a_what); int r = LastOne - SoFar;
68       if (l < r) { strcpy(what_error+SoFar, a_what); SoFar += l; }
69       else if (r > 0)
70       {
71          strncpy(what_error+SoFar, a_what, r);
72          what_error[LastOne] = 0;
73          SoFar = LastOne;
74       }
75    }
76 }
77 
AddInt(int value)78 void BaseException::AddInt(int value)
79 {
80    bool negative;
81    if (value == 0) { AddMessage("0"); return; }
82    else if (value < 0) { value = -value; negative = true; }
83    else negative = false;
84    int n = 0; int v = value;        // how many digits will we need?
85    while (v > 0) { v /= 10; n++; }
86    if (negative) n++;
87    if (LastOne-SoFar < n) { AddMessage("***"); return; }
88 
89    SoFar += n; n = SoFar; what_error[n] = 0;
90    while (value > 0)
91    {
92       int nv = value / 10; int rm = value - nv * 10;  value = nv;
93       what_error[--n] = (char)(rm + '0');
94    }
95    if (negative) what_error[--n] = '-';
96    return;
97 }
98 
PrintTrace()99 void Tracer::PrintTrace()
100 {
101    cout << "\n";
102    for (Tracer* et = last; et; et=et->previous)
103       cout << "  * " << et->entry << "\n";
104 }
105 
AddTrace()106 void Tracer::AddTrace()
107 {
108    if (last)
109    {
110       BaseException::AddMessage("Trace: ");
111       BaseException::AddMessage(last->entry);
112       for (Tracer* et = last->previous; et; et=et->previous)
113       {
114          BaseException::AddMessage("; ");
115          BaseException::AddMessage(et->entry);
116       }
117       BaseException::AddMessage(".\n");
118    }
119 }
120 
121 #ifdef SimulateExceptions
122 
123 
Janitor()124 Janitor::Janitor()
125 {
126    if (do_not_link)
127    {
128       do_not_link = false; NextJanitor = 0; OnStack = false;
129 #ifdef CLEAN_LIST
130       cout << "Not added to clean-list " << (unsigned long)this << "\n";
131 #endif
132    }
133    else
134    {
135       OnStack = true;
136 #ifdef CLEAN_LIST
137       cout << "Add to       clean-list " << (unsigned long)this << "\n";
138 #endif
139       NextJanitor = JumpBase::jl->janitor; JumpBase::jl->janitor=this;
140    }
141 }
142 
~Janitor()143 Janitor::~Janitor()
144 {
145    // expect the item to be deleted to be first on list
146    // but must be prepared to search list
147    if (OnStack)
148    {
149 #ifdef CLEAN_LIST
150       cout << "Delete from  clean-list " << (unsigned long)this << "\n";
151 #endif
152       Janitor* lastjan = JumpBase::jl->janitor;
153       if (this == lastjan) JumpBase::jl->janitor = NextJanitor;
154       else
155       {
156 	 for (Janitor* jan = lastjan->NextJanitor; jan;
157 	    jan = lastjan->NextJanitor)
158 	 {
159 	    if (jan==this)
160 	       { lastjan->NextJanitor = jan->NextJanitor; return; }
161 	    lastjan=jan;
162 	 }
163 
164 	 Throw(BaseException(
165 "Cannot resolve memory linked list\nSee notes in myexcept.cpp for details\n"
166          ));
167 
168 
169 // This message occurs when a call to ~Janitor() occurs, apparently
170 // without a corresponding call to Janitor(). This could happen if my
171 // way of deciding whether a constructor is being called by new
172 // fails.
173 
174 // It may happen if you are using my simulated exceptions and also have
175 // your compiler s exceptions turned on.
176 
177 // It can also happen if you have a class derived from Janitor
178 // which does not include a copy constructor [ eg X(const &X) ].
179 // Possibly also if delete is applied an object on the stack (ie not
180 // called by new). Otherwise, it is a bug in myexcept or your compiler.
181 // If you do not #define TEMPS_DESTROYED_QUICKLY you will get this
182 // error with Microsoft C 7.0. There are probably situations where
183 // you will get this when you do define TEMPS_DESTROYED_QUICKLY. This
184 // is a bug in MSC. Beware of "operator" statements for defining
185 // conversions; particularly for converting from a Base class to a
186 // Derived class.
187 
188 // You may get away with simply deleting this error message and Throw
189 // statement if you can not find a better way of overcoming the
190 // problem. In any case please tell me if you get this error message,
191 // particularly for compilers apart from Microsoft C 7.0.
192 
193 
194       }
195    }
196 }
197 
198 JumpItem* JumpBase::jl;              // will be set to zero
199 jmp_buf JumpBase::env;
200 bool Janitor::do_not_link;           // will be set to false
201 
202 
203 int JanitorInitializer::ref_count;
204 
JanitorInitializer()205 JanitorInitializer::JanitorInitializer()
206 {
207    if (ref_count++ == 0) new JumpItem;
208                                     // need JumpItem at head of list
209 }
210 
211 #endif                              // end of SimulateExceptions
212 
213 Tracer* Tracer::last;               // will be set to zero
214 
215 
Terminate()216 void Terminate()
217 {
218    cout << "\n\nThere has been an exception with no handler - exiting";
219    const char* what = BaseException::what();
220    if (what) cout << what << "\n";
221    exit(1);
222 }
223 
224 
225 
226 #ifdef DO_FREE_CHECK
227 // Routines for tracing whether new and delete calls are balanced
228 
FreeCheckLink()229 FreeCheckLink::FreeCheckLink() : next(FreeCheck::next)
230    { FreeCheck::next = this; }
231 
FCLClass(void * t,char * name)232 FCLClass::FCLClass(void* t, char* name) : ClassName(name) { ClassStore=t; }
233 
FCLRealArray(void * t,char * o,int s)234 FCLRealArray::FCLRealArray(void* t, char* o, int s)
235   : Operation(o), size(s) { ClassStore=t; }
236 
FCLIntArray(void * t,char * o,int s)237 FCLIntArray::FCLIntArray(void* t, char* o, int s)
238   : Operation(o), size(s) { ClassStore=t; }
239 
240 FreeCheckLink* FreeCheck::next;
241 int FreeCheck::BadDelete;
242 
Report()243 void FCLClass::Report()
244 { cout << "   " << ClassName << "   " << (unsigned long)ClassStore << "\n"; }
245 
Report()246 void FCLRealArray::Report()
247 {
248    cout << "   " << Operation << "   " << (unsigned long)ClassStore <<
249       "   " << size << "\n";
250 }
251 
Report()252 void FCLIntArray::Report()
253 {
254    cout << "   " << Operation << "   " << (unsigned long)ClassStore <<
255       "   " << size << "\n";
256 }
257 
Register(void * t,char * name)258 void FreeCheck::Register(void* t, char* name)
259 {
260    FCLClass* f = new FCLClass(t,name);
261    if (!f) { cout << "Out of memory in FreeCheck\n"; exit(1); }
262 #ifdef REG_DEREG
263    cout << "Registering   " << name << "   " << (unsigned long)t << "\n";
264 #endif
265 }
266 
RegisterR(void * t,char * o,int s)267 void FreeCheck::RegisterR(void* t, char* o, int s)
268 {
269    FCLRealArray* f = new FCLRealArray(t,o,s);
270    if (!f) { cout << "Out of memory in FreeCheck\n"; exit(1); }
271 #ifdef REG_DEREG
272    cout << o << "   " << s << "   " << (unsigned long)t << "\n";
273 #endif
274 }
275 
RegisterI(void * t,char * o,int s)276 void FreeCheck::RegisterI(void* t, char* o, int s)
277 {
278    FCLIntArray* f = new FCLIntArray(t,o,s);
279    if (!f) { cout << "Out of memory in FreeCheck\n"; exit(1); }
280 #ifdef REG_DEREG
281    cout << o << "   " << s << "   " << (unsigned long)t << "\n";
282 #endif
283 }
284 
DeRegister(void * t,char * name)285 void FreeCheck::DeRegister(void* t, char* name)
286 {
287    FreeCheckLink* last = 0;
288 #ifdef REG_DEREG
289    cout << "Deregistering " << name << "   " << (unsigned long)t << "\n";
290 #endif
291    for (FreeCheckLink* fcl = next; fcl; fcl = fcl->next)
292    {
293       if (fcl->ClassStore==t)
294       {
295 	 if (last) last->next = fcl->next; else next = fcl->next;
296 	 delete fcl; return;
297       }
298       last = fcl;
299    }
300    cout << "\nRequest to delete non-existent object of class and location:\n";
301    cout << "   " << name << "   " << (unsigned long)t << "\n";
302    BadDelete++;
303    Tracer::PrintTrace();
304    cout << "\n";
305 }
306 
DeRegisterR(void * t,char * o,int s)307 void FreeCheck::DeRegisterR(void* t, char* o, int s)
308 {
309    FreeCheckLink* last = 0;
310 #ifdef REG_DEREG
311    cout << o << "   " << s << "   " << (unsigned long)t << "\n";
312 #endif
313    for (FreeCheckLink* fcl = next; fcl; fcl = fcl->next)
314    {
315       if (fcl->ClassStore==t)
316       {
317 	 if (last) last->next = fcl->next; else next = fcl->next;
318 	 if (s >= 0 && ((FCLRealArray*)fcl)->size != s)
319 	 {
320 	    cout << "\nArray sizes do not agree:\n";
321 	    cout << "   " << o << "   " << (unsigned long)t
322 	       << "   " << ((FCLRealArray*)fcl)->size << "   " << s << "\n";
323 	    Tracer::PrintTrace();
324 	    cout << "\n";
325 	 }
326 	 delete fcl; return;
327       }
328       last = fcl;
329    }
330    cout << "\nRequest to delete non-existent real array:\n";
331    cout << "   " << o << "   " << (unsigned long)t << "   " << s << "\n";
332    BadDelete++;
333    Tracer::PrintTrace();
334    cout << "\n";
335 }
336 
DeRegisterI(void * t,char * o,int s)337 void FreeCheck::DeRegisterI(void* t, char* o, int s)
338 {
339    FreeCheckLink* last = 0;
340 #ifdef REG_DEREG
341    cout << o << "   " << s << "   " << (unsigned long)t << "\n";
342 #endif
343    for (FreeCheckLink* fcl = next; fcl; fcl = fcl->next)
344    {
345       if (fcl->ClassStore==t)
346       {
347 	 if (last) last->next = fcl->next; else next = fcl->next;
348 	 if (s >= 0 && ((FCLIntArray*)fcl)->size != s)
349 	 {
350 	    cout << "\nArray sizes do not agree:\n";
351 	    cout << "   " << o << "   " << (unsigned long)t
352 	       << "   " << ((FCLIntArray*)fcl)->size << "   " << s << "\n";
353 	    Tracer::PrintTrace();
354 	    cout << "\n";
355 	 }
356 	 delete fcl; return;
357       }
358       last = fcl;
359    }
360    cout << "\nRequest to delete non-existent int array:\n";
361    cout << "   " << o << "   " << (unsigned long)t << "   " << s << "\n";
362    BadDelete++;
363    Tracer::PrintTrace();
364    cout << "\n";
365 }
366 
Status()367 void FreeCheck::Status()
368 {
369    if (next)
370    {
371       cout << "\nObjects of the following classes remain undeleted:\n";
372       for (FreeCheckLink* fcl = next; fcl; fcl = fcl->next) fcl->Report();
373       cout << "\n";
374    }
375    else cout << "\nNo objects remain undeleted\n\n";
376    if (BadDelete)
377    {
378       cout << "\nThere were " << BadDelete <<
379          " requests to delete non-existent items\n\n";
380    }
381 }
382 
383 #endif                            // end of DO_FREE_CHECK
384 
385 // derived exception bodies
386 
Logic_error(const char * a_what)387 Logic_error::Logic_error(const char* a_what) : BaseException()
388 {
389    Select = BaseException::Select;
390    AddMessage("Logic error:- "); AddMessage(a_what);
391    if (a_what) Tracer::AddTrace();
392 }
393 
Runtime_error(const char * a_what)394 Runtime_error::Runtime_error(const char* a_what)
395    : BaseException()
396 {
397    Select = BaseException::Select;
398    AddMessage("Runtime error:- "); AddMessage(a_what);
399    if (a_what) Tracer::AddTrace();
400 }
401 
Domain_error(const char * a_what)402 Domain_error::Domain_error(const char* a_what) : Logic_error()
403 {
404    Select = BaseException::Select;
405    AddMessage("domain error\n"); AddMessage(a_what);
406    if (a_what) Tracer::AddTrace();
407 }
408 
Invalid_argument(const char * a_what)409 Invalid_argument::Invalid_argument(const char* a_what) : Logic_error()
410 {
411    Select = BaseException::Select;
412    AddMessage("invalid argument\n"); AddMessage(a_what);
413    if (a_what) Tracer::AddTrace();
414 }
415 
Length_error(const char * a_what)416 Length_error::Length_error(const char* a_what) : Logic_error()
417 {
418    Select = BaseException::Select;
419    AddMessage("length error\n"); AddMessage(a_what);
420    if (a_what) Tracer::AddTrace();
421 }
422 
Out_of_range(const char * a_what)423 Out_of_range::Out_of_range(const char* a_what) : Logic_error()
424 {
425    Select = BaseException::Select;
426    AddMessage("out of range\n"); AddMessage(a_what);
427    if (a_what) Tracer::AddTrace();
428 }
429 
430 //Bad_cast::Bad_cast(const char* a_what) : Logic_error()
431 //{
432 //   Select = BaseException::Select;
433 //   AddMessage("bad cast\n"); AddMessage(a_what);
434 //   if (a_what) Tracer::AddTrace();
435 //}
436 
437 //Bad_typeid::Bad_typeid(const char* a_what) : Logic_error()
438 //{
439 //   Select = BaseException::Select;
440 //   AddMessage("bad type id.\n"); AddMessage(a_what);
441 //   if (a_what) Tracer::AddTrace();
442 //}
443 
Range_error(const char * a_what)444 Range_error::Range_error(const char* a_what) : Runtime_error()
445 {
446    Select = BaseException::Select;
447    AddMessage("range error\n"); AddMessage(a_what);
448    if (a_what) Tracer::AddTrace();
449 }
450 
Overflow_error(const char * a_what)451 Overflow_error::Overflow_error(const char* a_what) : Runtime_error()
452 {
453    Select = BaseException::Select;
454    AddMessage("overflow error\n"); AddMessage(a_what);
455    if (a_what) Tracer::AddTrace();
456 }
457 
Bad_alloc(const char * a_what)458 Bad_alloc::Bad_alloc(const char* a_what) : BaseException()
459 {
460    Select = BaseException::Select;
461    AddMessage("bad allocation\n"); AddMessage(a_what);
462    if (a_what) Tracer::AddTrace();
463 }
464 
465 
466 
467 
468 unsigned long Logic_error::Select;
469 unsigned long Runtime_error::Select;
470 unsigned long Domain_error::Select;
471 unsigned long Invalid_argument::Select;
472 unsigned long Length_error::Select;
473 unsigned long Out_of_range::Select;
474 //unsigned long Bad_cast::Select;
475 //unsigned long Bad_typeid::Select;
476 unsigned long Range_error::Select;
477 unsigned long Overflow_error::Select;
478 unsigned long Bad_alloc::Select;
479 
480 #ifdef use_namespace
481 }
482 #endif
483 
484 
485