CSC 2045 Week 07 Exception Handling PDF

Summary

This document provides an overview of exception handling in C++ with examples and explanations. It discusses different aspects of exception handling, such as when to use and when not to use exceptions.

Full Transcript

CSC 2045 EXCEPTION HANDLING STD::EXCEPTION OBJECTIVES AGENDA: WEEK 07 Understand the concept of exceptions, write 1. Exception Handling & Syntax code to handle exceptions using try-except bl...

CSC 2045 EXCEPTION HANDLING STD::EXCEPTION OBJECTIVES AGENDA: WEEK 07 Understand the concept of exceptions, write 1. Exception Handling & Syntax code to handle exceptions using try-except blocks, and be able to recognize and 2. Exception Handling diagnose common exceptions in a program. Guidelines Be familiar with commonly used coding 3. SEI Handle all Exceptions standards and conventions, and be able to 4. Review Exception Handling write clean, readable, secure, and 5. std::exception maintainable code following established coding standards for compliant code. 6. Detect Errors String to Number Identify rules to develop safe, reliable, and secure systems, by eliminating undefined 7. When NOT and TO use behaviors that can lead to undefined Exception Handling program behaviors and exploitable 8. Exception Handling vulnerabilities. & Efficiency EXCEPTION HANDLING An exception forces calling code to recognize an error condition and handle it. Unhandled exceptions stop program execution. An exception jumps to the point in the call stack that can handle the error. Intermediate functions can let the exception propagate. They don't have to coordinate with other layers. The exception stack-unwinding mechanism destroys all objects in scope after an exception is thrown, according to well-defined rules. An exception enables a clean separation between the code that detects the error and the code that handles the error. BASIC EXCEPTION HANDLING (W3SCHOOLS) Exception handling in C++ consist of three keywords: try, throw and catch The try statement allows you to define a block of code to be tested for errors while it is being executed. The throw keyword throws an exception when a problem is detected, which lets us create a custom error. The catch statement allows you to define a block of code to be executed, if an error occurs in the try block. The try and catch keywords come in pairs GUIDELINES EXCEPTION HANDLING (MSDN) Use exceptions when the code that handles the error is separated from the code that detects the error by one or more intervening function calls. Use exceptions to check for errors that might occur, for example, errors in input validation on parameters of public functions Throw exceptions by value, catch them by reference. To avoid making a needless copy of the exception object when it is passed to the handler. To avoid object slicing when catching a derived exception as a base class object. Don’t catch what you can't handle. EXCEPTION HANDLING (ISOCPP) What good can using exceptions do for me? The basic answer is: Using exceptions for error handling makes your code simpler, cleaner, and less likely to miss errors. But what’s wrong with “good old errno and if-statements”? The basic answer is: Using those, your error handling and your normal code are closely intertwined. That way, your code gets messy and it becomes hard to ensure that you have dealt with all errors (think “spaghetti code” or a “rat’s nest of tests”). EXCEPTION HANDLING (CPLUSPLUS) Exceptions provide a way to react to exceptional circumstances (like runtime errors) in programs by transferring control to special functions called handlers. To catch exceptions, a portion of code is placed under exception inspection. This is done by enclosing that portion of code in a try- block. When an exceptional circumstance arises within that block, an exception is thrown that transfers the control to the exception handler. If no exception is thrown, the code continues normally, and all handlers are ignored. MULTI CATCH EXCEPTIONS (CPLUSPLUS) Multiple handlers (i.e., catch expressions) can be chained; each one with a different parameter type. Only the handler whose argument type matches the type of the exception specified in the throw statement is executed. If an ellipsis (...) is used as the parameter of catch, that handler will catch any exception no matter what the type of the exception thrown. This can be used as a default handler that catches all exceptions not caught by other handlers: HANDLE ALL EXCEPTIONS All exceptions thrown by an application must be caught by a matching exception handler. Even if the exception cannot be gracefully recovered from, using the matching exception handler ensures that the stack will be properly unwound and provides an opportunity to gracefully manage external resources before terminating the process. One possible solution to comply with this rule, as well as with ERR50- CPP, is for the main() function to catch all exceptions. While this does not generally allow the application to recover from the exception gracefully, it does allow the application to terminate in a controlled fashion. HANDLE ALL EXCEPTIONS: NON-COMPLIANT Neither f() nor main() catch exceptions thrown by throwing_func(). Because no matching handler can be found for the exception thrown, std::terminate() is called. HANDLE ALL EXCEPTIONS: COMPLIANT The main entry point handles all exceptions, which ensures that the stack is unwound up to the main() function and allows for graceful management of external resources int main() { try { f(); } catch (...) { // Handle error } } HANDLE ALL EXCEPTIONS: NON-COMPLIANT The thread entry point function thread_start() does not catch exceptions thrown by throwing_func(). If the initial thread function exits because an exception is thrown, std::terminate() is called. HANDLE ALL EXCEPTIONS: COMPLIANT The thread_start() handles all exceptions and does not rethrow, allowing the thread to terminate normally. void thread_start(void) { try { throwing_func(); } catch (...) { // Handle error } } REVIEW EXCEPTION HANDLING Improving error recovery is one of the most powerful ways you can increase the robustness of your code. 1. Error-handling code is not nearly so tedious to write, and it doesn't become mixed up with your normal code. 2. Errors cannot be ignored. Use exceptions for truly exceptional conditions STANDARD EXCEPTIONS (CPLUSPLUS) Standard exceptions provides a consistent interface to handle errors through the throw expression. All exceptions generated by the standard library inherit from std::exception and defined in header. std::exception has a virtual member function called what() what() returns a null-terminated character sequence that can be overwritten in derived classes to contain some sort of description of the exception. Watch out that you don't violate information disclosure using the what() std::exception (links) description logic_error error related to the internal logic of the program errors that arise because an argument value has not been invalid_argument accepted errors from attempt to exceed defined length limits for an object length_error (std::string) out_of_range errors from attempt to access elements out of defined range bad_cast thrown by dynamic_cast when it fails in a dynamic cast runtime_error error detected during runtime report arithmetic overflow/underflow error: results from when a overflow_error computation is too large or too small for the destination type underflow_error (to_ulong and to_ullong) bad_alloc thrown by new on allocation failure ios_base::failure thrown on failure by the functions in the Input/Output library WHAT SHOULD BE CAUGHT DEMO #1? Research and then update to catch the most specific std::exception class. Does the catch order matter? WHAT SHOULD BE CAUGHT DEMO #2? Research and then update to catch the most specific std::exception class. What changes if operator[] is used instead? WHAT SHOULD BE CAUGHT DEMO #3 Research and then update to catch the most specific std::exception class. What type of exception is guaranteed? WHAT SHOULD BE CAUGHT DEMO #4 Fix the code block Research and then update to catch the most specific std::exception class. DETECT ERRORS: STRING TO NUMBER The process of parsing an integer or floating-point number from a string can produce many errors. The string might not contain a number. It might contain a number of the correct type that is out of range (such as an integer that is larger than INT_MAX). The string may also contain extra information after the number, which may or may not be useful after the conversion. These error conditions must be detected and addressed when a string- to-number conversion is performed using a formatted input stream such as std::istream DETECT ERRORS STRING TO NUMBER NON-COMPLIANT Multiple numeric values are converted from the standard input stream. However, if the text received from the standard input stream cannot be converted into a numeric value that can be represented by an int, the resulting value stored into the variables i and j may be unexpected. If the text 12345678901234567890 is the first converted value read from the standard input stream, then i will have the value std::numeric_limits::max() and j will be uninitialized. If the text abcdefg is the first converted value read from the standard input stream, then i will have the value 0 and j will remain uninitialized. DETECT ERRORS STRING TO NUMBER COMPLIANT Exceptions are enabled so that any conversion failure results in an exception being thrown. However, this approach cannot distinguish between which values are valid and which values are invalid and must assume that all values are invalid. Both the badbit and failbit flags are set to ensure that conversion errors as well as loss of integrity with the stream are treated as exceptions. DETECT ERRORS STRING TO NUMBER COMPLIANT Each converted value read from the standard input stream is tested for validity before reading the next value in the sequence, allowing error recovery on a per-value basis. It checks std::istream::fail() to see if the failure bit was set due to a conversion failure or whether the bad bit was set due to a loss of integrity with the stream object. If a failure condition is encountered, it is cleared on the input stream and then characters are read and discarded until a ' ' occurs. The error handling in this case only works if a space character is what delimits the two numeric values to be converted. WHEN NOT TO USE EXCEPTION HANDLING Exceptions are NOT the answer to all problems; overuse can cause trouble. Situations where exceptions are not warranted: Not for asynchronous events Not for benign error conditions Not for flow of control You are NOT forced to use exceptions New exceptions, old code The best advice for deciding when to use exceptions is to throw exceptions ONLY when a function fails to meet its specification. WHEN TO USE EXCEPTION HANDLING Start with standard exceptions Wrap functions (especially C library functions) that use ordinary error schemes, so they produce exceptions instead. Simplify. If your error handling scheme makes things more complicated, it is painful and annoying to use. Exceptions can be used to make error handling simpler and more effective. Make your library and program safer. This is a short-term investment (for debugging) and a long-term investment (for application robustness). EXCEPTION HANDLING & EFFICIENCY When an exception is thrown, there is considerable runtime overhead. For this reason, you never want to use exceptions as part of your normal flow-of-control Exceptions should occur only rarely, so the overhead is piled on the exception and not on the normally executing code. Think of a throw expression as a call to a special system function that takes the exception object as an argument and backtracks up the chain of execution. For this to work, extra information needs to be put on the stack by the compiler, to aid in stack unwinding.

Use Quizgecko on...
Browser
Browser