OSSP CVS Repository

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

Check-in Number: 1860
Date: 2002-Feb-14 16:56:04 (local)
2002-Feb-14 15:56:04 (UTC)
User:rse
Branch:
Comment: don't forget the lessons learned today
Tickets:
Inspections:
Files:
ossp-pkg/ex/00TODO      added-> 1.1

ossp-pkg/ex/00TODO -> 1.1

*** /dev/null    Sat Nov 23 02:19:40 2024
--- -    Sat Nov 23 02:19:59 2024
***************
*** 0 ****
--- 1,90 ----
+ 
+ **** 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;
+     }                                                    |     }
+ }                                                        | }
+ 

CVSTrac 2.0.1