C H A P T E R  13

image

Exception Handling

Exception Handling in packetC

packetC utilizes a try-catch-throw exception-handling system similar to many modern languages, such as C++ and Java. In packetC, all exceptions must be caught whether they are system-defined or application-defined. That means that all applications must be wrapped within an error-handler to accommodate catching any errors that may be thrown by the functionality utilized. Any possible errors thrown by an application that are not caught will be flagged by the compiler and compilation will not be allowed to proceed.

Identifiers used by the exception-handling system are named-constants that are either pre-defined by the system or defined by the application to catch exceptions thrown by a portion of the application. Further study on this method of error-handling will show how this can either dominate the architecture of an application or help to keep error-handling out of the primary processing flow, depending upon the amount of up-front planning performed. Additionally, just like other parts of packetC are heavily influenced by scope, so is exception-handling. Ensuring that the scope of caught exceptions is being handled where they are thrown will help to avoid the common application-created exceptions that are trying to be handled at too global of a scope.

For every opcode that produces a possible exception, a location to catch the exception must be present. This leads to the requirement described above whereby the compiler ensures that a program has caught every possible exception to successfully compile. Performance of this approach is enhanced as the opcode itself has the location of the exception-handler and it is not up to additional or subjectively-handled code to determine whether an exception has occurred and whether to handle it. This also ensures more secure code as undetected errors can lead to assumptions about input criteria that may not be visible in a simple audit of a control flow.

The following section describes the control flow within a packetC application. It is important to note that some aspects of the control-flow and exceptions may generate conditions where the application cannot handle the response. This may include the failure of an opcode to perform its expected task. As such, some hypervisor errors will generate exceptions handled by a control plane. While this is out of the scope of packetC, it is important to understand the possibility of that interaction. For example, should the underlying system be unable to receive packets due to an operating system issue, this is out of the scope of a packetC application to handle and as such the exception will not be presented to packetC in the data plane but rather a control plane processor for an exception handler.

Try-Catch-Throw Statements (Error Handling)

try  compound_statement  catch_list
catch  (  identifier )  compound_statement
catch  (  …  )  compound_statement

Error Handling (try-catch-throw)

packetC uses try-catch-throw error-handling for cleaner code and more advanced error-handling possibilities. Ignoring the fact that not handling errors is very bad programming practice, several methods for error handling we explored and the migration to this mechanism similar to C++ provided the cleanest control flow and deterministic handling. Other possible methods for error handling ranged from return-code testing to On Error handling, both of which did not join well with the flow of packetC applications nor the performance attributes. Try-catch in packetC provides benefits in speed and size, with the added bonus of providing a less error-prone way to handle errors. Given that try-catch-throw is the error-handling method that most modern-day programming languages use, advancing packetC away from the primitive return-code handling of C meets many of the exception-handling demands of a real-time system.

try {
    pkt.replicate();
    ...
    // other statements
}
catch( ERR_PKT_NOREPLICATE )  // catch just this error
{…}
catch( ... )                  // catch all other errors
{…}

If an exception is thrown in the code sequence of a try block, subsequent statements in the sequence are skipped and the code in the catch block handling the exception is executed.

Try and Catch Statements

packetC provides try, catch, and throw constructs as the basis for user error handling. The try construct effectively connects a try block (which may consist of a single packetC statement or a compound statement) with a related group of catch constructs—a catch block. If the execution of any construct in the try block triggers a recognized packetC system error (see table below) or triggers a throw statement, the associated catch block must handle that error.

catch constructs either respond to a single error (identified by a named int constant within parentheses) or handle all errors, indicated by (an ellipsis) in parentheses. catch statements cannot appear by themselves, they must be associated with a matching try construct.

try {
    pkt.replicate();
    …
    // other statements
}
catch( ERR_PKT_NOREPLICATE )  // catch just this error
{…}
catch( ... )                  // catch all other errors
{…}

Each catch clause is associated with one or more statements within curly braces, which take user-specified actions in response to the named error condition. Catch clauses with only one statement must place that statement within curly braces. packetC and C++ both have this requirement.

An implementation may optionally analyze the position of catch-all clauses and issue warnings about catch clauses or catch-all clauses that can never be executed.

// legal – explicit catch clause handles relevant error
try  { pkt.replicate(); }
catch (  ERR_PKT_NOREPLICATE  )  {…}

// legal – catch-all clause is present
try  { pkt.replicate(); }
catch ( ... ) {…}

// ERROR: no catch clause for replicate construct's ERR_PKT_NOREPLICATE
try { pkt.replicate(); }
catch ( ERR_PKT_NOTREQUEUED )  {…}
Implicit Throw Statements

Some packetC constructs are capable of implicitly throwing a predefined error when they appear within a try statement or block of statements (see Table 13-1). It is a compilation error if any system error that could be thrown by a packetC construct is not handled by an associated catch clause. This requires the construct that could throw the error to appear within a try block.

images

a  =  b;
pkt.replicate();  // ERROR: ERR_PKT_NOREPLICATE not handled
b  =  c;

pkt.replicate();
catch ( ERR_PKT_NOREPLICATE )  {…}
// Error: catch cannot appear stand-alone;
// must be associated with a try construct.
Explicit Throw Statements

A throw statement explicitly throws the solitary error indicated by its lone argument. That error is a unique constant of type int and is either a predefined system error (as listed in the table above and in file cloudshield.ph) or an error defined by the user. It is a compilation error for the thrown error not to be caught by an appropriate catch statement.

The placement and behavior of throw statements are governed by these rules:

  • A throw statement must appear within a statement block associated with a try statement: to do otherwise is an error.
  • The throw statement may be within a nesting level deeper than that of the governing try block. This includes appearing within a catch block associated with some try block nested more deeply than the governing try block (see below).
  • A throw statement's error is matched against the catch clauses of the innermost try block that encloses it. It is a compilation error if none of these catch clauses handles the error. packetC does not propagate the error to any successive, outer nesting scopes for comparison against their catch clauses.
// Assume SOME_ERROR, SOME_OTHER_ERROR are defined "const ints"
try  {
        …
         throw SOME_ERROR;
     }
       catch ( SOME_OTHER_ERROR )  {…}
     catch (…) {…}          // Catch all other errors (SOME_ERROR in this case)

In the following example, both of the throw statements are handled by the same catch clause.

try {
         try {
                 ...
         }
         catch( ERR_DB_FULL ) {
                 ...
                 throw MY_ERROR; // outer try is the enclosing try block
         }
         catch( ... ) {
                 ...
         }

   ...
   throw MY_ERROR;
   ...
}

catch( ERR_PKT_NOREPLICATE ) {  
       ...
}
catch( MY_ERROR ) {
       ...
}

In the following example, the throw statement throws an error outside of any try-block, creating an unhandled error.

try  {
             ...
}
catch ( AN_ERROR )  {
    ...
    throw SOME_ERROR; // thrown outside of catch's associated try-block
}
catch ( OTHER_ERROR ) {}
catch (…) {…}
// COMPILER ERROR: SOME_ERROR throw statement does not appear
// within any enclosing try block
User-Defined Errors

A packetC implementation lists all the error numbers it uses for predefined packetC errors (i.e., those implicitly thrown by packetC commands) in the include file “cloudshield.ph”. It is recommended that the user use the ERR_LAST_DEFINED, which is defined as the highest integer value used for system-defined errors. User-provided error numbers can calculate their values in terms of ERR_LAST_DEFINED to ensure unique values.

const int USER_ERROR1 = ERR_LAST_DEFINED + 1;
const int USER_ERROR2 = ERR_LAST_DEFINED + 2;
const int USER_ERROR3 = ERR_LAST_DEFINED + 3;

System-Defined Response

This section lists the conditions for which a packetC implementation should describe system-defined responses. While packetC does not prescribe specific behavior for these various states, it does not ascribe “undefined behavior” for them, as C99 does.

  • Divide by zero: a divide or remainder operator was executed with a zero divisor.
  • Illegal array slice range: a range expression for an array slice was not determinable at compile time and at run time yielded an illegal value (i.e., array indices out of bounds, range with right-hand expression less than left-hand expression).

Errors Section from cloudshield.ph

packetC uses the following declarations, available in the file cloudshield.ph for the user to reference.

/* The pre-defined packetC errors and their associated values are shown below:
const int  ERR_DB_FULL          = 1;
const int  ERR_DB_READ          = 2;
const int  ERR_DB_NOMATCH      = 3;
const int  ERR_PKT_INSERT       = 4;
const int  ERR_PKT_DELETE      = 5;
const int  ERR_PKT_NOREPLICATE = 6;
const int  ERR_SET_NOMATCH     = 7;
const int  ERR_SET_NOTFOUND    = 9;
const int  ERR_PKT_NOTREQUEUED = 10;
*/
const int  ERR_LAST_DEFINED    = 64;

Simple Program Flow with Try-Catch-Throw Implemented

packet module searchpayload;
#include <cloudshield.ph>;
#include <protocols.ph>;

regex searchset regexSet[2][4] = {"GET", "POST"};
%pragma datatype regexSet ( regex1 );

void main( $PACKET pkt, $PIB pib, $SYS sys )
{
   searchResult rslt;
   
    try {
      rslt = regexSet.find( pkt[pib.payloadOffset:end] );
      pib.action = FORWARD_PACKET;
   }
   catch ( ERR_SET_NOTFOUND )
   {
      pib.action = DROP_PACKET;
   }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.104.183