Test out lclint and its4 on com_err library. One lclint error left on Solaris,
authorKen Raeburn <raeburn@mit.edu>
Wed, 8 Nov 2000 05:46:18 +0000 (05:46 +0000)
committerKen Raeburn <raeburn@mit.edu>
Wed, 8 Nov 2000 05:46:18 +0000 (05:46 +0000)
due to deficiencies in lclint.  Its4 chokes in parser.

* com_err.h (struct error_table): Annotate MSGS as pointing to 'shared' data.
(error_message): Returned data is 'observer' and 'dependent'; modifies internal
state.
* com_err.c (default_com_err_proc): Cast various return values to void.
(reset_com_err_hook): Use NULL, not 0.
(com_err_hook): Annotate as 'null'.
* error_table.h (_et_list): Annotate as 'null' and 'dependent'.
(struct et_list): Annotate NEXT as 'dependent' and 'null', and TABLE as
'dependent'.
(struct dynamic_et_list): Duplicate et_list definition, except NEXT is
annotated as 'only' instead of 'dependent'.
(error_table_name, error_table_name_r): Annotate for lclint.
* et_h.awk: Add lclint annotations for initialize_* functions.
* error_message.c (_et_list): Can be 'null'.
(error_message): Explicitly compare against zero.  Cast strerror arg to int.
(et_list_dynamic): New variable, for dynamically allocated list elements;
_et_list is now for statically allocated elements only.
(add_error_table, remove_error_table): Check both lists.
* et_name.c (error_table_name, error_table_name_r): Annotate for lclint.
* init_et.c (et_add_error_table): Change "link" to "e" to avoid confusion with
C library function in analysis tools.
* et1.et, et2.et, t_com_err.c: New files.  Exercise addition and removal of
error tables from list, using both interfaces.
* Makefile.in (LCLINT, LCLINTOPTS, ITS4, ITS4OPTS): New variables.
(do-lclint, do-its4, et1.o, et2.o, t_com_err.o, t_com_err): New targets.  Not
automatically invoked at present.
(FILES): Updated.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@12855 dc483132-0cff-0310-8789-dd5450dbe970

12 files changed:
src/util/et/ChangeLog
src/util/et/Makefile.in
src/util/et/com_err.c
src/util/et/com_err.h
src/util/et/error_message.c
src/util/et/error_table.h
src/util/et/et1.et [new file with mode: 0644]
src/util/et/et2.et [new file with mode: 0644]
src/util/et/et_h.awk
src/util/et/et_name.c
src/util/et/init_et.c
src/util/et/t_com_err.c [new file with mode: 0644]

index 9fa415fb6486df80c95305a0919ebff0bc3329ca..f64c89cfbafebcc5b0e71ab5ed14246b05089f9f 100644 (file)
@@ -1,3 +1,41 @@
+2000-11-08  Ken Raeburn  <raeburn@mit.edu>
+
+       Test out lclint and its4 on com_err library.  One lclint error
+       left on Solaris, due to deficiencies in lclint.  Its4 chokes in
+       parser.
+       * com_err.h (struct error_table): Annotate MSGS as pointing to
+       'shared' data.
+       (error_message): Returned data is 'observer' and 'dependent';
+       modifies internal state.
+       * com_err.c (default_com_err_proc): Cast various return values to
+       void.
+       (reset_com_err_hook): Use NULL, not 0.
+       (com_err_hook): Annotate as 'null'.
+       * error_table.h (_et_list): Annotate as 'null' and 'dependent'.
+       (struct et_list): Annotate NEXT as 'dependent' and 'null', and
+       TABLE as 'dependent'.
+       (struct dynamic_et_list): Duplicate et_list definition, except
+       NEXT is annotated as 'only' instead of 'dependent'.
+       (error_table_name, error_table_name_r): Annotate for lclint.
+       * et_h.awk: Add lclint annotations for initialize_* functions.
+       * error_message.c (_et_list): Can be 'null'.
+       (error_message): Explicitly compare against zero.  Cast strerror
+       argument to int.
+       (et_list_dynamic): New variable, for dynamically allocated list
+       elements; _et_list is now for statically allocated elements only.
+       (add_error_table, remove_error_table): Check both lists.
+       * et_name.c (error_table_name, error_table_name_r): Annotate for
+       lclint.
+       * init_et.c (et_add_error_table): Change "link" to "e" to avoid
+       confusion with C library function in analysis tools.
+       * et1.et, et2.et, t_com_err.c: New files.  Exercise addition and
+       removal of error tables from list, using both interfaces.
+       * Makefile.in (LCLINT, LCLINTOPTS, ITS4, ITS4OPTS): New
+       variables.
+       (do-lclint, do-its4, et1.o, et2.o, t_com_err.o, t_com_err): New
+       targets.  Not automatically invoked at present.
+       (FILES): Updated.
+
 2000-11-01  Ezra Peisach  <epeisach@mit.edu>
 
        * configure.in: Change AC_CONST to AC_C_CONST, AC_HEADER_EGREP to
index f97b5aadcda84ebf424f38f38dd1b9da6dbb170f..94e188ffcc7a11a07dd34676ce5732a51b1993cf 100644 (file)
@@ -34,6 +34,7 @@ FILES=        Makefile et_name.c error_message.c compile_et.c \
                com_err.c com_err.h \
                error_table.h mit-sipb-copyright.h \
                test_et.c test1.et test2.et \
+               t_com_err.c et1.et et2.et \
                compiler.h internal.h \
                com_err.texinfo texinfo.tex
 #SRCS= compile_et.c error_table.c error_message.c et_name.c \
@@ -79,9 +80,37 @@ et_lex.lex.o: et_lex.lex.c
 test1.o: test1.c
 test2.o: test2.c
 test_et.o: test1.h test2.h
+et1.o: et1.c
+et2.o: et2.c
+t_com_err.o: et1.h et2.h t_com_err.c
+
+# /u1/kr/lclint-2.5m/bin/lclint -warnposix -D__sparc
+LCLINT=lclint
+# +posixlib    gets more complete errno list than ansilib
+# -usedef      turns off bogus warnings from poor dataflow analysis (should be
+#              redundant with gcc warnings anyways)
+# -warnposix
+# +charintliteral
+# +ignoresigns
+# -predboolint
+# -exportlocal
+# -retvalint   allow ignoring of int return values (e.g., fputs)
+LCLINTOPTS=+posixlib \
+       -usedef -warnposix +charintliteral +ignoresigns -predboolint \
+       -exportlocal -retvalint \
+       +mod-uncon +modinternalstrict +modfilesys \
+       -expect 1
+do-lclint: error_table.y et_lex.lex.c
+       $(LCLINT) $(LCLINTOPTS) $(LOCALINCLUDES) $(DEFS) $(SRCS)
+ITS4=its4
+ITS4OPTS=
+do-its4: error_table.y et_lex.lex.c
+       $(ITS4) $(ITS4OPTS) $(SRCS)
 
 test_et: test_et.o test1.o test2.o $(LIBOBJS)
        $(CC) -o test_et test_et.o test1.o test2.o $(LIBOBJS)
+t_com_err: t_com_err.o et1.o et2.o $(LIBOBJS)
+       $(CC) -o t_com_err t_com_err.o et1.o et2.o $(LIBOBJS)
 
 all-unix:: compile_et includes
 
index 7bb081048df4a8c67b6dc3cd7666c737af02f023..19a30a0b089e77e940d7caf78509cc55040f8c7b 100644 (file)
@@ -33,7 +33,7 @@
 static void MacMessageBox(char *errbuf);
 #endif
 
-static et_old_error_hook_func com_err_hook = 0;
+static /*@null@*/ et_old_error_hook_func com_err_hook = 0;
 
 static void default_com_err_proc
 ET_P((const char FAR *whoami, errcode_t code,
@@ -60,7 +60,8 @@ static void default_com_err_proc(whoami, code, fmt, ap)
                strncat (errbuf, " ", sizeof(errbuf) - 1 - strlen(errbuf));
        }
        if (fmt)
-               vsprintf (errbuf + strlen (errbuf), fmt, ap);
+           /* ITS4: ignore vsprintf */
+           vsprintf (errbuf + strlen (errbuf), fmt, ap);
        errbuf[sizeof(errbuf) - 1] = '\0';
 
 #ifdef macintosh
@@ -148,7 +149,7 @@ et_old_error_hook_func reset_com_err_hook ()
 {
        et_old_error_hook_func x = com_err_hook;
     
-       com_err_hook = 0;
+       com_err_hook = NULL;
        return x;
 }
 #endif
index 7a8858b38611c8b5ef4b345c6211469823989c8f..268ccf5ee2194bdf958845886d4555c7b6a65938 100644 (file)
@@ -59,7 +59,7 @@ typedef void (*et_old_error_hook_func) ET_P((const char FAR *, errcode_t,
                                             const char FAR *, va_list ap));
        
 struct error_table {
-       char const FAR * const FAR * msgs;
+       /*@shared@*/ char const FAR * const FAR * msgs;
        unsigned long base;
        unsigned int n_msgs;
 };
@@ -73,8 +73,9 @@ KRB5_DLLIMP extern void KRB5_CALLCONV_C com_err
 KRB5_DLLIMP extern void KRB5_CALLCONV com_err_va
        ET_P((const char FAR *whoami, errcode_t code, const char FAR *fmt,
              va_list ap));
-KRB5_DLLIMP extern const char FAR * KRB5_CALLCONV error_message
-       ET_P((errcode_t));
+KRB5_DLLIMP extern /*@observer@*//*@dependent@*/ const char FAR * KRB5_CALLCONV error_message
+       ET_P((errcode_t))
+       /*@modifies internalState@*/;
 KRB5_DLLIMP extern errcode_t KRB5_CALLCONV add_error_table
        ET_P((const struct error_table FAR *));
 KRB5_DLLIMP extern errcode_t KRB5_CALLCONV remove_error_table
index b4a0537cf670bcaaa7ead0c046729e19eb830625..615530684a4fe09652226d22fe353df882a0b001 100644 (file)
@@ -55,26 +55,45 @@ static struct et_list * _et_list = (struct et_list *) NULL;
 struct et_list * _et_list = (struct et_list *) NULL;
 #endif
 
-KRB5_DLLIMP const char FAR * KRB5_CALLCONV error_message(code)
-       long code;
+/*@null@*//*@only@*/static struct dynamic_et_list * et_list_dynamic;
+
+#ifdef _MSDOS
+/*
+ * Win16 applications cannot call malloc while the DLL is being
+ * initialized...  To get around this, we pre-allocate an array
+ * sufficient to hold several error tables.
+ */
+#define PREALLOCATE_ETL 32
+static struct et_list etl[PREALLOCATE_ETL];
+static int etl_used = 0;
+#endif
+
+KRB5_DLLIMP const char FAR * KRB5_CALLCONV
+error_message(long code)
+    /*@modifies internalState@*/
 {
        unsigned long offset;
        unsigned long l_offset;
        struct et_list *et;
+       struct dynamic_et_list *det;
        unsigned long table_num;
        int started = 0;
        unsigned int divisor = 100;
        char *cp;
+       const struct error_table *table;
 
        l_offset = (unsigned long)code & ((1<<ERRCODE_RANGE)-1);
        offset = l_offset;
        table_num = ((unsigned long)code - l_offset) & ERRCODE_MAX;
-       if (!table_num) {
+       if (table_num == 0) {
                if (code == 0)
                        goto oops;
 
+               /* This could trip if int is 16 bits.  */
+               if ((unsigned long)(int)offset != offset)
+                   abort ();
 #ifdef HAVE_STRERROR
-               cp = strerror(offset);
+               cp = strerror((int) offset);
                if (cp)
                        return cp;
                goto oops;
@@ -90,17 +109,46 @@ KRB5_DLLIMP const char FAR * KRB5_CALLCONV error_message(code)
 #endif /* HAVE_STRERROR */
        }
 
-       et = _et_list;
-       while (et) {
+#ifndef DEBUG_TABLE_LIST
+#define dprintf(X)
+#else
+#define dprintf(X) printf X
+#endif
+
+       dprintf (("scanning static list for %x\n", table_num));
+       for (et = _et_list; et != NULL; et = et->next) {
+           dprintf (("\t%x = %s\n", et->table->base & ERRCODE_MAX,
+                     et->table->msgs[0]));
            if ((et->table->base & ERRCODE_MAX) == table_num) {
-                       /* This is the right table */
-                       if (et->table->n_msgs <= offset)
-                               break;
-                       return(et->table->msgs[offset]);
-               }
-               et = et->next;
+               table = et->table;
+               goto found;
+           }
+       }
+       dprintf (("scanning dynamic list for %x\n", table_num));
+       for (det = et_list_dynamic; det != NULL; det = det->next) {
+           dprintf (("\t%x = %s\n", det->table->base & ERRCODE_MAX,
+                     det->table->msgs[0]));
+           if ((det->table->base & ERRCODE_MAX) == table_num) {
+               table = det->table;
+               goto found;
+           }
        }
+       goto no_table_found;
+
+ found:
+       dprintf (("found it!\n"));
+       /* This is the right table */
+
+       /* This could trip if int is 16 bits.  */
+       if ((unsigned long)(unsigned int)offset != offset)
+           goto no_table_found;
 
+       if (table->n_msgs <= (unsigned int) offset)
+           goto no_table_found;
+
+       return table->msgs[offset];
+
+ no_table_found:
 #if defined(_MSDOS) || defined(_WIN32)
        /*
         * WinSock errors exist in the 10000 and 11000 ranges
@@ -162,14 +210,14 @@ oops:
        cp = buffer;
        strcpy(cp, "Unknown code ");
        cp += sizeof("Unknown code ") - 1;
-       if (table_num) {
-               error_table_name_r(table_num, cp);
-               while (*cp)
+       if (table_num != 0L) {
+               (void) error_table_name_r(table_num, cp);
+               while (*cp != '\0')
                        cp++;
                *cp++ = ' ';
        }
        while (divisor > 1) {
-           if (started || offset >= divisor) {
+           if (started != 0 || offset >= divisor) {
                *cp++ = '0' + offset / divisor;
                offset %= divisor;
                started++;
@@ -181,42 +229,40 @@ oops:
        return(buffer);
 }
 
-
-#ifdef _MSDOS
-/*
- * Win16 applications cannot call malloc while the DLL is being
- * initialized...  To get around this, we pre-allocate an array
- * sufficient to hold several error tables.
- */
-#define PREALLOCATE_ETL 32
-static struct et_list etl[PREALLOCATE_ETL];
-static int etl_used = 0;
-#endif
-
 KRB5_DLLIMP errcode_t KRB5_CALLCONV
 add_error_table(et)
-    const struct error_table FAR * et;
+    /*@dependent@*/ const struct error_table FAR * et;
 {
-    struct et_list *el = _et_list;
+    struct et_list *el;
+    struct dynamic_et_list *del;
 
-    while (el) {
+    /* Always check both lists, because the old interface code
+       wouldn't check the dynamically maintained list before adding an
+       entry to the static list.  */
+    for (el = _et_list; el != NULL; el = el->next)
        if (el->table->base == et->base)
            return EEXIST;
-       el = el->next;
-    }
+    for (del = et_list_dynamic; del != NULL; del = del->next)
+       if (del->table->base == et->base)
+           return EEXIST;
 
 #ifdef _MSDOS
-    if (etl_used < PREALLOCATE_ETL)
+    if (etl_used < PREALLOCATE_ETL) {
        el = &etl[etl_used++];
-    else
+       el->table = et;
+       el->next = _et_list;
+       et_list = el;
+       return 0;
+    }
 #endif
-       if (!(el = (struct et_list *)malloc(sizeof(struct et_list))))
-           return ENOMEM;
 
-    el->table = et;
-    el->next = _et_list;
-    _et_list = el;
+    del = (struct dynamic_et_list *)malloc(sizeof(struct dynamic_et_list));
+    if (del == NULL)
+       return errno;
 
+    del->table = et;
+    del->next = et_list_dynamic;
+    et_list_dynamic = del;
     return 0;
 }
 
@@ -224,23 +270,33 @@ KRB5_DLLIMP errcode_t KRB5_CALLCONV
 remove_error_table(et)
     const struct error_table FAR * et;
 {
-    struct et_list *el = _et_list;
-    struct et_list *el2 = 0;
-
-    while (el) {
-       if (el->table->base == et->base) {
-           if (el2)    /* Not the beginning of the list */
-               el2->next = el->next;
-           else
-               _et_list = el->next;
+    struct dynamic_et_list **del;
+    struct et_list **el;
+    errcode_t ret = ENOENT;
+
+    /* Always check both lists, because the old interface code
+       wouldn't check the dynamically maintained list before adding an
+       entry to the static list.  */
+    for (del = &et_list_dynamic; *del; del = &(*del)->next)
+       if ((*del)->table->base == et->base) {
+           /*@only@*/ struct dynamic_et_list *old = *del;
+           *del = old->next;
+           free (old);
+           ret = 0;
+           break;
+       }
+    for (el = &_et_list; *el; el = &(*el)->next)
+       if ((*el)->table->base == et->base) {
+           struct et_list *old = *el;
+           *el = old->next;
+           old->next = NULL;
+           old->table = NULL;
 #ifdef _MSDOS
-           if ((el < etl) || (el > &etl[PREALLOCATE_ETL-1]))
+           if ((old >= etl) && (old < &etl[PREALLOCATE_ETL-1]))
+               /* do something? */;
 #endif
-               (void) free(el);
-           return 0;
+           ret = 0;
+           break;
        }
-       el2 = el;
-       el = el->next;
-    }
-    return ENOENT;
+    return ret;
 }
index 2bc90765111cd418bb6a15ff1593d57312537812..3f48a8c2ccea31614cf9a2426e5481c4c3ed034a 100644 (file)
 #endif
 
 struct et_list {
-    struct et_list *next;
-    const struct error_table FAR *table;
+    /*@dependent@*//*@null@*/ struct et_list *next;
+    /*@dependent@*/ const struct error_table FAR *table;
+};
+
+struct dynamic_et_list {
+    /*@only@*//*@null@*/ struct dynamic_et_list *next;
+    /*@dependent@*/ const struct error_table FAR *table;
 };
 
 #if !defined(_MSDOS) && !defined(_WIN32) && !defined(macintosh)
-extern struct et_list * _et_list;
+/*@null@*//*@dependent@*/ extern struct et_list * _et_list;
 #endif
 
 #define        ERRCODE_RANGE   8       /* # of bits to shift table number */
 #define        BITS_PER_CHAR   6       /* # bits to shift per character in name */
-#define ERRCODE_MAX   0xFFFFFFFF      /* Mask for maximum error table */
+#define ERRCODE_MAX   0xFFFFFFFFUL      /* Mask for maximum error table */
 
-extern const char FAR *error_table_name ET_P((unsigned long));
-extern const char FAR *error_table_name_r ET_P((unsigned long, char FAR *));
+extern /*@observer@*/ const char FAR *error_table_name ET_P((unsigned long))
+     /*@modifies internalState@*/;
+extern const char FAR *error_table_name_r (unsigned long,
+                                               /*@out@*/ /*@returned@*/ char FAR *outbuf)
+     /*@modifies outbuf@*/;
 
 #define _ET_H
 #endif
diff --git a/src/util/et/et1.et b/src/util/et/et1.et
new file mode 100644 (file)
index 0000000..71c4e6c
--- /dev/null
@@ -0,0 +1,11 @@
+       error_table et1
+
+ec     ET1_M0, "error table 1 message 0"
+
+ec     ET1_M1,
+       "error table 1 message 1"
+
+error_code ET1_M2,
+       "error table 1 message 2"
+
+end
diff --git a/src/util/et/et2.et b/src/util/et/et2.et
new file mode 100644 (file)
index 0000000..4425f04
--- /dev/null
@@ -0,0 +1,11 @@
+       error_table et2
+
+ec     ET2_M0, "error table 2 message 0"
+
+ec     ET2_M1,
+       "error table 2 message 1"
+
+error_code ET2_M2,
+       "error table 2 message 2"
+
+end
index 2521886ec03585c8c262f3100ec619678393bc6a..19bdcc05a28dbd7e1fda50837738fb2b5fa8e46e 100644 (file)
@@ -150,7 +150,7 @@ END {
        print "" > outfile
        print "#if !defined(_MSDOS) && !defined(_WIN32) && !defined(macintosh)" > outfile
        print "/* for compatibility with older versions... */" > outfile
-       print "extern void initialize_" table_name "_error_table ();" > outfile
+       print "extern void initialize_" table_name "_error_table () /*@modifies internalState@*/;" > outfile
        print "#define init_" table_name "_err_tbl initialize_" table_name "_error_table" > outfile
        print "#define " table_name "_err_base ERROR_TABLE_BASE_" table_name > outfile
        print "#else" > outfile
index 267f20b28b32165b1dc6c548513e58905f3dd911..788170735ef03e300f2f91a3113a000f5585b067 100644 (file)
 static const char char_set[] =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
 
-const char * error_table_name_r(num, out)
-       unsigned long num;
-       char FAR *out;
+const char *
+error_table_name_r (unsigned long num,
+                   /*@out@*/ /*@returned@*/ char FAR *outbuf)
+     /*@modifies outbuf@*/
 {
        long ch;
        int i;
-       char *p;
+       /*@out@*/ char *p;
 
-       p = out;
+       p = outbuf;
        num >>= ERRCODE_RANGE;
 
        for (i = 3; i >= 0; i--) {
@@ -42,11 +43,12 @@ const char * error_table_name_r(num, out)
                        *p++ = char_set[ch-1];
        }
        *p = '\0';
-       return(out);
+       return(outbuf);
 }
 
-const char FAR * error_table_name(num)
-       unsigned long num;
+/*@observer@*/
+const char FAR * error_table_name(unsigned long num)
+     /*@modifies internalState@*/
 {
        static char buf[6];
 
index c3d0398114c024b8a53bae4ba75a386ff1c49945..a1ea1dd50a75426eb9262c014f034a3c828ab23b 100644 (file)
@@ -92,15 +92,15 @@ KRB5_DLLIMP extern errcode_t KRB5_CALLCONV et_add_error_table(ectx, tbl)
        et_ctx ectx;
        struct error_table FAR *tbl;
 {
-       struct et_list FAR *link;
+       struct et_list FAR *e;
 
-       link = malloc(sizeof(struct et_list));
-       if (!link)
+       e = malloc(sizeof(struct et_list));
+       if (!e)
                return ENOMEM;
        
-       link->table = tbl;
-       link->next = ectx->tables;
-       ectx->tables = link;
+       e->table = tbl;
+       e->next = ectx->tables;
+       ectx->tables = e;
        
        return 0;
 }
diff --git a/src/util/et/t_com_err.c b/src/util/et/t_com_err.c
new file mode 100644 (file)
index 0000000..d3ed260
--- /dev/null
@@ -0,0 +1,107 @@
+#include <stdio.h>
+#include "com_err.h"
+#include "et1.h"
+#include "et2.h"
+
+int misc_err, known_err;       /* known_err is err in whether or not
+                                   table is 'known' to library */
+int fail;
+
+static void
+try_one (errcode_t code, int known, int table, int msgno)
+{
+    const char *msg = error_message (code);
+    char buffy[1024];
+
+    sprintf (buffy, "error table %d message %d", table, msgno);
+    if (!strcmp (buffy, msg)) {
+       if (!known) {
+           known_err++;
+       }
+       return;
+    }
+    sprintf (buffy, "Unknown code et%d %d", table, msgno);
+    if (!strcmp (buffy, msg)) {
+       if (known)
+           known_err++;
+       return;
+    }
+    printf ("error code %ld got unrecognized message '%s',\n"
+           "should have been table %d message %d\n",
+           (long) code, msg, table, msgno);
+    misc_err++;
+}
+
+static void
+try_table (int table, int known, int lineno,
+          errcode_t c0, errcode_t c1, errcode_t c2)
+{
+    try_one (c0, known, table, 0);
+    try_one (c1, known, table, 1);
+    try_one (c2, known, table, 2);
+    if (misc_err != 0 || known_err != 0) {
+       fail++;
+       if (known_err)
+           printf ("table list error from line %d, table %d\n", lineno,
+                   table);
+       if (misc_err)
+           printf ("misc errors from line %d table %d\n", lineno, table);
+       misc_err = known_err = 0;
+    }
+}
+
+static void
+try_em_1 (int t1_known, int t2_known, int lineno)
+{
+    try_table (1, t1_known, lineno, ET1_M0, ET1_M1, ET1_M2);
+    try_table (2, t2_known, lineno, ET2_M0, ET2_M1, ET2_M2);
+}
+#define try_em(A,B) try_em_1(A,B,__LINE__)
+
+int main (int argc, char *argv[])
+{
+    try_em (0, 0);
+    add_error_table (&et_et1_error_table);
+    try_em (1, 0);
+    add_error_table (&et_et2_error_table);
+    try_em (1, 1);
+    remove_error_table (&et_et1_error_table);
+    try_em (0, 1);
+    remove_error_table (&et_et1_error_table);
+    try_em (0, 1);
+    remove_error_table (&et_et2_error_table);
+    try_em (0, 0);
+
+    initialize_et1_error_table ();
+    try_em (1, 0);
+    add_error_table (&et_et1_error_table);
+    try_em (1, 0);
+    remove_error_table (&et_et1_error_table);
+    try_em (0, 0);
+
+    initialize_et1_error_table ();
+    try_em (1, 0);
+    add_error_table (&et_et1_error_table);
+    try_em (1, 0);
+    add_error_table (&et_et2_error_table);
+    try_em (1, 1);
+    remove_error_table (&et_et1_error_table);
+    try_em (0, 1);
+    remove_error_table (&et_et2_error_table);
+    try_em (0, 0);
+    remove_error_table (&et_et2_error_table);
+    try_em (0, 0);
+
+    add_error_table (&et_et2_error_table);
+    try_em (0, 1);
+    initialize_et2_error_table ();
+    try_em (0, 1);
+    add_error_table (&et_et1_error_table);
+    try_em (1, 1);
+    remove_error_table (&et_et1_error_table);
+    try_em (0, 1);
+    remove_error_table (&et_et2_error_table);
+    try_em (0, 0);
+
+    return fail;
+}