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