2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2000 University of Virginia,
4 ** Massachusetts Institute of Technology
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** General Public License for more details.
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
20 ** For information on lclint: lclint-request@cs.virginia.edu
21 ** To report a bug: lclint-bug@cs.virginia.edu
22 ** For more information: http://lclint.cs.virginia.edu
28 # include "lclintMacros.nf"
33 ** from the CC man page:
35 ** -Idir Search for #include files whose names do not begin with a
36 ** slash (/) in the following order: (1) in the directory of
37 ** the dir argument, (2) in the directories specified by -I
38 ** options, (3) in the standard directory (/usr/include).
41 /* needed for string literals literals */
45 /*@null@*/ /*@observer@*/ char *name;
46 /*@null@*/ /*@observer@*/ char *describe;
49 static flagcatinfo categories[] =
51 { FK_ABSTRACT, "abstract", "abstraction violations, representation access" } ,
52 { FK_ALIAS, "aliasing", "unexpected or dangerous aliasing" } ,
53 { FK_USE, "alluse", "all declarations are used" } ,
54 { FK_ANSI, "ansi", "violations of constraints imposed by ANSI/ISO standard" } ,
55 { FK_ARRAY, "arrays", "special checking involving arrays" } ,
56 { FK_BOOL, "booleans", "checking and naming of boolean types" } ,
57 { FK_COMMENTS, "comments", "interpretation of stylized comments" } ,
58 { FK_COMPLETE, "complete", "completely defined, used, or specified system" } ,
59 { FK_CONTROL, "controlflow", "suspicious control structures" } ,
60 { FK_DECL, "declarations", "consistency of declarations" } ,
61 { FK_DEF, "definition", "undefined storage errors" } ,
62 { FK_DIRECT, "directories", "set directores" } ,
63 { FK_DISPLAY, "display", "control what is displayed" } ,
64 { FK_EFFECT, "effect", "statements with no effects" } ,
65 { FK_ERRORS, "errors", "control expected errors, summary reporting" } ,
66 { FK_EXPORT, "export", "control what may be exported" } ,
67 { FK_EXPOSURE, "exposure", "representation exposure" } ,
68 { FK_FILES, "files", "control system files" } ,
69 { FK_FORMAT, "format", "control format of warning messages" } ,
70 { FK_GLOBALS, "globals", "use of global and file static variables" },
71 { FK_HEADERS, "headers", "control inclusion and generation of header files" },
72 { FK_HELP, "help", "on-line help" },
73 { FK_IMPLICIT, "implicit", "control implicit annotations and interpretations" } ,
74 { FK_INIT, "initializations", "initialization files" } ,
75 { FK_ITER, "iterators", "checking iterator definitions and uses" } ,
76 { FK_LEAK, "leaks", "memory leaks" } ,
77 { FK_LIBS, "libraries", "loading and dumping of user and standard libraries" } ,
78 { FK_LIMITS, "limits", "violations of set limits" } ,
79 { FK_MACROS, "macros", "expansion, definition and use of macros" },
80 { FK_MEMORY, "memory", "memory management" } ,
81 { FK_MODIFIES, "modification", "modification errors" } ,
82 { FK_NAMES, "names", "naming conventions and limits" } ,
83 { FK_NULL, "null", "misuses of null pointers" } ,
84 { FK_NUMBERS, "numbers", "control type-checking of numeric types" } ,
85 { FK_OPS, "operations", "checking of primitive operations" } ,
86 { FK_PARAMS, "parameters", "function and macro parameters" } ,
87 { FK_SPEED, "performance", "speeding up checking" } ,
88 { FK_POINTER, "pointers", "pointers" } ,
89 { FK_PRED, "predicates", "condition test expressions" } ,
90 { FK_PREFIX, "prefixes", "set naming prefixes and control checking" } ,
91 { FK_PREPROC, "preproc", "defines and undefines for the preprocessor" } ,
92 { FK_PROTOS, "prototypes", "function prototypes" } ,
93 { FK_DEAD, "released", "using storage that has been deallocated" } ,
94 { FK_IGNORERET, "returnvals", "ignored return values" },
95 { FK_SPEC, "specifications", "checks involving .lcl specifications" } ,
96 { FK_SUPPRESS, "suppress", "local and global suppression of messages" } ,
97 { FK_TYPEEQ, "typeequivalence", "control what types are equivalent" } ,
98 { FK_BEHAVIOR, "undefined", "code with undefined or implementation-defined behavior" } ,
99 { FK_UNRECOG, "unrecognized", "unrecognized identifiers" } ,
100 { FK_UNSPEC, "unconstrained", "checking in the presence of unconstrained functions" } ,
101 { FK_DEBUG, NULL, NULL } ,
102 { FK_SYNTAX, NULL, NULL } ,
103 { FK_TYPE, NULL, NULL } ,
104 { FK_SECRET, NULL, NULL } ,
105 { FK_OBSOLETE, NULL, NULL } ,
106 { FK_NONE, NULL, NULL } /* must be last */
119 bool isSpecial; /* setting this flag may set other flags (or values) */
120 bool isIdem; /* idempotent - always sets to TRUE */
121 bool isGlobal; /* cannot be set locally (using control comments) */
122 bool isModeFlag; /* set by modes */
124 /*@observer@*/ char *flag;
126 /*@observer@*/ /*@null@*/ char *desc;
132 typedef fflag flaglist[];
134 # include "flags.def"
136 /*@iter allFlags (yield observer fflag f); @*/
137 # define allFlags(m_f) \
138 { /*@+enumint@*/ flagcode m_i; for (m_i = 0; m_i < NUMFLAGS; m_i++) { fflag m_f = flags[m_i]; /*@=enumint@*/
139 # define end_allFlags }}
141 static bn_mstring mode_names[] =
143 "weak", "standard", "checks", "strict", NULL,
146 /*@iter allModes (yield bn_mstring modename)@*/
147 # define allModes(m_m) \
148 { int m_ii = 0; while (mstring_isDefined (mode_names[m_ii])) \
149 { bn_mstring m_m = mode_names[m_ii]; m_ii++;
151 # define end_allModes }}
155 static cstring describeFlagCode (flagcode p_flag) /*@*/ ;
156 static cstringSList sortedFlags (void) /*@*/ ;
157 static /*@observer@*/ cstring categoryName (flagkind p_kind) /*@*/ ;
158 static /*@unused@*/ cstring listModes (void) /*@*/ ;
160 bool flagcode_isSpecialFlag (flagcode f)
162 return (flags[f].isSpecial);
165 bool flagcode_isGlobalFlag (flagcode f)
167 return (flags[f].isGlobal);
170 bool flagcode_isIdemFlag (flagcode f)
172 return (flags[f].isIdem);
175 bool flagcode_isModeFlag (flagcode f)
177 return (flags[f].isModeFlag);
180 bool flagcode_isNameChecksFlag (flagcode f)
182 return (flags[f].main == FK_NAMES);
186 ** Internal consistency check on the flags.
189 void flags_initMod ()
194 if (flags[code].code != code)
196 llbug (message ("*** ERROR: inconsistent flag %s / %d / %d",
197 cstring_fromChars (flags[code].flag),
198 flags[code].code, code));
211 char *buf = mstring_create (128);
215 if (f.nreported > 0 || f.nsuppressed > 0)
217 int nrep = f.nreported;
218 int nsup = f.nsuppressed;
219 cstring fs = cstring_fill (cstring_fromChars (f.flag), 23);
223 llmsgplain (cstring_makeLiteral
224 ("\nError Type Reported Suppressed\n"
225 "=================== ======== ========="));
229 sprintf (buf, "%s%7d %9d", cstring_toCharsSafe (fs), nrep, nsup);
235 llmsg (cstring_copy (cstring_fromChars (buf)));
241 cstring ts = cstring_fill (cstring_makeLiteralTemp ("Total"), 23);
243 llmsglit (" ======== =========");
245 sprintf (buf, "%s%7d %9d", cstring_toCharsSafe (ts), sumrep, sumsup);
247 llmsgplain (cstring_copy (cstring_fromChars (buf)));
256 flagcode_recordError (flagcode f)
258 if (f != INVALID_FLAG)
260 if (f == FLG_WARNFLAGS)
262 ; /* don't count these */
266 flags[f].nreported = flags[f].nreported + 1;
271 llcontbug (message ("flagcode_recordError: invalid flag: %d", (int) f));
276 flagcode_recordSuppressed (flagcode f)
278 llassertprint (f != INVALID_FLAG, ("flagcode: %s", flagcode_unparse (f)));
280 flags[f].nsuppressed = flags[f].nsuppressed + 1;
284 flagcode_numReported (flagcode f)
286 llassert (f != INVALID_FLAG);
288 return (flags[f].nreported);
291 /*@observer@*/ cstring
292 flagcodeHint (flagcode f)
294 llassert (f != INVALID_FLAG);
296 if (mstring_isDefined (flags[f].hint))
298 return (cstring_fromChars (flags[f].hint));
302 return (cstring_fromChars (flags[f].desc));
306 static int categorySize (flagkind kind) /*@*/
313 if (f.main == kind || f.sub == kind)
322 flagkind identifyCategory (cstring s)
326 for (i = 0; categories[i].kind != FK_NONE; i++)
328 if (mstring_isDefined (categories[i].name))
330 if (cstring_equalLit (s, categories[i].name))
332 return categories[i].kind;
340 static /*@observer@*/ cstring categoryName (flagkind kind)
344 for (i = 0; categories[i].kind != FK_NONE; i++)
346 if (categories[i].kind == kind)
348 return (cstring_fromChars (categories[i].name));
352 return (cstring_makeLiteralTemp ("<No Category>"));
355 static int categoryIndex (flagkind kind)
359 for (i = 0; categories[i].kind != FK_NONE; i++)
361 if (categories[i].kind == kind)
370 void printCategory (flagkind kind)
372 int index = categoryIndex (kind);
374 llassert (index >= 0);
376 llmsg (message ("%s (%d flags)\n\3%s\n\n",
377 cstring_fromChars (categories[index].name),
379 cstring_fromChars (categories[index].describe)));
383 if (f.main == kind || f.sub == kind)
385 llmsg (message (" %s\n\6%q", cstring_fromChars (f.flag),
386 describeFlagCode (f.code)));
392 listAllCategories (void)
396 for (i = 0; categories[i].kind != FK_NONE; i++)
398 flagkind kind = categories[i].kind ;
400 if (categories[i].describe != NULL)
402 llmsg (message ("%s (%d flags)\n\3%s",
405 cstring_fromChars (categories[i].describe)));
411 printAllFlags (bool desc, bool full)
415 cstringSList fl = sortedFlags ();
417 cstringSList_elements (fl, el)
419 llmsg (message ("%q\n\n", describeFlag (el)));
420 } end_cstringSList_elements ;
422 cstringSList_free (fl);
428 if (f.code != INVALID_FLAG && f.main != FK_OBSOLETE)
430 if (mstring_isDefined (f.desc))
434 llmsg (message ("%s --- %s", cstring_fromChars (f.flag),
435 cstring_fromChars (f.desc)));
444 describeFlagCode (flagcode flag)
446 cstring ret = cstring_undefined;
449 if (flagcode_isInvalid (flag))
451 return (cstring_makeLiteral ("<invalid>"));
454 context_resetAllFlags ();
457 ret = cstring_copy (cstring_fromChars (f.desc));
460 if (f.sub != FK_NONE)
462 ret = message ("%q\nCategories: %s, %s",
464 categoryName (f.main),
465 categoryName (f.sub));
469 if (f.main != FK_NONE)
471 cstring cname = categoryName (f.main);
473 if (cstring_isDefined (cname))
475 ret = message ("%q\nCategory: %s",
487 context_setMode (cstring_fromChars (mname));
491 ret = message ("%q\nMode Settings: %s %s",
492 ret, cstring_fromChars (mname),
493 cstring_makeLiteralTemp
494 (context_getFlag (flag) ? "+" : "-"));
499 ret = message ("%q, %s %s",
500 ret, cstring_fromChars (mname),
501 cstring_makeLiteralTemp
502 (context_getFlag (flag) ? "+" : "-"));
508 ret = message ("%q\nDefault Setting: %s",
510 cstring_makeLiteralTemp
511 (context_getFlag (flag) ? "+" : "-"));
516 ret = message("%q\nSet globally only", ret);
520 ret = message("%q\nSet locally", ret);
529 if (flag == FLG_COMMENTCHAR)
531 ret = message("%q\nCharacter Argument. Default: %h",
532 ret, (char) context_getValue (flag));
536 ret = message("%q\nNumeric Argument. Default: %d",
538 context_getValue (flag));
542 if (cstring_isDefined (context_getString (flag)))
544 ret = message("%q\nString Argument. Default: %s",
546 context_getString (flag));
550 ret = message("%q\nString Argument. No default.", ret);
555 if (mstring_isDefined (f.hint))
557 ret = message("%q\n\3%s", ret, cstring_fromChars (f.hint));
564 describeFlag (cstring flagname)
566 cstring oflagname = cstring_copy (flagname);
567 flagcode f = identifyFlag (flagname);
569 if (flagcode_isSkip (f))
571 cstring_free (oflagname);
572 return cstring_undefined;
574 else if (flagcode_isValid (f))
576 if (cstring_equal (flagname, oflagname))
578 cstring_free (oflagname);
579 return (message ("%s\n\3%q", flagname, describeFlagCode (f)));
583 return (message ("%q (standardized name: %s)\n\3%q",
584 oflagname, flagname, describeFlagCode (f)));
589 if (isMode (flagname))
591 cstring_free (oflagname);
594 (message ("%s: predefined mode (see User's Guide for information)",
599 return (message ("%q: <invalid flag>", oflagname));
607 cstringSList s = cstringSList_new ();
613 s = cstringSList_add (s, cstring_fromChars (f.flag));
617 cstringSList_alphabetize (s);
622 void printAlphaFlags ()
624 cstringSList fl = sortedFlags ();
626 cstringSList_printSpaced (fl, 3, 1, context_getLineLen () - 25);
627 cstringSList_free (fl);
629 /*@observer@*/ cstring
630 flagcode_name (flagcode code)
632 return cstring_fromChars (flags[code].flag);
636 ** Transforms a flag into its cannonical form.
638 ** The following transformations are made:
644 ** parameter -> param
645 ** unrecognized -> unrecog
647 ** declaration -> decl
648 ** globalias -> (no change)
656 ** unconstrained -> unspec
663 canonicalizeFlag (cstring s)
666 static bn_mstring transform[] =
672 "parameter", "param",
673 "unrecognized", "unrecog",
675 "declaration", "decl",
683 "unconstrained", "uncon",
693 while ((current = transform[i]) != NULL)
695 if (cstring_containsLit (s, current))
697 cstring_replaceLit (s, current, transform[i+1]);
702 /* remove whitespace, -'s, and _'s */
703 cstring_stripChars (s, " -_");
707 identifyFlag (cstring s)
709 if (cstring_length (s) == 0) {
710 /* evs 2000-06-25: A malformed flag. */
714 if (cstring_firstChar (s) == 'I')
716 return FLG_INCLUDEPATH; /* no space after -I */
719 if (cstring_firstChar (s) == 'S')
721 return FLG_SPECPATH; /* no space after -S */
724 if (cstring_firstChar (s) == 'D')
726 return FLG_DEFINE; /* no space after -D */
729 if (cstring_firstChar (s) == 'U')
731 return FLG_UNDEFINE; /* no space after -D */
734 canonicalizeFlag (s);
738 if (cstring_equal (cstring_fromChars (f.flag), s))
748 if (cstring_equalLit (s, "pred"))
753 if (cstring_equalLit (s, "modobserverstrict"))
755 return FLG_MODOBSERVERUNCON;
758 if (cstring_equalLit (s, "czechnames"))
763 if (cstring_equalLit (s, "slovaknames"))
768 if (cstring_equalLit (s, "czechoslovaknames"))
770 return FLG_CZECHOSLOVAK;
773 if (cstring_equalLit (s, "globunspec")
774 || cstring_equalLit (s, "globuncon"))
776 return FLG_GLOBUNSPEC;
779 if (cstring_equalLit (s, "modglobsunspec")
780 || cstring_equalLit (s, "modglobsuncon")
781 || cstring_equalLit (s, "modglobsnomods"))
783 return FLG_MODGLOBSUNSPEC;
786 if (cstring_equalLit (s, "export"))
788 return FLG_EXPORTANY;
791 if (cstring_equalLit (s, "macrospec"))
793 return FLG_MACRODECL;
796 if (cstring_equalLit (s, "ansireservedlocal"))
798 return FLG_ANSIRESERVEDLOCAL;
801 if (cstring_equalLit (s, "warnposix"))
803 return FLG_WARNPOSIX;
806 if (cstring_equalLit (s, "defuse"))
811 if (cstring_equalLit (s, "macroundef"))
813 return FLG_MACROUNDEF;
816 if (cstring_equalLit (s, "showcol"))
821 if (cstring_equalLit (s, "intbool"))
826 if (cstring_equalLit (s, "intchar"))
831 if (cstring_equalLit (s, "intenum"))
837 ** For our European friends...
840 if (cstring_equalLit (s, "isolib"))
845 if (cstring_equalLit (s, "isostrictlib"))
847 return FLG_STRICTLIB;
850 if (cstring_equalLit (s, "ansistrictlib"))
852 return FLG_STRICTLIB;
855 if (cstring_equalLit (s, "skipisoheaders"))
857 return FLG_SKIPANSIHEADERS;
860 if (cstring_equalLit (s, "isoreserved"))
862 return FLG_ANSIRESERVED;
865 if (cstring_equalLit (s, "isoreservedinternal"))
867 return FLG_ANSIRESERVEDLOCAL;
870 if (cstring_equalLit (s, "isolimits"))
872 return FLG_ANSILIMITS;
879 if (cstring_equalLit (s, "accessunspec"))
882 (cstring_makeLiteralTemp
883 ("accessunspec flag is not supported by LCLint version 2.0 or "
884 "later. It has been replaced by accessmodule, accessfile and "
885 "accessfunction to provide more precise control of accessibility "
886 "of representations. For more information, "
887 "see lclint -help accessmodule"));
892 if (cstring_equalLit (s, "staticmods"))
895 (cstring_makeLiteralTemp
896 ("staticmods flag is obsolete. You probably "
897 "want impcheckmodstatics. For more information, "
898 "see lclint -help impcheckmodstatics"));
903 if (cstring_equalLit (s, "bool"))
906 (cstring_makeLiteralTemp ("bool flag is obsolete. It never really "
907 "made sense in the first place."));
912 if (cstring_equalLit (s, "ansi"))
915 (cstring_makeLiteralTemp ("ansi flag is obsolete. You probably "
916 "want noparams and/or oldstyle."));
921 if (cstring_equalLit (s, "stdio"))
924 (cstring_makeLiteralTemp
925 ("stdio flag is obsolete. You may "
926 "want strictlib or one of the gloabls "
927 "checking flags. For more information, "
928 "see lclint -help strictlib or lclint -help flags globals"));
936 void setValueFlag (flagcode opt, cstring arg)
944 case FLG_EXTERNALNAMELEN:
945 case FLG_INTERNALNAMELEN:
946 case FLG_CONTROLNESTDEPTH:
947 case FLG_STRINGLITERALLEN:
948 case FLG_NUMSTRUCTFIELDS:
949 case FLG_NUMENUMMEMBERS:
950 case FLG_INCLUDENEST:
952 int val = cstring_toPosInt (arg);
959 ("Flag %s must be followed by a positive number number. "
961 flagcode_unparse (opt), arg));
965 context_setValueAndFlag (opt, val);
969 case FLG_COMMENTCHAR:
971 if (cstring_length (arg) != 1)
975 ("Flag %s should be followed by a single character. Followed by %s",
976 flagcode_unparse (opt), arg));
980 context_setCommentMarkerChar (cstring_firstChar (arg));
988 void setStringFlag (flagcode opt, /*@only@*/ cstring arg)
994 if (cstring_lastChar (arg) == CONNECTCHAR)
996 context_setString (opt, arg);
1000 context_setString (opt, cstring_appendChar (arg, CONNECTCHAR));
1006 context_setString (opt, arg);
1015 cstring s = cstring_makeLiteral ("Flag ");
1016 cstringSList sflags = sortedFlags ();
1020 s = message ("%q%9s", s, cstring_fromChars (modename));
1023 s = message ("%q\n", s);
1025 cstringSList_elements (sflags, flagname)
1027 flagcode code = identifyFlag (flagname);
1028 fflag currentflag = flags[code];
1030 if (mstring_isDefined (currentflag.desc) && flagcode_isModeFlag (code))
1032 s = message ("%q\n%27s", s,
1033 cstring_fromChars (currentflag.flag));
1037 context_setMode (cstring_fromChars (modename));
1039 if (context_getFlag (code))
1041 s = message ("%q%9s", s, cstring_makeLiteralTemp ("+"));
1045 s = message ("%q%9s", s, cstring_makeLiteralTemp (" "));
1048 context_resetModeFlags ();
1051 } end_cstringSList_elements;
1053 cstringSList_free (sflags);
1055 s = cstring_appendChar (s, '\n');
1063 cstring s = cstring_makeLiteral ("\t");
1068 if (i != 0 && (i % 4 == 0))
1070 s = message ("%q\n\t%15s", s, cstring_fromChars (modename));
1074 s = message ("%q%15s", s, cstring_fromChars (modename));
1087 if (mstring_isDefined (modename))
1089 if (cstring_equalLit (s, modename))
1099 extern bool flagcode_hasArgument (flagcode f)
1101 return (flags[f].argtype != ARG_NONE);
1104 extern bool flagcode_hasValue (flagcode f)
1106 return (flags[f].argtype == ARG_VALUE);
1109 extern bool flagcode_hasString (flagcode f)
1111 return (flags[f].argtype == ARG_STRING);
1114 extern int flagcode_valueIndex (flagcode f)
1116 /*@unchecked@*/ static bool initialized = FALSE;
1118 /*@unchecked@*/ static flagcode valueFlags[NUMVALUEFLAGS];
1127 if (flagcode_hasValue (code))
1129 llassert (nv < NUMVALUEFLAGS);
1130 valueFlags[nv] = code;
1135 llassertprint (nv == NUMVALUEFLAGS,
1136 ("number of value flags: %d (expected %d)",
1137 nv, NUMVALUEFLAGS));
1141 for (i = 0; i < NUMVALUEFLAGS; i++)
1143 /* static valueFlags must be defined */
1144 /*@-usedef@*/ if (f == valueFlags[i]) /*@=usedef@*/
1153 extern int flagcode_stringIndex (flagcode f)
1155 /*@unchecked@*/ static bool initialized = FALSE;
1156 /*@unchecked@*/ static flagcode stringFlags[NUMSTRINGFLAGS];
1166 if (flagcode_hasString (code))
1168 llassertprint (nv < NUMSTRINGFLAGS, ("Incorrect number of string flags: %d (need at least %d)", NUMSTRINGFLAGS, nv));
1169 stringFlags[nv] = code;
1174 llassertprint (nv == NUMSTRINGFLAGS,
1175 ("number of string flags: %d (expected %d)",
1176 nv, NUMSTRINGFLAGS));
1180 for (i = 0; i < NUMSTRINGFLAGS; i++)
1182 /*@-usedef@*/ if (f == stringFlags[i]) /*@=usedef@*/
1188 llbug (message ("Bad string flag: %s", flagcode_unparse (f)));
1192 bool flagcode_isNamePrefixFlag (flagcode f)
1196 case FLG_MACROVARPREFIX:
1198 case FLG_ENUMPREFIX:
1199 case FLG_FILESTATICPREFIX:
1200 case FLG_GLOBPREFIX:
1201 case FLG_TYPEPREFIX:
1202 case FLG_EXTERNALPREFIX:
1203 case FLG_LOCALPREFIX:
1204 case FLG_UNCHECKEDMACROPREFIX:
1205 case FLG_CONSTPREFIX:
1206 case FLG_ITERPREFIX:
1207 case FLG_DECLPARAMPREFIX: