From e62faf6f8edb1c34c8eed9887e71541b5107b9d3 Mon Sep 17 00:00:00 2001 From: Ken Raeburn Date: Wed, 8 Nov 2000 05:46:18 +0000 Subject: [PATCH] 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 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 --- src/util/et/ChangeLog | 38 ++++++++ src/util/et/Makefile.in | 29 +++++++ src/util/et/com_err.c | 7 +- src/util/et/com_err.h | 7 +- src/util/et/error_message.c | 168 ++++++++++++++++++++++++------------ src/util/et/error_table.h | 20 +++-- src/util/et/et1.et | 11 +++ src/util/et/et2.et | 11 +++ src/util/et/et_h.awk | 2 +- src/util/et/et_name.c | 18 ++-- src/util/et/init_et.c | 12 +-- src/util/et/t_com_err.c | 107 +++++++++++++++++++++++ 12 files changed, 347 insertions(+), 83 deletions(-) create mode 100644 src/util/et/et1.et create mode 100644 src/util/et/et2.et create mode 100644 src/util/et/t_com_err.c diff --git a/src/util/et/ChangeLog b/src/util/et/ChangeLog index 9fa415fb6..f64c89cfb 100644 --- a/src/util/et/ChangeLog +++ b/src/util/et/ChangeLog @@ -1,3 +1,41 @@ +2000-11-08 Ken Raeburn + + 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 * configure.in: Change AC_CONST to AC_C_CONST, AC_HEADER_EGREP to diff --git a/src/util/et/Makefile.in b/src/util/et/Makefile.in index f97b5aadc..94e188ffc 100644 --- a/src/util/et/Makefile.in +++ b/src/util/et/Makefile.in @@ -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 diff --git a/src/util/et/com_err.c b/src/util/et/com_err.c index 7bb081048..19a30a0b0 100644 --- a/src/util/et/com_err.c +++ b/src/util/et/com_err.c @@ -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 diff --git a/src/util/et/com_err.h b/src/util/et/com_err.h index 7a8858b38..268ccf5ee 100644 --- a/src/util/et/com_err.h +++ b/src/util/et/com_err.h @@ -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 diff --git a/src/util/et/error_message.c b/src/util/et/error_message.c index b4a0537cf..615530684 100644 --- a/src/util/et/error_message.c +++ b/src/util/et/error_message.c @@ -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<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; } diff --git a/src/util/et/error_table.h b/src/util/et/error_table.h index 2bc907651..3f48a8c2c 100644 --- a/src/util/et/error_table.h +++ b/src/util/et/error_table.h @@ -16,20 +16,28 @@ #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 index 000000000..71c4e6c59 --- /dev/null +++ b/src/util/et/et1.et @@ -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 index 000000000..4425f047a --- /dev/null +++ b/src/util/et/et2.et @@ -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 diff --git a/src/util/et/et_h.awk b/src/util/et/et_h.awk index 2521886ec..19bdcc05a 100644 --- a/src/util/et/et_h.awk +++ b/src/util/et/et_h.awk @@ -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 diff --git a/src/util/et/et_name.c b/src/util/et/et_name.c index 267f20b28..788170735 100644 --- a/src/util/et/et_name.c +++ b/src/util/et/et_name.c @@ -25,15 +25,16 @@ 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]; diff --git a/src/util/et/init_et.c b/src/util/et/init_et.c index c3d039811..a1ea1dd50 100644 --- a/src/util/et/init_et.c +++ b/src/util/et/init_et.c @@ -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 index 000000000..d3ed26057 --- /dev/null +++ b/src/util/et/t_com_err.c @@ -0,0 +1,107 @@ +#include +#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; +} -- 2.26.2