OSSP CVS Repository

ossp - ossp-pkg/ex/00TODO 1.3
Not logged in
[Honeypot]  [Browse]  [Directory]  [Home]  [Login
[Reports]  [Search]  [Ticket]  [Timeline
  [Raw

ossp-pkg/ex/00TODO 1.3

**** 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