Skip to main content

If you don't have an IBM ID and password, register here.

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

C++ exception-handling tricks for Linux

Four techniques for dealing with built-in language limitations

Sachin Agrawal (sachin_agrawal@in.ibm.com), Staff Software Engineer, IBM Software Labs, India
Sachin has been working extensively in C++ for more than six years, including three years of research into the C++ object models of various compilers. He currently works for IBM Global Services, India. You can contact him at sachin_agrawal@in.ibm.com.

Summary:  Handling exceptions in C++ has a few implicit restrictions at the language level, but you can get around them in some instances. Learn ways to make exceptions work for you so you can produce more reliable applications.

Date:  23 Feb 2005
Level:  Intermediate

Comments:  

Retaining exception source information

In C++, whenever an exception is caught within a handler, the information about the source of the exception is lost. The exact source of the exception could provide a lot of vital information to better handle it, or the information could be appended to the error log for postmortem.

To deal with this, you can generate a stack trace in the constructor of the exception object during the throw exception statement. ExceptionTracer is a class that demonstrates this behavior.


Listing 1. Generating a stack trace in the exception object constructor

 // Sample Program:
 // Compiler: gcc 3.2.3 20030502
 // Linux: Red Hat

 #include <execinfo.h>
 #include <signal.h>

 #include <exception>
 #include <iostream>

 using namespace std;

 /////////////////////////////////////////////

 class ExceptionTracer
 {
 public:
     ExceptionTracer()
     {
         void * array[25];
         int nSize = backtrace(array, 25);
         char ** symbols = backtrace_symbols(array, nSize);

         for (int i = 0; i < nSize; i++)
         {
             cout << symbols[i] << endl;
         }

         free(symbols);
     }
 };


Managing signals

Whenever a process performs an offending action such that the Linux™ kernel raises a signal, the signal must be handled. The signal handler generally releases the important resources and terminates the application. In this case, all the object instances on the stack are left un-destructed. On the other hand, if such signals are instead translated to C++ exceptions, you can gracefully invoke their destructors and program multiple levels of catch blocks to better deal with the signals.

However, you must remember the following:

  1. If the signal type is asynchronous or irrecoverable, this approach will not work. Not all the signal types are synchronous, meaning a different thread in that process may receive them. Also, a signal type may not be recoverable, and the process must shut down. To add to the complexity, a signal type on one kernel could be synchronous and on another kernel asynchronous. You can not write a single code that will work for all.

  2. Some Linux/UNIX systems require a stack fix-up before you can throw the C++ exception from within your signal handler. Again, the exact nature of stack fix-up depends on your kernel.

  3. In general, a signal that is translated to a Java Exception by any JVM on that platform can also be translated to a C++ exception.

SignalExceptionClass, defined in Listing 2, provides the abstraction of a C++ exception representing a signal that the kernel might rise. SignalTranslator is a template class based on SignalExceptionClass, which actually does the translation. There can be only one signal handler per signal per process active at any instant. Hence, SignalTranslator adopts a singleton design pattern. The whole concept is demonstrated using the SegmentationFault class for SIGSEGV and the FloatingPointException class for SIGFPE.


Listing 2. Translating signals to exceptions

 template <class SignalExceptionClass> class SignalTranslator
 {
 private:
     class SingleTonTranslator
     {
     public:
         SingleTonTranslator()
         {
             signal(SignalExceptionClass::GetSignalNumber(), SignalHandler);
         }

         static void SignalHandler(int)
         {
             throw SignalExceptionClass();
         }
     };

 public:
     SignalTranslator()
     {
         static SingleTonTranslator s_objTranslator;
     }
 };

 // An example for SIGSEGV
 class SegmentationFault : public ExceptionTracer, public exception
 {
 public:
     static int GetSignalNumber() {return SIGSEGV;}
 };

 SignalTranslator<SegmentationFault> g_objSegmentationFaultTranslator;

 // An example for SIGFPE
 class FloatingPointException : public ExceptionTracer, public exception
 {
 public:
     static int GetSignalNumber() {return SIGFPE;}
 };

 SignalTranslator<FloatingPointException> g_objFloatingPointExceptionTranslator;


Managing exceptions in constructors and destructors

Per ANSI C++, during construction and destruction of global (static global) variables, catching exceptions is not possible. Hence, ANSI C++ does not recommend throwing exceptions in the constructor and destructor of a class whose instances may be defined globally (static-globally). The other way to say it is, never define a global (static global) instance of a class whose constructor or destructor may throw exceptions. However, if you assume a specific compiler and a specific system, it may be doable, and fortunately, with GCC on Linux, it is.

This is demonstrated using the ExceptionHandler class, which again adopts a singleton design pattern. Its constructor registers an un-caught handler. Since there can be only one un-caught handler per process active at a time, the constructor should be invoked only once; hence, the reason for the singleton pattern. A global (static global) instance of ExceptionHandler should be defined prior to the definition of the actual global (static global) variable in question.


Listing 3. Handling exceptions in a constructor

 class ExceptionHandler
 {
 private:
     class SingleTonHandler
     {
     public:
         SingleTonHandler()
         {
             set_terminate(Handler);
         }

         static void Handler()
         {
             // Exception from construction/destruction of global variables
             try
             {
                 // re-throw
                 throw;
             }
             catch (SegmentationFault &)
             {
                 cout << "SegmentationFault" << endl;
             }
             catch (FloatingPointException &)
             {
                 cout << "FloatingPointException" << endl;
             }
             catch (...)
             {
                 cout << "Unknown Exception" << endl;
             }

             //if this is a thread performing some core activity
             abort();
             // else if this is a thread used to service requests
             // pthread_exit();
         }
     };

 public:
     ExceptionHandler()
     {
         static SingleTonHandler s_objHandler;
     }
 };

 //////////////////////////////////////////////////////////////////////////

 class A
 {
 public:
     A()
     {
         //int i = 0, j = 1/i;
         *(int *)0 = 0;
     }
 };

 // Before defining any global variable, we define a dummy instance
 // of ExceptionHandler object to make sure that
 // ExceptionHandler::SingleTonHandler::SingleTonHandler() is invoked
 ExceptionHandler g_objExceptionHandler;
 A g_a;

 //////////////////////////////////////////////////////////////////////////

 int main(int argc, char* argv[])
 {
     return 0;
 }


Handling exceptions in multi-threaded programs

Sometimes exceptions are left un-caught, which will cause the process to abort. Many times, however, processes contain multiple threads, where a few threads perform the core application logic while the rest service the external requests. If a service thread does not handle an exception due to programming error, it will kill the whole application. This may be undesirable as it promotes denial-of-service attacks by feeding illegal requests to the application. To avoid this, an un-caught handler can decide whether to invoke an abort or a thread-exit call. This is demonstrated towards the end of the ExceptionHandler::SingleTonHandler::Handler() function in Listing 3.


Conclusion

I've briefly discussed a few C++ programming design patterns to better perform the following tasks:

  • Tracing the source of exception while it is in process of being thrown.
  • Translating signals from the kernel to C++ exceptions.
  • Catching exceptions thrown during construction and/or destruction of global variables.
  • Exception handling in multithreaded processes.

I hope you're able to adopt some of these techniques to develop trouble-free code.


Resources

  • A classic text on C++ is The C++ Programming Language (Addison-Wesley, 1997) by Bjarne Stroustrup.

  • An excellent resource for understanding C++ internals is Inside the C++ Object Model (Addison-Wesley, 1996) by Stanley B. Lippman.

  • Don't forget also to check the system man pages for individual functions like backtrace(), backtrace_symbols(), signal(), abort(), and pthread_exit().

  • "Writing good exceptions" (developerWorks, May 2003) offers some practical advice on throwing and catching exceptions and refining your exception-handling sensibilities.

  • Java™ programmers might be interested to read "Best practices in EJB exception handling" (developerWorks, May 2002), which illustrates techniques for faster problem resolution.

  • Find more resources for Linux developers in the developerWorks Linux zone.

  • Get involved in the developerWorks community by participating in developerWorks blogs.

  • Browse for books on these and other technical topics.

  • Order the SEK for Linux, a two-DVD set containing the latest IBM trial software for Linux from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.

  • Innovate your next Linux development project with IBM trial software, available for download directly from developerWorks.

About the author

Sachin Agrawal

Sachin has been working extensively in C++ for more than six years, including three years of research into the C++ object models of various compilers. He currently works for IBM Global Services, India. You can contact him at sachin_agrawal@in.ibm.com.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in

If you don't have an IBM ID and password, register here.


Forgot your IBM ID?


Forgot your password?
Change your password


By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)


By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Linux
ArticleID=49678
ArticleTitle=C++ exception-handling tricks for Linux
publish-date=02232005
author1-email=sachin_agrawal@in.ibm.com
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).