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
+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
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 \
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
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,
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
{
et_old_error_hook_func x = com_err_hook;
- com_err_hook = 0;
+ com_err_hook = NULL;
return x;
}
#endif
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;
};
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
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;
#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
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++;
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;
}
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;
}
#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
--- /dev/null
+ 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
--- /dev/null
+ 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
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
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--) {
*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];
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;
}
--- /dev/null
+#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;
+}