Upload
ppd1961
View
1.090
Download
1
Tags:
Embed Size (px)
DESCRIPTION
Second part of my series on Exception Handling. Talks mostly of the stuff in C++. Prepared in 2007
Citation preview
Oct 11, 2007
Handling Exceptions in C++
Dr. Partha Pratim DasInterra Systems (India) Pvt. Ltd.
PART BPART B
04/12/23 22
Agenda
• PART A– Exception Fundamentals
– Exceptions in C• C Language Features
• C Standard Library Support
– SEH in Microsoft C
– Exceptions in C++• C++ Language Features
– try–catch–throw
– Exception Specifications
• C++ Standard Library Support
04/12/23 33
Agenda
• PART B– Exception Instrumentations in C++
• How Compilers Manage Exceptional Flow?
– Designing with Exceptions in C++• Goals
• Scope
• Anatomy of a Function
• Meyers Guidelines
04/12/23 44
Agenda
• PART C– Designing with Exceptions in C++
• Analysis & Design of an Exception-safe stack
• Exception behavior of Standard Library
• Handling Exceptions in Multithreaded Environment
• TR1 Proposal
04/12/23 55
PART BPART B
04/12/23 66
Exceptions Instrumentations in C++
How compilers manage How compilers manage Exceptional FlowExceptional Flow
04/12/23 77
Exception Handling: Issues• Code Isolation
– Separate Exceptions Flow from Normal Flow
– Separate Error Reporting from Error Handling
• Efficiency– Minimal Time Overhead for Normal Flow
– Minimal Space Overhead for Normal Flow
• Optimization– Minimize Loss of code optimizations under Exceptions
• Safety– Contain the vulnerability of the Program
04/12/23 88
Function Call: Instrumentations
• Normal Flow– return
• Exceptional Flow with Stack Cutting– setjmp / longjmp
• Exceptional Flow with Stack Unwinding– try-catch-throw
04/12/23 99
Function Call: Items• Normal Call
– Stack Frame
– Context
– Finalization
• Stack Cutting– Enhanced Stack Frame
– Exception Handler Frame
• Stack Unwinding– Destructor Thunk
– EH Handler
04/12/23 1010
Function Call Items: Stack Frame
• Function parameters
• Function return address
• Frame pointer
• Local Objects
• Callee save registers
04/12/23 1111
Function Call Items: Context
• Register PC / Return Address – (eip on x86)
• Register SP / Stack Pointer – (esp on x86)
• Register FP / Frame Pointer or Base Pointer – (ebp on x86)
04/12/23 1212
Function Call Items: Finalization
• How are the right destructors called in the right order? – On Normal Exit– On Exceptional Exit
• NOTE:– This is tricky once the function has a multiple
return statements before / after a number of local object constructions
04/12/23 1313
Function Call: Normal Flow
• Caller prepares the Parameters• Caller calls the Callee• Callee saves the Context (Function Prologue)• Callee does the job• Callee restores the Context (Function Epilogue)• Callee returns• Caller cleans up the Parameters• Caller uses the return value
04/12/23 1616
Function Call: Stack Cutting
• setjmp sets the jmp_buf buffer.#define _JBLEN 16#define _JBTYPE int// Define jump buffer layout for x86 setjmp/longjmp.typedef struct __JUMP_BUFFER { unsigned long Ebp; unsigned long Ebx; unsigned long Edi; unsigned long Esi; unsigned long Esp; unsigned long Eip; unsigned long Registration; unsigned long TryLevel; unsigned long Cookie; unsigned long UnwindFunc; unsigned long UnwindData[6];} _JUMP_BUFFER;typedef _JBTYPE jmp_buf[_JBLEN];
04/12/23 1717
Function Call: Stack Cutting
• longjmp forces the context (FP, SP and PC) to the jmp_buf buffer stored at setjmp point.
• Effect is – control resurfaces in setjmp and longjmp never returns.
• Stack is ‘CUT’:– Local objects are not finalized– All intervening frames are trashed
04/12/23 http://en.wikipedia.org/wiki/Thunk 1919
Function Call Items: Thunk
• A delayed computation
• Runtime registers a destructor thunk for the exception object.
• Catch handler calls the thunk at end.
04/12/23 2121
Function Call: Stack Unwinding
• Flow:– Creation of Exception object– Placement of destructor thunk for Exception object– Wrapping up of the stack frame.– Calling of Finalizers – ‘UNWIND’– Matching for Handler
• Catch handlers are statically overloaded but dynamically dispatched.
• Explain why this will need RTTI.
04/12/23 2222
Function Call: Stack Unwinding
• Flow:– Invocation of the right handler.– Exit from the handler – Invocation of the thunk if no rethrow has been
done.
04/12/23 2323
Function Call: Stack Unwinding
• Data Structures:– Stack Frame– RUNTIME_FUNCTION
– UNWIND_INFO– TRY_REGION_TABLE– CLEANUP_TABLE
04/12/23 2525
Designing with Exceptions in C++
Glimpses of Design IssuesGlimpses of Design Issues
04/12/23 2626
Designing with Exceptions: Goals
• “With Exceptions” !!!– Designing in spite of Exceptions?
– Designing with the help of Exceptions?
– Both.
04/12/23 2727
Designing with Exceptions: Goals
• Graded Goals– Do Nothing
– No Crash
– No Resource Leak
– Valid System State
– Unchanged System State
– Works ALWAYS
No Safety
Minimal Safety
Basic Safety
Strong Safety
No-Throw Safety
04/12/23 http://en.wikipedia.org/wiki/Exception_handling 2828
Exception Safety: Levels• No Exception Safety
– No guarantees are made.
– This is never acceptable in a production environment.
• Minimal Exception Safety– Partial execution of failed operations may store invalid data but
will not cause a crash.
– This may be acceptable for a graceful exit.
• Basic Exception Guarantee– Partial execution of failed operations can cause side effects
– Invariants on the state are preserved
– Any stored data will contain valid values.
04/12/23 http://en.wikipedia.org/wiki/Exception_handling 2929
Exception Safety: Levels• Strong Exception Guarantee (Commit or Rollback)
– Failed operations are guaranteed to have no side effects.
– Operations either succeed or have no effect at all.
• No-Throw Guarantee (Failure Transparency)– Operations are guaranteed to succeed and satisfy all requirements
even in presence of exceptional situations.
– Ideal; but may be unrealistic.
– Usually not possible in libraries where complete knowledge of the application is not available.
04/12/23 3030
Designing with Exceptions: Scope
• We Consider:– Function Calls
• Global Functions
• Static Methods
• Non-Static Methods
• Virtual Functions
• Operators (Overloaded)
– Objects• Automatic
• Dynamic
04/12/23 3131
Designing with Exceptions: Scope
• We do not consider:– Static Objects
– Asynchronous Exceptions
– Standard Library Objects
– STL Containers
– …
04/12/23 3232
C++ Ground Rules: Lifetime
• When does an object's lifetime begin?– When its constructor completes successfully
and returns normally.
• When does an object's lifetime end?– When its destructor begins.
• What is the state of the object after its lifetime has ended?– There is no object.
04/12/23 3333
C++ Ground Rules: Lifetime• Construction:
– An object is considered fully constructed when the control goes out of constructor.
• Destruction:– C++ refuses to call destructors for objects that haven't
been fully constructed – When an object is destructed, all fully constructed sub-
objects are destructed.
• Finalization: – Destructors for all local objects are called on exit
(except for abort(), exit() and longjmp()).
04/12/23 3434
Anatomy of a Function
• Safe Operations– Operations with built-in
types– Compiler Mechanisms
• Call, Return, Try, Throw, Catch
– Safe Functions• Unsafe Operations
– Functions– Construction– Copy Construction– Copy Assignment– Destruction– operator new / delete– …
class A { };A Viscera(
A x, // Argument CopyA& rx, A* px)
{ // Local objectsA a;A& ra = *px;A* pa = new A(rx);
try { // ...// Parameter CopyA a = // Return Value CopyViscera(a, *pa, &ra);// ...
} catch (A& e) {// Handler
} // Exception Destructor Thunk
// Exception Object Copythrow x; // Exception Exit
// Temporary Object Copyreturn a; // Normal Exit
} // Local Object Cleanup
04/12/23 3535
Exceptional Design Rules
Meyers’ Recommendations Meyers’ Recommendations on Basic Exception Safetyon Basic Exception Safety
04/12/23 More Effective C++ 3636
Exception Safety: Meyers Guidelines
• Item 9: Use destructors to prevent resource leaks
• Item 10: Prevent resource leaks in constructors
• Item 11: Prevent exceptions from leaving destructors
• Item 12: Understand how throwing an exception differs from passing a parameter or calling a virtual function
• Item 13: Catch exceptions by reference
• Item 14: Use exception specifications judiciously
• Item 15: Understand the costs of exception handling
04/12/23 More Effective C++, Example: PPD 3737
Meyers [9]: Use destructors to prevent resource leaks
• Situation
– A hierarchy of Polygonal objects
– Two methods:•Poly* readPoly(istream&)
– Read from input stream, and
– Create (through factory).•virtual void plotPoly()
– Object drawn on the plotter device
PolyPoly
QuadQuad TriTri
04/12/23 More Effective C++, Example: PPD 3838
Meyers [9]: Use destructors to prevent resource leaks
• Classesclass Poly { public:
virtual void plotPoly() = 0; ... };
class Quad: public Poly { public: virtual void plotPoly();
... };
class Tri: public Poly { public: virtual void plotPoly();
... };
04/12/23 More Effective C++, Example: PPD 3939
Meyers [9]: Use destructors to prevent resource leaks
• plot() for the Graphic Device (unsafe)void plot(istream& myStream) {
// while there's data while (myStream) {
// get next poly Poly *pPoly = readPoly(myStream);
// Plot the polygonpPoly->plotPoly();
// delete object that // readPoly returned delete pPoly;
} }
plotPoly() throws *pPoly leaks
04/12/23 More Effective C++, Example: PPD 4040
Meyers [9]: Use destructors to prevent resource leaks
• plot() for the Graphic Device (safe)void plot(istream& myStream) {
// while there's data while (myStream) {
// get next poly Poly *pPoly = readPoly(myStream);
try {// Plot the polygonpPoly->plotPoly();
} catch (...){
// delete object - exceptiondelete pPoly;throw; // passes on exception
}// delete object – no exceptiondelete pPoly;
} }
Code Duplication
Code Duplication
04/12/23 More Effective C++, Example: PPD 4141
Meyers [9]: Use destructors to prevent resource leaks
• Litter code with try and catch blocks. • Duplicate cleanup code
– Normal paths and – Exceptional paths. – Executes anyway!
• Move the cleanup code that must always be executed into the destructor for an object local to plot(). – Local objects are always destroyed when leaving a function,
regardless of how that function is exited.
• The solution is to replace the pointer with an object that acts like a pointer– aka, Smart Pointer
04/12/23 4242
Meyers [9]: Use destructors to prevent resource leaks
• Smart pointer – Is a C++ object
– Stores pointers to dynamically allocated (heap / free store) objects
– Improves raw pointers by implementing • Construction & Destruction
• Copying & Assignment
• Dereferencing:– operator–> – operator*
– Grossly mimics raw pointer syntax & semantics
04/12/23 More Effective C++, Example: PPD 4343
Meyers [9]: Use destructors to prevent resource leaks
• auto_ptrtemplate<class T> class auto_ptr { public:
// save ptr to object auto_ptr(T *p = 0): ptr_(p) {}
// delete ptr to object ~auto_ptr() { delete ptr_; }
// Indirection T* operator->() const { return ptr_; } ...
private: // raw ptr to object T *ptr_;
};
04/12/23 More Effective C++, Example: PPD 4444
Meyers [9]: Use destructors to prevent resource leaks
• plot() for the Graphic Device (safe)void plot(istream& myStream) {
// while there's data while (myStream) {
// get next poly auto_ptr<Poly> pPoly(readPoly(myStream));
// Plot the polygonpPoly->plotPoly();
} }
pPoly->plotPoly();
means
(pPoly.operator->())->plotPoly();
04/12/23 4545
Meyers [9]: Use destructors to prevent resource leaks
• Smart Pointers work as Holders of Resources
– RAII – Resource Acquisition is Initialization Idiom
– Scoped Acquisition – Release Paradigm• Acquires / Locks in Constructor
• Releases / Unlocks in Destructor
• Ensures safety on face of exceptions
04/12/23 More Effective C++, Example: PPD 4646
Meyers [9]: Use destructors to prevent resource leaks
• Window Handling in Windows OS (unsafe)
// This function leaks resources // if an exception is thrown void Display(const Information& info) {
HANDLE w = CreateWindow(/* Creation Parameters */);
/* Data preparations */RenderWindow(w, info, /* Display Parameters */); /* Data Cleanup */
DestroyWindow(w); }
04/12/23 More Effective C++, Example: PPD 4747
Meyers [9]: Use destructors to prevent resource leaks
• Window Holder// class for Holding (acquiring and // releasing) a window handle class WindowHolder { public:
WindowHolder(HANDLE h): w_(h) {} ~WindowHolder() { DestroyWindow(w_); }
operator HANDLE() { return w_; }private:
HANDLE w_;
// Stop free functions being available WindowHolder(const WindowHolder&); WindowHolder& operator=(const WindowHolder&);
};
04/12/23 More Effective C++, Example: PPD 4848
Meyers [9]: Use destructors to prevent resource leaks
• Window Handling in Windows OS (safe)
// This function cleans up resources - alwaysvoid Display(const Information& info) {
WindowHolder w(CreateWindow(/* Creation Parameters */));
/* Data preparations */// WindowHandle is implicitly converted to HANDLERenderWindow(w, info, /* Display Parameters */); /* Data Cleanup */
}
04/12/23 More Effective C++, Example: PPD 4949
Meyers [9]: Use destructors to prevent resource leaks
• Morale– Resources should be encapsulated inside
objects. – Usually avoids resource leaks in the face of
exceptions.
04/12/23 More Effective C++, Example: PPD 5050
More Questions
• What happens if an exception is thrown in the process of acquiring a resource, that is, in the constructor of a resource-acquiring class?
• What happens if an exception is thrown during the automatic destruction of such resources?
04/12/23 More Effective C++ 5151
Meyers [10]: Prevent resource leaks in constructors
• Consider:
class T { ... }; class T1 { public: T1(const T&); ... }; class T2 { public: T2(const T&); ... }; class A { public:
A(const T&, const T& = (T)0, const T& = (T)0); ~A(); void f(const T&); ...
private: T m_; T1 *p1_; T2 *p2_;
};
04/12/23 More Effective C++ 5252
Meyers [10]: Prevent resource leaks in constructors
• Constructor (unsafe) / Destructor:
A::A(const T& d, const T& s1, const T& s2):m_(d), p1_(0), p2_(0)
{if (s1 != (T)0)
p1_ = new T1(s1); // 1if (s2 != (T)0)
p2_ = new T2(s2); // 2}
A::~A(){
delete p1_;delete p2_’
}
04/12/23 More Effective C++ 5353
Meyers [10]: Prevent resource leaks in constructors
• Exception in body:– operator (T) may throw.– T::operator != may throw– T::operator new may throw bad_alloc
– Constructor for T1 or T2 may throw
• Exception at Line 1 is safe. – m_ gets destructed.
• Exception at Line 2 leaks p1_. – A::~A() does not get called as the object is not there.
A::A(const T& d, const T& s1, const T& s2):m_(d), p1_(0), p2_(0) {if (s1 != (T)0) p1_ = new T1(s1); // Line 1if (s2 != (T)0) p2_ = new T2(s2); // Line 2 }
04/12/23 More Effective C++ 5454
Meyers [10]: Prevent resource leaks in constructors
• Try Exception Fix by Dynamic Allocation– Doesn’t work as pA is never assigned if the following throws
• T::operator new
• Constructor for A
{ A *pA = 0; try {
pA = new A(d, s1, s2); ...
} catch (...) { // catch all exceptionsdelete pA; // delete pA on an exceptionthrow; // Rethrow exception
}delete pA; // delete pA normally
}
04/12/23 More Effective C++ 5555
Meyers [10]: Prevent resource leaks in constructors
• Constructor (safe) cleans up itselfA::A(const T& d, const T& s1, const T& s2):
m_(d), p1_(0), p2_(0){
try {if (s1 != (T)0)
p1_ = new T1(s1); // 1if (s2 != (T)0)
p2_ = new T2(s2); // 2} catch (...) {
delete p1_;delete p2_;throw;
}}
A::~A(){
delete p1_;delete p2_’
}
04/12/23 More Effective C++ 5656
Meyers [10]: Prevent resource leaks in constructors
• Constructor (safe): w/o code duplicationA::A(const T& d, const T& s1, const T& s2):
m_(d), p1_(0), p2_(0){
try {if (s1 != (T)0)
p1_ = new T1(s1); // 1if (s2 != (T)0)
p2_ = new T2(s2); // 2} catch (...) {
CleanUp();throw;
}}
A::~A(){
CleanUp();}
A::CleanUp(){
delete p1_;delete p2_;
}
04/12/23 More Effective C++ 5757
Meyers [10]: Prevent resource leaks in constructors
• Reconsider:
class T { ... }; class T1 { public: T1(const T&); ... }; class T2 { public: T2(const T&); ... }; class A { public:
A(const T&, const T& = (T)0, const T& = (T)0); ~A(); void f(const T&); ...
private: T m_; T1 * const p1_; T2 * const p2_;
};
04/12/23 More Effective C++ 5858
Meyers [10]: Prevent resource leaks in constructors
• Constructor (unsafe):
• Exception at Line 1 is safe. – m_ gets destructed.
• Exception at Line 2 leaks p1_. – A::~A() does not get called.
• No try-catch on Initializer list – only expressions.
A::A(const T& d, const T& s1, const T& s2):m_(d), p1_((s1 != (T)0)? new T1(s1): 0), // Line 1p2_((s2 != (T)0)? new T2(s2): 0) // Line 2
{ }
04/12/23 More Effective C++ 5959
Meyers [10]: Prevent resource leaks in constructors
• Constructor (safe):
T1* A::InitT1(const T&s) {if (s != (T)0) return new T1(s);else return (T1*)0; }
T2* A::InitT2(const T&s) {try {
if (s != (T)0) return new T2(s);else return (T2*)0;
} catch (...) {delete p1_;throw; }
}A::A(const T& d, const T& s1, const T& s2):
m_(d), p1_(InitT1(s1)), p2_(InitT2(s2)) { }
04/12/23 More Effective C++ 6060
Meyers [10]: Prevent resource leaks in constructors
• A better design:
class T { ... }; class T1 { public: T1(const T&); ... }; class T2 { public: T2(const T&); ... }; class A { public:
A(const T&, const T& = (T)0, const T& = (T)0); ~A(); void f(const T&); ...
private: T m_; const auto_ptr<T1> p1_; const auto_ptr<T2> p2_;
};
04/12/23 More Effective C++ 6161
Meyers [10]: Prevent resource leaks in constructors
• Constructor (safe by design):
• Exception at Line 1 is safe. – m_ gets destructed.
• Exception at Line 2 is safe. – m_ & p1_ get destructed.
// ConstructorA::A(const T& d, const T& s1, const T& s2):
m_(d), p1_((s1 != (T)0)? new T1(s1): 0), // Line 1p2_((s2 != (T)0)? new T2(s2): 0) // Line 2
{ }
// DestructorA::~A(){ }
04/12/23 More Effective C++, Example: PPD 6262
Meyers [10]: Prevent resource leaks in constructors
• Moral– Replace pointer class members with their
corresponding auto_ptr objects• Fortifies constructors against resource leaks in the
presence of exceptions,
• Eliminates the need to manually deallocate resources in destructors, and
• Allows const member pointers to be handled in the same graceful fashion as non-const pointers.
04/12/23 More Effective C++ 6363
Meyers [11]: Prevent exceptions from leaving destructors
• A destructor is called in two situations – When an object is destroyed under “normal”
conditions• When it goes out of scope or
• Is explicitly deleted.
– When an object is destroyed by the exception-handling mechanism during the stack-unwinding part of “exception propagation”.
04/12/23 More Effective C++ 6464
Meyers [11]: Prevent exceptions from leaving destructors
• Recap – If an exception is thrown when another
exception is active, terminate() is called and the program immediately terminates.
– From within a destructor, there is no robust way to determine if an exception is active.
04/12/23 More Effective C++ 6565
Meyers [11]: Prevent exceptions from leaving destructors
• Consider
class Session { public:
Session(); ~Session(); ...
private: static void logCreation(Session *); static void logDestruction(Session *);
};
Session::~Session() {// Fatal to throw herelogDestruction(this);
};
04/12/23 More Effective C++ 6666
Meyers [11]: Prevent exceptions from leaving destructors
• Manage the exceptions Session::~Session() {
try {logDestruction(this);
}catch (...) {
// Fatal again if operator<<() throwscerr << "Unable to log destruction of Session object"
<< "at address " << this << ".\n";
} };
04/12/23 More Effective C++ 6767
Meyers [11]: Prevent exceptions from leaving destructors
• Bite the dust – swallow the exceptions
Session::~Session() {try {
logDestruction(this);}catch (...) { }
};
04/12/23 More Effective C++ 6868
Meyers [11]: Prevent exceptions from leaving destructors
• Moral – Keep exceptions from propagating out of
destructors. • Prevents terminate from being called during the
stack-unwinding part of exception propagation.
• Helps ensure that destructors always accomplish everything they are supposed to accomplish.
04/12/23 More Effective C++ 6969
Meyers [12]: Throwing an exception differs from passing a parameter or calling a virtual function
• Control does not return to the throw site.
• Throw always copies the object.
• Catch needs to clean-up the thrown object.
• Parameter Matching is exact for Catch and done with the static type
• Overloaded Catch clauses are tried in lexical order.
04/12/23 More Effective C++ 7070
Meyers [13]: Catch exceptions by reference
04/12/23 More Effective C++ 7171
Meyers [14]: Use exception specifications judiciously
04/12/23 More Effective C++ 7272
Meyers [15]: Understand the costs of exception handling
04/12/23 7373
Handling Exceptions in C & C++
References & CreditsReferences & Credits
13-May-05 7474
References• Handling Exceptions: Part 1 – 4
– Robert Schmidt• Modern C++ Design: Generic Programming & Design Pattern Applied
– Andrei Alexandrescu• Exceptional C++ & More Exceptional C++
– Herb Sutter • Effective C++ & More Effective C++
– Scott Meyers• Standard Features Missing From VC++ 7.1. Part I: Exception
Specifications – Nemanja Trifunovic
http://www.codeproject.com/cpp/stdexceptionspec.asp • A Pragmatic Look at Exception Specifications
– http://www.gotw.ca/publications/mill22.htm
04/12/23 7575
Credits / Acknowledgements
04/12/23 7676
Thank You