*** /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;
+ } | }
+ } | }
+
|