OSSP CVS Repository

ossp - Check-in [2037]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 2037
Date: 2002-Mar-30 19:55:28 (local)
2002-Mar-30 18:55:28 (UTC)
User:rse
Branch:
Comment: Incorporate Thomas pitfall documentation into ex.pod and this way remove the last item from OSSP ex' TODO list.
Tickets:
Inspections:
Files:
ossp-pkg/ex/00TODO      1.3 -> 1.4     0 inserted, 90 deleted
ossp-pkg/ex/ex.pod      1.22 -> 1.23     145 inserted, 1 deleted

ossp-pkg/ex/00TODO 1.3 -> 1.4

--- 00TODO       2002/03/07 21:30:09     1.3
+++ 00TODO       2002/03/30 18:55:28     1.4
@@ -1,90 +0,0 @@
-
-**** IMPROVE DOCUMENTATION ****
-
-/* BAD EXAMPLE */
-try {
-    char *cp1, *cp2, cp3;
-
-    cp1 = mallocex(SMALLAMOUNT);
-    globalcontext->first = cp1;
-    cp2 = mallocex(TOOBIG);
-    cp3 = mallocex(SMALLAMOUNT);
-
-    strcpy(cp1, "foo"); strcpy(cp2, "bar");
-}
-clean {
-    if (cp3 != NULL) free(cp3);
-    if (cp2 != NULL) free(cp2);
-    if (cp1 != NULL) free(cp1);
-}
-catch(ex) {
-    printf("cp3=%s", cp3);
-    rethrow;
-}
-
-The code above shows some pitfalls and contains many errors.
-
-01) variable scope
-
-Variables which are used in the "clean" or "catch" blocks must be declared
-before "try", otherwise they only exists inside the "try" block. In the
-example above, cp1-3 are automatic variables and only exist in the "try"
-block, the "clean" and "catch" blocks don't know anything about them.
-
-02) variable initialization
-
-Variables which are used in the "clean" or "catch" blocks must be initialized
-before the point of the first possible "throw" is reached. In the example
-above, "clean" would have trouble using cp3 when mallocex() throws a exception
-when allocating a TOOBIG buffer.
-
-03) volatile variables
-
-Variables which are used in the "clean" or "catch" blocks must be declared
-volatile, otherwise they might contain outdated information when "throw" does
-the longjmp(). When using a "free if unset" mechanism like the example does in
-the "clean" block, the variables must be initialized (see 02) *and* remain
-valid upon use.
-
-04) clean before catch
-
-The "clean" block is evaluated before "catch", so resources being cleaned up
-must no longer be used in the "catch" block. The example above would have
-trouble referencing the character strings in the printf() statement because
-these have been free()d before.
-
-05) variable uninitialization
-
-When resources are passed away and out of the scope of the "try/clean/catch"
-construct and the variables were initialized for using a "free if unset"
-mechanism then they must be uninitialized after being passed away.  The
-example above would free() cp1 in the "clean" block when mallocex() throws a
-exception when allocating a TOOBIG buffer. The globalcontext->first pointer
-hence becomes invalid.
-
-/* GOOD EXAMPLE */                                       | /* ALTERNATE *05* GOOD EXAMPLE */
-{ /*01*/                                                 | { /*01*/
-    volatile /*03*/ char *cp1 = NULL /*02*/;             |     volatile /*03*/ char *cp1 = NULL /*02*/;
-    volatile /*03*/ char *cp2 = NULL /*02*/;             |     volatile /*03*/ char *cp2 = NULL /*02*/;
-    volatile /*03*/ char *cp3 = NULL /*02*/;             |     volatile /*03*/ char *cp3 = NULL /*02*/;
-    try {                                                |     try {
-        cp1 = mallocex(SMALLAMOUNT);                     |         cp1 = mallocex(SMALLAMOUNT);
-        globalcontext->first = cp1;                      |         globalcontext->first = cp1;
-        cp1 = NULL /*05 give away*/;                     |         /*05 keep responsibility*/
-        cp2 = mallocex(TOOBIG);                          |         cp2 = mallocex(TOOBIG);
-        cp3 = mallocex(SMALLAMOUNT);                     |         cp3 = mallocex(SMALLAMOUNT);
-                                                         | 
-        strcpy(cp1, "foo"); strcpy(cp2, "bar");          |         strcpy(cp1, "foo"); strcpy(cp2, "bar");
-    }                                                    |     }
-    clean {                                              |     clean {
- /*04*/ printf("cp3=%s", cp3 == NULL /*02*/ ? "" : cp3); |  /*04*/ printf("cp3=%s", cp3 == NULL /*02*/ ? "" : cp3);
-        if (cp3 != NULL) free(cp3);                      |         if (cp3 != NULL) free(cp3);
-        if (cp2 != NULL) free(cp2);                      |         if (cp2 != NULL) free(cp2);
-        /*05 cp1 was given away */                       |         if (cp1 != NULL) free(cp1);
-    }                                                    |     }
-    catch(ex) {                                          |     catch(ex) {
-        /*05 global context untouched */                 |         globalcontext->first = NULL;
-         rethrow;   }                                    |         rethrow;
-    }                                                    |     }
-}                                                        | }
-


ossp-pkg/ex/ex.pod 1.22 -> 1.23

--- ex.pod       2002/03/30 18:15:49     1.22
+++ ex.pod       2002/03/30 18:55:28     1.23
@@ -5,7 +5,7 @@
 ##  Copyright (c) 2002 Cable & Wireless Deutschland <http://www.cw.com/de/>
 ##
 ##  This file is part of OSSP ex, an exception library
-##  which can be found at http://www.ossp.org/pkg/ex/.
+##  which can be found at http://www.ossp.org/pkg/lib/ex/.
 ##
 ##  Permission to use, copy, modify, and distribute this software for
 ##  any purpose with or without fee is hereby granted, provided that
@@ -375,6 +375,150 @@
 alternative you can define C<__EX_NS_UCCXX__> to get the same but with a
 more namespace safe upper case first letter.
 
+=head1 PROGRAMMING PITFALLS
+
+Exception handling is a very elegant and efficient way of dealing with
+exceptional situation. Nevertheless it requires additional discipline
+in programming and there are a few pitfalls one must be aware of. Look
+the following code which shows some pitfalls and contains many errors
+(assuming a mallocex() function which throws an exception if malloc(3)
+fails):
+
+ /* BAD EXAMPLE */
+ ex_try {
+     char *cp1, *cp2, cp3;
+ 
+     cp1 = mallocex(SMALLAMOUNT);
+     globalcontext->first = cp1;
+     cp2 = mallocex(TOOBIG);
+     cp3 = mallocex(SMALLAMOUNT);
+     strcpy(cp1, "foo");
+     strcpy(cp2, "bar");
+ }
+ ex_clean {
+     if (cp3 != NULL) free(cp3);
+     if (cp2 != NULL) free(cp2);
+     if (cp1 != NULL) free(cp1);
+ }
+ ex_catch(ex) {
+     printf("cp3=%s", cp3);
+     ex_rethrow;
+ }
+
+This example raises a few issues:
+
+=over 4
+
+=item B<01: variable scope>
+
+Variables which are used in the B<ex_clean> or B<ex_catch> clauses
+must be declared before the B<ex_try> clause, otherwise they only
+exist inside the B<ex_try> block. In the example above, C<cp1>, C<cp2>
+and C<cp3> are automatic variables and only exist in the block of the
+B<ex_try> clause, the code in the B<ex_clean> and B<ex_catch> clauses
+does not know anything about them.
+
+=item B<02: variable initialization>
+
+Variables which are used in the B<ex_clean> or B<ex_catch> clauses must
+be initialized before the point of the first possible B<ex_throw> is
+reached. In the example above, B<ex_clean> would have trouble using
+C<cp3> if mallocex() throws a exception when allocating a C<TOOBIG>
+buffer.
+
+=item B<03: volatile variables>
+
+Variables which are used in the B<ex_clean> or B<ex_catch> clauses
+must be declared with the storage class C<volatile>, otherwise they
+might contain outdated information if B<ex_throw> throws an exception.
+If using a "free if unset" approach like the example does in the
+B<ex_clean> clause, the variables must be initialized (see B<02>) I<and>
+remain valid upon use.
+
+=item B<04: clean before catch>
+
+The B<ex_clean> clause is not only written down before the B<ex_catch>
+clause, it is also evaluated before the B<ex_catch> clause. So,
+resources being cleaned up must no longer be used in the B<ex_catch>
+block. The example above would have trouble referencing the character
+strings in the printf3) statement because these have been free()d
+before.
+
+=item B<05: variable uninitialization>
+
+If resources are passed away and out of the scope of the
+B<ex_try>/B<ex_clean>/B<ex_catch> construct and the variables were
+initialized for using a "free if unset" approach then they must be
+uninitialized after being passed away. The example above would free()
+C<cp1> in the B<ex_clean> clause if mallocex() throws an exception if
+allocating a C<TOOBIG> buffer. The C<globalcontext-&gt;first> pointer
+hence becomes invalid.
+
+=back
+
+As following is fixed version of the code (annotated with the pitfall
+items for reference):
+
+ /* GOOD EXAMPLE */
+ { /*01*/
+     volatile /*03*/ char *cp1 = NULL /*02*/;
+     volatile /*03*/ char *cp2 = NULL /*02*/;
+     volatile /*03*/ char *cp3 = NULL /*02*/;
+     try {
+         cp1 = mallocex(SMALLAMOUNT);
+         globalcontext->first = cp1;
+         cp1 = NULL /*05 give away*/;
+         cp2 = mallocex(TOOBIG);
+         cp3 = mallocex(SMALLAMOUNT);
+         strcpy(cp1, "foo");
+         strcpy(cp2, "bar");
+     }
+     clean {
+  /*04*/ printf("cp3=%s", cp3 == NULL /*02*/ ? "" : cp3);
+         if (cp3 != NULL) 
+             free(cp3);
+         if (cp2 != NULL) 
+             free(cp2);
+         /*05 cp1 was given away */                       
+     }                                                    
+     catch(ex) {                                          
+          /*05 global context untouched */                 
+          rethrow;   
+     }                                                    
+ }                                                        
+
+An alternative fixed version could also be:
+
+ /* ALTERNATE *05* GOOD EXAMPLE */
+ { /*01*/
+     volatile /*03*/ char *cp1 = NULL /*02*/;
+     volatile /*03*/ char *cp2 = NULL /*02*/;
+     volatile /*03*/ char *cp3 = NULL /*02*/;
+     try {
+         cp1 = mallocex(SMALLAMOUNT);
+         globalcontext->first = cp1;
+         /*05 keep responsibility*/
+         cp2 = mallocex(TOOBIG);
+         cp3 = mallocex(SMALLAMOUNT);
+         strcpy(cp1, "foo"); 
+         strcpy(cp2, "bar");
+     }
+     clean {
+  /*04*/ printf("cp3=%s", cp3 == NULL /*02*/ ? "" : cp3);
+         if (cp3 != NULL) 
+             free(cp3);
+         if (cp2 != NULL) 
+             free(cp2);
+         if (cp1 != NULL) 
+             free(cp1);
+     }
+     catch(ex) {
+         globalcontext->first = NULL;
+         rethrow;
+     }
+ }
+
+
 =head1 MULTITHREADING ENVIRONMENTS
 
 B<OSSP ex> is designed to work both in single-threading and

CVSTrac 2.0.1