exception.cpp
00001 00002 /*************************************************************************** 00003 * exception.cpp - basic exception 00004 * 00005 * Generated: Thu Feb 09 13:04:45 2006 (from FireVision) 00006 * Copyright 2005-2006 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. A runtime exception applies to 00014 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Library General Public License for more details. 00020 * 00021 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00022 */ 00023 00024 #include <core/exception.h> 00025 #include <core/threading/mutex.h> 00026 00027 #ifndef _GNU_SOURCE 00028 #define _GNU_SOURCE 00029 #endif 00030 00031 #include <cstring> 00032 #include <cstdlib> 00033 #include <cstdio> 00034 #ifdef HAVE_EXECINFO 00035 # include <execinfo.h> 00036 #endif 00037 00038 namespace fawkes { 00039 00040 /** @class Exception core/exception.h 00041 * Base class for exceptions in Fawkes. 00042 * Exceptions are a good way to handle errors. If you choose to use 00043 * exceptions use derivates of this class so that there is a unified way of 00044 * handling errors in Fawkes. Do <i>not</i> throw an arbitrary class such as 00045 * a string or integer as this is hard to handle. 00046 * 00047 * For your exceptions in general you only need to override the constructor 00048 * and call the Exception constructor with the appropriate message. In 00049 * cases where more information is needed about the error add appropriate 00050 * handlers. 00051 * 00052 * In most cases it is bad to just throw an Exception like this: 00053 * 00054 * @code 00055 * if ( error_condition ) { 00056 * throw Exception("Out of memory"); 00057 * } 00058 * @endcode 00059 * 00060 * Rather you should explicitly subclass Exception appropriately. For the 00061 * above example you could have something like this as exception class: 00062 * 00063 * @code 00064 * class OutOfMemException : public Exception 00065 * { 00066 * public: 00067 * OutOfMemoryException() : Exception("Out of memory") {} 00068 * } 00069 * @endcode 00070 * 00071 * And in your handling code you throw a OutOfMemoryException. This is 00072 * especially useful if it is possible to throw several different exceptions. 00073 * If the message was different you would have to parse the string for 00074 * the exact error. This can be avoided if you just catch different 00075 * exceptions. This is also useful if the Exception is not catched explicitly 00076 * as this will printout the name of the exception class thrown just before 00077 * exiting the program. And reading something like 00078 * "terminate called after throwing an instance of 'OutOfMemoryException'" 00079 * makes it a lot easier to spot the problem. 00080 * 00081 * Exceptions should be catched by reference like this: 00082 * @code 00083 * try { 00084 * some_operation(); 00085 * } catch (OutOfMemoryException &e) { 00086 * std::cout << e.c_str() << std::endl; 00087 * error_handling(); 00088 * } 00089 * @endcode 00090 * 00091 * Messages are stored as list. The first message however is called the 00092 * primary message and it should contain as much information as available. 00093 * This message is printed on the screen if the application crashes with an 00094 * unhandled exception. So having meaningful content here means that the 00095 * error can be traced more easily. 00096 * 00097 * You can utilize the list feature by adding appropriate information 00098 * through appropriate try/catch statements. This way you can 00099 * build information path ways that will help to debug your software. Use 00100 * block like this to append information: 00101 * @code 00102 * try { 00103 * potentially_failing(); 00104 * } catch {MyException &e) { 00105 * e.append("info where exception happened"); 00106 * throw; // re-throw exception 00107 * } 00108 * @endcode 00109 * This is especially useful if the exception may occur at several different 00110 * places and it cannot be fixed where it happens. 00111 * 00112 * 00113 * @see example_exception.cpp 00114 * @ingroup FCL 00115 * @ingroup Exceptions 00116 * 00117 * @author Tim Niemueller 00118 */ 00119 /** @var Exception::messages 00120 * List of messages. Should not be NULL. Messages are append with append(). 00121 * Using a custom list to avoid including STL stuff in this core file. 00122 * @see append() 00123 */ 00124 /** @var Exception::messages_iterator 00125 * Iterator to iterate over messages 00126 */ 00127 /** @var Exception::messages_end 00128 * Pointer that points to the very last message. Used for fast appending. 00129 */ 00130 /** @var Exception::messages_mutex 00131 * Mutex to protect operations on messages list. 00132 */ 00133 /** @var Exception::_errno 00134 * Error number, should be used if the error was caused by a method that supplies 00135 * errno. 00136 */ 00137 00138 00139 /** Constructor. 00140 * Constructs a new exception with the given message. 00141 * @param format The format of the primary message. Supports the same 00142 * arguments as append(). The message is copied and not just referenced. 00143 * Thus the memory has to be freed if it is a dynamic string on the heap. 00144 */ 00145 Exception::Exception(const char *format, ...) throw() 00146 { 00147 messages_mutex = new Mutex(); 00148 00149 _errno = 0; 00150 00151 messages = NULL; 00152 messages_end = NULL; 00153 messages_iterator = NULL; 00154 00155 if ( format != NULL ) { 00156 va_list arg; 00157 va_start(arg, format); 00158 append_nolock_va(format, arg); 00159 va_end(arg); 00160 } else { 00161 append_nolock("Unnkown Exception"); 00162 } 00163 } 00164 00165 00166 /** Constructor. 00167 * Constructs a new exception with the given message and errno value. This 00168 * is particularly handy when throwing the exception after a function failed 00169 * that returns an error code in errno. 00170 * @param errno error number 00171 * @param format The format of the primary message. Supports the same 00172 * arguments as append(). The message is copied and not just referenced. 00173 * Thus the memory has to be freed if it is a dynamic string on the heap. 00174 */ 00175 Exception::Exception(int errno, const char *format, ...) throw() 00176 { 00177 messages_mutex = new Mutex(); 00178 00179 _errno = errno; 00180 00181 messages = NULL; 00182 messages_end = NULL; 00183 messages_iterator = NULL; 00184 00185 if ( format != NULL ) { 00186 va_list arg; 00187 va_start(arg, format); 00188 char *ext_format; 00189 if ( asprintf(&ext_format, "%s (errno: %i, %s)", format, errno, strerror(errno)) == -1 ) { 00190 append_nolock_va(format, arg); 00191 } else { 00192 append_nolock_va(ext_format, arg); 00193 free(ext_format); 00194 } 00195 va_end(arg); 00196 } else { 00197 append_nolock("Exception with errno=%i (%s)", errno, strerror(errno)); 00198 } 00199 } 00200 00201 00202 /** Copy constructor. 00203 * The copy constructor is worth some extra discussion. If you do an exception 00204 * by value (which you shouldn't in the first place since this will generate a 00205 * copy, only do this if you can't avoid it for some reason. Not if you only 00206 * THINK that you can't avoid it) the copy constructor is called. If your catch 00207 * statements reads like 00208 * @code 00209 * try { 00210 * ... 00211 * } catch (Exception e) { 00212 * ... 00213 * } 00214 * @endcode 00215 * then a copy will be created for the catch block. You throw the exception with 00216 * something like 00217 * @code 00218 * throw Exception("Boom"); 00219 * @endcode 00220 * This will create an Exception which is valid in the block where you throw the 00221 * exception. Now for the catch block a copy is created. Since the exception 00222 * holds a pointer on the heap the implicit copy constructor would just copy 00223 * the pointer, not the data. So both exceptions point to the same data (to the 00224 * message for the base exception). If now both destructors for the exception 00225 * are called they both try to free the very same memory. Of course the second 00226 * destructor will cause a disaster. If you are lucky your glibc detectes the 00227 * problem an kills the application. If you are not that fortunate you will 00228 * cause very strange behaviour of your application. 00229 * 00230 * In general you should not have to worry about this. But if you choose to have 00231 * own storage on the heap using either new, malloc or a method that returns 00232 * memory on the heap (like strdup()) you have to write your own copy contructor 00233 * and copy the memory area or take care that only one exception frees the memory. 00234 * @param exc Exception to copy 00235 */ 00236 Exception::Exception(const Exception &exc) throw() 00237 { 00238 messages_mutex = new Mutex(); 00239 00240 messages = NULL; 00241 messages_end = NULL; 00242 messages_iterator = NULL; 00243 00244 _errno = exc._errno; 00245 copy_messages(exc); 00246 } 00247 00248 00249 /** Constructor for subclasses. 00250 * This constructor can be used in subclasses is some processing code is 00251 * needed (like sprintf) to assign the message. At least assign the empty 00252 * string to the message. 00253 */ 00254 Exception::Exception() throw() 00255 { 00256 messages_mutex = new Mutex(); 00257 _errno = 0; 00258 messages = NULL; 00259 messages_end = NULL; 00260 messages_iterator = NULL; 00261 } 00262 00263 00264 /** Destructor. */ 00265 Exception::~Exception() throw() 00266 { 00267 message_list_t *msg_this; 00268 messages_iterator = messages; 00269 while ( messages_iterator ) { 00270 free(messages_iterator->msg); 00271 msg_this = messages_iterator; 00272 messages_iterator = messages_iterator->next; 00273 free(msg_this); 00274 } 00275 messages = NULL; 00276 messages_end = NULL; 00277 delete messages_mutex; 00278 } 00279 00280 00281 /** Prepend messages to the message list. 00282 * @param format format of the message to prepend, see printf(3) for details about formatting 00283 * options. 00284 */ 00285 void 00286 Exception::prepend(const char *format, ...) throw() 00287 { 00288 // do not append empty messages 00289 if (format == NULL) return; 00290 00291 va_list arg; 00292 va_start(arg, format); 00293 messages_mutex->lock(); 00294 prepend_nolock_va(format, arg); 00295 messages_mutex->unlock(); 00296 va_end(arg); 00297 } 00298 00299 00300 /** Append messages to the message list. 00301 * @param format format of the message to append, see printf(3) for details about formatting 00302 * options. 00303 */ 00304 void 00305 Exception::append(const char *format, ...) throw() 00306 { 00307 // do not append empty messages 00308 if (format == NULL) return; 00309 00310 va_list arg; 00311 va_start(arg, format); 00312 messages_mutex->lock(); 00313 append_nolock_va(format, arg); 00314 messages_mutex->unlock(); 00315 va_end(arg); 00316 } 00317 00318 00319 /** Append messages to the message list. 00320 * @param format format of the message to append, see printf(3) for details about formatting 00321 * options. 00322 * @param va va_list with arguments matching the format 00323 */ 00324 void 00325 Exception::append_va(const char *format, va_list va) throw() 00326 { 00327 // do not append empty messages 00328 if (format == NULL) return; 00329 00330 messages_mutex->lock(); 00331 append_nolock_va(format, va); 00332 messages_mutex->unlock(); 00333 } 00334 00335 00336 /** Append message that are from another Exception. 00337 * @param e Exception to copy messages from 00338 */ 00339 void 00340 Exception::append(const Exception &e) throw() 00341 { 00342 copy_messages(e); 00343 } 00344 00345 00346 /** Append messages without lock. 00347 * this can be used to append messages without locking the mutex if the mutex 00348 * has been locked already to append many messages and keep their order intact 00349 * and thus to prevent messages to be appended inbetween. 00350 * Used for example in copy constructor. 00351 * @param format The format of the primary message. Supports the same 00352 * arguments as append(). The message is copied and not just referenced. 00353 * Thus the memory has to be freed if it is a dynamic string on the heap. 00354 */ 00355 void 00356 Exception::append_nolock(const char *format, ...) throw() 00357 { 00358 va_list arg; 00359 va_start(arg, format); 00360 00361 char *msg; 00362 if ( vasprintf(&msg, format, arg) == -1 ) { 00363 msg = strdup(format); 00364 } 00365 00366 va_end(arg); 00367 00368 if ( messages == NULL ) { 00369 // This is our first message 00370 messages = (message_list_t *)malloc(sizeof(message_list_t)); 00371 messages->next = NULL; 00372 messages->msg = msg; 00373 messages_end = messages; 00374 } else { 00375 message_list_t *ml = (message_list_t *)malloc(sizeof(message_list_t)); 00376 ml->next = NULL; 00377 ml->msg = msg; 00378 messages_end->next = ml; 00379 messages_end = ml; 00380 } 00381 } 00382 00383 00384 /** Prepend messages without lock by formatted string. 00385 * This can be used to append messages without locking the mutex if the mutex 00386 * has been locked already to append many messages and keep their order intact 00387 * and thus to prevent messages to be appended inbetween. 00388 * Used for example in copy constructor. 00389 * @param format format of the message to be appended 00390 * @param ap argument va_list for format 00391 */ 00392 void 00393 Exception::prepend_nolock_va(const char *format, va_list ap) throw() 00394 { 00395 char *msg; 00396 if ( vasprintf(&msg, format, ap) == -1 ) { 00397 msg = strdup(format); 00398 } 00399 00400 if ( messages == NULL ) { 00401 // This is our first message 00402 messages = (message_list_t *)malloc(sizeof(message_list_t)); 00403 messages->next = NULL; 00404 messages->msg = msg; 00405 messages_end = messages; 00406 } else { 00407 message_list_t *ml = (message_list_t *)malloc(sizeof(message_list_t)); 00408 ml->next = messages; 00409 ml->msg = msg; 00410 messages = ml; 00411 } 00412 } 00413 00414 00415 /** Append messages without lock by formatted string. 00416 * this can be used to append messages without locking the mutex if the mutex 00417 * has been locked already to append many messages and keep their order intact 00418 * and thus to prevent messages to be appended inbetween. 00419 * Used for example in copy constructor. 00420 * @param format format of the message to be appended 00421 * @param ap argument va_list for format 00422 */ 00423 void 00424 Exception::append_nolock_va(const char *format, va_list ap) throw() 00425 { 00426 char *msg; 00427 if ( vasprintf(&msg, format, ap) == -1 ) { 00428 msg = strdup(format); 00429 } 00430 00431 if ( messages == NULL ) { 00432 // This is our first message 00433 messages = (message_list_t *)malloc(sizeof(message_list_t)); 00434 messages->next = NULL; 00435 messages->msg = msg; 00436 messages_end = messages; 00437 } else { 00438 message_list_t *ml = (message_list_t *)malloc(sizeof(message_list_t)); 00439 ml->next = NULL; 00440 ml->msg = msg; 00441 messages_end->next = ml; 00442 messages_end = ml; 00443 } 00444 } 00445 00446 00447 /** Append message without copying. 00448 * Can be used in subclasses to append messages that have been allocated 00449 * on the heap. Use with extreme care. Do not add constant strings! This would 00450 * cause your application to crash since the destructor will try to free all 00451 * messages. The message list is not locked. 00452 * @param msg Message to append. 00453 */ 00454 void 00455 Exception::append_nolock_nocopy(char *msg) throw() 00456 { 00457 if ( messages == NULL ) { 00458 // This is our first message 00459 messages = (message_list_t *)malloc(sizeof(message_list_t)); 00460 messages->next = NULL; 00461 messages->msg = msg; 00462 messages_end = messages; 00463 } else { 00464 message_list_t *ml = (message_list_t *)malloc(sizeof(message_list_t)); 00465 ml->next = NULL; 00466 ml->msg = msg; 00467 messages_end->next = ml; 00468 messages_end = ml; 00469 } 00470 } 00471 00472 00473 /** Assign an Exception. 00474 * As this is one of the Big Three (see C++ FAQ at 00475 * http://www.parashift.com/c++-faq-lite/coding-standards.html#faq-27.10) this 00476 * is needed because we already need a copy constructor. Read about the 00477 * copy constructor why this is the case. 00478 * @see Exception(const Exception &exc) 00479 * @param exc The exception with the values to assign to this exception. 00480 * @return reference to this object. Allows assignment chaining. 00481 */ 00482 Exception & 00483 Exception::operator=(const Exception &exc) throw() 00484 { 00485 messages_mutex = new Mutex(); 00486 copy_messages(exc); 00487 00488 return *this; 00489 } 00490 00491 00492 /** Copy messages from given exception. 00493 * Copies the messages from exc to this exception. 00494 * @param exc Exception to copy messages from. 00495 */ 00496 void 00497 Exception::copy_messages(const Exception &exc) throw() 00498 { 00499 messages_mutex->lock(); 00500 exc.messages_mutex->lock(); 00501 00502 // copy messages 00503 messages_iterator = exc.messages; 00504 while ( messages_iterator ) { 00505 append_nolock(messages_iterator->msg); 00506 messages_iterator = messages_iterator->next; 00507 } 00508 00509 exc.messages_mutex->unlock(); 00510 messages_mutex->unlock(); 00511 } 00512 00513 00514 /** This can be used to throw this exception. 00515 * This can be used to throw this exception instance. This is a precaution if 00516 * it is needed. See C++ FAQ 17.10. 00517 */ 00518 void 00519 Exception::raise() 00520 { 00521 throw *this; 00522 } 00523 00524 00525 /** Prints a backtrace. */ 00526 void 00527 Exception::print_backtrace() const throw() 00528 { 00529 #ifdef HAVE_EXECINFO 00530 void * array[25]; 00531 int size = backtrace(array, 25); 00532 char ** symbols = backtrace_symbols(array, size); 00533 00534 printf("Backtrace:\n"); 00535 for (int i = 0; i < size; ++i) { 00536 printf(" %s\n", symbols[i]); 00537 } 00538 00539 free(symbols); 00540 #else 00541 printf("Backtrace not available on current system\n"); 00542 #endif 00543 } 00544 00545 00546 /** Generate backtrace string. 00547 * @return freshly allocated string of backtrace. Free after you are done. 00548 */ 00549 char * 00550 Exception::generate_backtrace() const throw() 00551 { 00552 #ifdef HAVE_BACKTRACE 00553 void * array[25]; 00554 int size = backtrace(array, 25); 00555 char ** symbols = backtrace_symbols(array, size); 00556 00557 size_t total_size = 1; //null termination 00558 for (int i = 0; i < size; ++i) { 00559 total_size += strlen(symbols[i]) + 1; 00560 } 00561 char *rv = (char *)calloc(1, total_size); 00562 char *r = rv; 00563 for (int i = 0; i < size; ++i) { 00564 sprintf(r, "%s\n", symbols[i]); 00565 r += strlen(symbols[i]); 00566 } 00567 00568 free(symbols); 00569 #else 00570 char *rv = strdup("Backtrace not available on current system\n"); 00571 #endif 00572 00573 return rv; 00574 } 00575 00576 00577 /** Prints trace to stderr. 00578 * This prints out a message trace of all messages appended to the exception 00579 * in chronological order starting with the oldest (first message appended 00580 * via constructor or append(). Output will be sent to stderr. 00581 */ 00582 void 00583 Exception::print_trace() throw() 00584 { 00585 messages_mutex->lock(); 00586 fprintf(stderr, 00587 "=================================================== BEGIN OF EXCEPTION =====\n"); 00588 if ( messages == NULL ) { 00589 fprintf(stderr, "No messages recorded.\n"); 00590 } else { 00591 messages_iterator = messages; 00592 while ( messages_iterator ) { 00593 fprintf(stderr, "%s\n", messages_iterator->msg); 00594 messages_iterator = messages_iterator->next; 00595 } 00596 } 00597 fprintf(stderr, 00598 "=================================================== END OF EXCEPTION =======\n"); 00599 messages_mutex->unlock(); 00600 } 00601 00602 00603 /** Get errno. 00604 * @return error number, may be 0 if not set 00605 */ 00606 int 00607 Exception::errno() throw() 00608 { 00609 return _errno; 00610 } 00611 00612 00613 /** Get primary string. 00614 * Messages are stored in a list. The first entry in this list is called primary 00615 * message. This is why it is important to have a meaningful first message! 00616 * @return Returns a constant char pointer with the message. The message is 00617 * private to the exception and may not be modified or freed (hence const) 00618 * If no message has been set "Unknown error" is returned. This method may be 00619 * overidden by other exceptions. 00620 * This method is also called by the runtime system if the exception was not 00621 * caught and resulted in a program termination. 00622 * @return string describing the general cause of the current error 00623 */ 00624 const char * 00625 Exception::what() const throw() 00626 { 00627 #ifdef HAVE_EXECINFO 00628 print_backtrace(); 00629 #endif 00630 if ( messages != NULL ) { 00631 return messages->msg; 00632 } else { 00633 return "Unknown error"; 00634 } 00635 } 00636 00637 00638 /** Get iterator for messages. 00639 * @return iterator for messages 00640 */ 00641 Exception::iterator 00642 Exception::begin() throw() 00643 { 00644 Exception::iterator i(messages); 00645 return i; 00646 } 00647 00648 00649 /** @class Exception::iterator <core/exception.h> 00650 * Message iterator for exceptions. 00651 * This iterator allows for iterating over all messages carried by an Exception. 00652 * @author Tim Niemueller 00653 */ 00654 00655 /** Get end iterator for messages. 00656 * @return end iterator for messages. 00657 */ 00658 Exception::iterator 00659 Exception::end() throw() 00660 { 00661 Exception::iterator i; 00662 return i; 00663 } 00664 00665 00666 /** Constructor. 00667 * @param message_list list of messages, will be used unlocked so use 00668 * with care. 00669 */ 00670 Exception::iterator::iterator(message_list_t *message_list) 00671 { 00672 mlist = message_list; 00673 } 00674 00675 00676 /** Plain constructor. 00677 * Creates a new invalid iterator (same as Exception::end()). 00678 */ 00679 Exception::iterator::iterator() 00680 { 00681 this->mlist = NULL; 00682 } 00683 00684 00685 /** Copy constructor. 00686 * @param i iterator to copy 00687 */ 00688 Exception::iterator::iterator(const Exception::iterator & i) 00689 { 00690 this->mlist = i.mlist; 00691 } 00692 00693 00694 /** Prefix ++ operator. 00695 * @return reference to this iterator after advancing. 00696 */ 00697 Exception::iterator & 00698 Exception::iterator::operator++() 00699 { 00700 if ( mlist != NULL ) { 00701 mlist = mlist->next; 00702 } 00703 return *this; 00704 } 00705 00706 00707 /** Postfix ++ operator. 00708 * @param inc used to denote postfix operator 00709 * @return copy of iterator before advancing. 00710 */ 00711 Exception::iterator 00712 Exception::iterator::operator++(int inc) 00713 { 00714 iterator i(mlist); 00715 if ( mlist != NULL ) { 00716 mlist = mlist->next; 00717 } 00718 return i; 00719 } 00720 00721 00722 /** Check equality. 00723 * @param i iterator to compare to 00724 * @return true, if iterators point to the same message, false otherwise 00725 */ 00726 bool 00727 Exception::iterator::operator==(const iterator & i) const 00728 { 00729 return (mlist == i.mlist); 00730 } 00731 00732 00733 /** Check inequality. 00734 * @param i iterator to compare to 00735 * @return true, if iterators point to different messages, false otherwise 00736 */ 00737 bool 00738 Exception::iterator::operator!=(const iterator & i) const 00739 { 00740 return (mlist != i.mlist); 00741 } 00742 00743 00744 /** Get current message. 00745 * Get message at current position. Returns NULL for the invalid ieterator. 00746 * @return message or NULL if iterator is invalid 00747 */ 00748 const char * 00749 Exception::iterator::operator* () const 00750 { 00751 if ( mlist != NULL ) { 00752 return mlist->msg; 00753 } else { 00754 return NULL; 00755 } 00756 } 00757 00758 00759 /** Assignment operator. 00760 * @param i iterator to assign to this iterator. 00761 * @return reference to this iterator. 00762 */ 00763 Exception::iterator & 00764 Exception::iterator::operator=(const iterator &i) 00765 { 00766 this->mlist = i.mlist; 00767 return *this; 00768 } 00769 00770 00771 } // end namespace fawkes

