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"
31 //#include "environmentTable.h"
33 /*@constant int ATINVALID; @*/
36 #define ENVIRONMENTSEARCHLIMIT ALIASSEARCHLIMIT
37 #define FLG_GLOBENVIRONMENT FLG_GLOBALIAS
38 #define NOENVIRONMENT NOALIAS
41 environmentTable_canEnvironmentAux (environmentTable p_s, sRef p_sr, int p_lim) /*@*/ ;
43 environmentTable_aliasedByLimit (environmentTable p_s, sRef p_sr, int p_lim) /*@*/ ;
45 environmentTable_aliasedByAux (environmentTable p_s, sRef p_sr, int p_lim) /*@*/ ;
48 environmentTable_new ()
50 return (environmentTable_undefined);
53 static /*@only@*/ /*@notnull@*/ environmentTable
54 environmentTable_newEmpty (void)
56 environmentTable s = (environmentTable) dmalloc (sizeof (*s));
59 s->nspace = environmentTableBASESIZE;
60 s->keys = (sRef *) dmalloc (sizeof (*s->keys) * environmentTableBASESIZE);
61 s->values = (sRefSet *) dmalloc (sizeof (*s->values) * environmentTableBASESIZE);
62 s->rangeValues = (rangeAt*) dmalloc (sizeof (*s->rangeValues) * environmentTableBASESIZE);
67 environmentTable_grow (/*@notnull@*/ environmentTable s)
70 o_sRefSet *oldvalues = s->values;
71 sRef *oldkeys = s->keys;
72 rangeAt *oldranges = s->rangeValues;
74 s->nspace += environmentTableBASESIZE;
76 s->values = (sRefSet *) dmalloc (sizeof (*s->values)
77 * (s->nelements + s->nspace));
78 s->keys = (sRef *) dmalloc (sizeof (*s->keys) * (s->nelements + environmentTableBASESIZE));
80 s->rangeValues = (rangeAt *) dmalloc (sizeof (*s->rangeValues) * (s->nelements + environmentTableBASESIZE));
83 if (s->keys == (sRef *) 0 || s->values == (sRefSet *)0 || s->rangeValues == (rangeAt*) 0 )
85 llfatalerror (cstring_makeLiteral ("environmentTable_grow: out of memory!"));
88 for (i = 0; i < s->nelements; i++)
90 s->values[i] = oldvalues[i];
91 s->keys[i] = oldkeys[i];
92 s->rangeValues[i] = oldranges[i];
94 // s->rangeValues[i] = dmalloc (sizeof (rangeAt));
102 static int environmentTable_lookupRefs (/*@notnull@*/ environmentTable s, sRef sr)
107 for (i = 0; i < environmentTable_size (s); i++)
109 if (sRef_same (sr, s->keys[i]))
119 environmentTable_postOpvar (/*@returned@*/ environmentTable s, sRef sr)
122 // printf("doing postop\n");
123 if (environmentTable_isUndefined (s) )
125 s = environmentTable_newEmpty();
128 ind = environmentTable_lookupRefs (s, sr);
129 if (ind == ATINVALID)
131 s = environmentTable_addRelativeRange (s, sr);
134 // assume it ++ we'll do -- later
136 s->rangeValues[ind].max++;
137 s->rangeValues[ind].min++;
143 environmentTable_mergeEnvironments (environmentTable s1, environmentTable s2)
147 t1 = environmentTable_copy (s1);
148 if (environmentTable_isUndefined (s2) )
151 for (i = 0; i < s2->nelements; i++)
153 int ind = environmentTable_lookupRefs ( t1, s1->keys[i]);
154 if (s2->rangeValues[i].isRelative)
156 if (ind == ATINVALID)
158 t1 = environmentTable_insertRelativeRange(t1, s2->keys[i], s2->rangeValues[i].max, s2->rangeValues[i].min);
162 t1->rangeValues[ind].min += s2->rangeValues[i].min;
163 t1->rangeValues[ind].max += s2->rangeValues[i].max;
168 /* we want to overwrite old value .. */
169 t1 = environmentTable_addExactValue (t1, s2->keys[i], s2->rangeValues[i].max);
170 /*should fix this to do min and max ... */
177 rangeAt_createRelativeRange ()
180 tmp.isRelative = TRUE;
187 rangeAt rangeAt_createExactRange (int min, int max)
190 tmp.isRelative = FALSE;
198 environmentTable_addRelativeRange (/*@returned@*/ environmentTable s,
199 /*@exposed@*/ sRef sr)
205 if (environmentTable_isUndefined (s))
207 s = environmentTable_newEmpty ();
212 ind = environmentTable_lookupRefs (s, sr);
215 if (ind == ATINVALID)
217 if (s->nspace <= 0) {
218 environmentTable_grow (s);
222 s->keys[s->nelements] = sr;
224 // s->values[s->nelements] = sRefSet_single (al);
228 range = rangeAt_createRelativeRange();
230 s->rangeValues[ind] = range;
235 environmentTable_testInRange ( environmentTable s, /*@exposed@*/ sRef sr, int index)
240 if (environmentTable_isUndefined (s))
242 fprintf(stderr,"environmentTable not defined\n");
246 ind = environmentTable_lookupRefs (s, sr);
247 if (ind == ATINVALID)
249 fprintf (stderr,"range not known\n");
252 if ( &s->rangeValues[ind] )
254 if ( (s->rangeValues[ind].min <= index ) && (s->rangeValues[ind].max >= index) )
256 printf("The value %d is in the range for this variable \n", index);
259 printf("The value %d is NOT in the range for this variable \n", index);
266 environmentTable_addExactValue (/*@returned@*/ environmentTable s,
267 /*@exposed@*/ sRef sr,
274 if (environmentTable_isUndefined (s))
276 s = environmentTable_newEmpty ();
281 ind = environmentTable_lookupRefs (s, sr);
284 if (ind == ATINVALID)
286 if (s->nspace <= 0) {
287 environmentTable_grow (s);
291 s->keys[s->nelements] = sr;
293 // s->values[s->nelements] = sRefSet_single (al);
300 /* s->values[ind] = sRefSet_insert (s->values[ind], al); */
303 if ( (s->rangeValues[ind]) == 0 )
305 s->rangeValues[ind] = dmalloc(sizeof(rangeAt) );
311 s->rangeValues[ind] = range;
316 environmentTable_insertRelativeRange (/*@returned@*/ environmentTable s,
317 /*@exposed@*/ sRef sr,
324 if (environmentTable_isUndefined (s))
326 s = environmentTable_newEmpty ();
331 ind = environmentTable_lookupRefs (s, sr);
334 if (ind == ATINVALID)
336 if (s->nspace <= 0) {
337 environmentTable_grow (s);
341 s->keys[s->nelements] = sr;
343 // s->values[s->nelements] = sRefSet_single (al);
348 range = rangeAt_createRelativeRange();
352 s->rangeValues[ind] = range;
357 environmentTable_addMustAlias (/*@returned@*/ environmentTable s,
358 /*@exposed@*/ sRef sr,
364 llassert (NOENVIRONMENT (sr, al));
366 if (environmentTable_isUndefined (s))
368 s = environmentTable_newEmpty ();
373 ind = environmentTable_lookupRefs (s, sr);
376 ss = environmentTable_canEnvironment (s, al);
379 if (ind == ATINVALID)
381 if (s->nspace <= 0) {
382 environmentTable_grow (s);
386 s->keys[s->nelements] = sr;
387 s->values[s->nelements] = sRefSet_single (al);
393 s->values[ind] = sRefSet_insert (s->values[ind], al);
396 s->values[ind] = sRefSet_unionExcept (s->values[ind], ss, s->keys[ind]);
402 static environmentTable
403 environmentTable_addSet (/*@returned@*/ environmentTable s,
404 /*@exposed@*/ sRef key, /*@only@*/ sRefSet value)
406 if (!sRefSet_isEmpty (value))
408 if (environmentTable_isUndefined (s))
410 s = environmentTable_newEmpty ();
416 environmentTable_grow (s);
421 s->keys[s->nelements] = key;
422 s->values[s->nelements] = value;
427 sRefSet_free (value);
434 ** When environmentes are cleared:
436 ** o remove all entries for sr
437 ** o replace all environmentes for things which environment sr with sr's environmentes
439 ** Clear environmentes for sr; if sr is a direct param reference, clear its environmentes too.
442 static void environmentTable_clearEnvironmentesAux (/*@notnull@*/ environmentTable p_s, sRef p_sr)
445 void environmentTable_clearEnvironmentes (environmentTable s, sRef sr)
447 if (environmentTable_isUndefined (s))
453 sRef rb = sRef_getRootBase (sr);
456 if (!sRef_isCvar (sr) && sRef_isLocalVar (rb))
458 int ind = environmentTable_lookupRefs (s, rb);
460 if (ind != ATINVALID)
462 sRefSet al = s->values[ind];
465 sRefSet_realElements (al, el)
468 if (sRef_isParam (el))
470 if (sRef_sameName (el, rb))
472 sRef fb = sRef_fixBase (sr, el);
474 environmentTable_clearEnvironmentesAux (s, fb);
477 } end_sRefSet_realElements ;
481 environmentTable_clearEnvironmentesAux (s, sr);
486 void environmentTable_clearEnvironmentesAux (/*@notnull@*/ environmentTable s, sRef sr)
490 for (i = 0; i < s->nelements; i++)
492 sRef key = s->keys[i];
494 if (sRef_includedBy (key, sr))
496 sRefSet_clear (s->values[i]);
500 (void) sRefSet_deleteBase (s->values[i], sr);
506 ** returns set of all sRefs that must environment sr (but are different from sr)
509 static /*@only@*/ sRefSet environmentTable_environmentedByAux (environmentTable s, sRef sr, int lim)
511 static bool hadWarning = FALSE;
512 sRefSet res = sRefSet_undefined;
515 llassert (!sRef_isConj (sr));
518 if (environmentTable_isUndefined (s) || lim >= ENVIRONMENTSEARCHLIMIT)
520 if (lim >= ENVIRONMENTSEARCHLIMIT && !hadWarning)
523 (message ("Environment search limit exceeded, checking %q. "
524 "This either means there is a variable with at least "
525 "%d indirections, or there is a bug in LCLint.",
527 ENVIRONMENTSEARCHLIMIT));
532 return sRefSet_undefined;
538 if (sRef_isPointer (sr))
540 abl = environmentTable_environmentedByLimit (s, sRef_getBase (sr), lim);
541 res = sRefSet_addIndirection (abl);
543 else if (sRef_isAddress (sr))
545 abl = environmentTable_environmentedByLimit (s, sRef_getBase (sr), lim);
546 res = sRefSet_removeIndirection (abl);
548 else if (sRef_isField (sr))
550 abl = environmentTable_environmentedByLimit (s, sRef_getBase (sr), lim);
551 res = sRefSet_accessField (abl, sRef_getField (sr));
553 else if (sRef_isArrayFetch (sr))
555 abl = environmentTable_environmentedByLimit (s, sRef_getBase (sr), lim);
557 if (sRef_isIndexKnown (sr))
559 int idx = sRef_getIndex (sr);
561 res = sRefSet_fetchKnown (abl, idx);
565 res = sRefSet_fetchUnknown (abl);
570 abl = sRefSet_undefined;
576 for (i = 0; i < s->nelements; i++)
578 sRef elem = s->keys[i];
580 if (!sRef_same (sr, elem)) /* was sameName */
583 sRefSet_realElements (s->values[i], current)
586 if (sRef_similar (sr, current))
588 res = sRefSet_insert (res, sRef_fixOuterRef (elem));
589 /*@innerbreak@*/ break;
591 } end_sRefSet_realElements;
598 static /*@only@*/ sRefSet environmentTable_environmentedByLimit (environmentTable s, sRef sr, int lim)
603 if (sRef_isConj (sr))
605 res = sRefSet_unionFree (environmentTable_environmentedByLimit (s, sRef_getConjA (sr), lim),
606 environmentTable_environmentedByLimit (s, sRef_getConjB (sr), lim));
610 res = environmentTable_environmentedByAux (s, sr, lim + 1);
616 /*@only@*/ sRefSet environmentTable_environmentedBy (environmentTable s, sRef sr)
618 if (sRef_isConj (sr))
620 return (sRefSet_unionFree (environmentTable_environmentedBy (s, sRef_getConjA (sr)),
621 environmentTable_environmentedBy (s, sRef_getConjB (sr))));
624 return (environmentTable_environmentedByAux (s, sr, 0));
627 /*@only@*/ sRefSet environmentTable_canEnvironment (environmentTable s, sRef sr)
632 if (sRef_isConj (sr))
634 res = sRefSet_unionFree (environmentTable_canEnvironment (s, sRef_getConjA (sr)),
635 environmentTable_canEnvironment (s, sRef_getConjB (sr)));
639 res = environmentTable_canEnvironmentAux (s, sr, 0);
646 ** need to limit the depth of environmenting searches
649 static /*@only@*/ sRefSet environmentTable_canEnvironmentLimit (environmentTable s, sRef sr, int lim)
653 if (sRef_isConj (sr))
655 sRefSet a = environmentTable_canEnvironmentLimit (s, sRef_getConjA (sr), lim);
656 sRefSet b = environmentTable_canEnvironmentLimit (s, sRef_getConjB (sr), lim);
658 res = sRefSet_unionFree (a, b);
662 res = environmentTable_canEnvironmentAux (s, sr, lim + 1);
668 static /*@only@*/ sRefSet
669 environmentTable_canEnvironmentAux (environmentTable s, sRef sr, int lim)
671 static bool hadWarning = FALSE;
672 llassert (!sRef_isConj (sr));
675 if (environmentTable_isUndefined (s) || lim >= ALIASSEARCHLIMIT)
677 if (lim >= ALIASSEARCHLIMIT && !hadWarning)
680 (message ("Environment search limit exceeded, checking %q. "
681 "This either means there is a variable with at least "
682 "%d indirections, or there is a bug in LCLint.",
684 ENVIRONMENTSEARCHLIMIT));
689 return sRefSet_undefined;
693 int ind = environmentTable_lookupRefs (s, sr);
695 if (sRef_isPointer (sr) || sRef_isAddress (sr) || sRef_isField (sr)
696 || sRef_isArrayFetch (sr))
698 sRef base = sRef_getBase (sr);
699 sRefSet tmp = environmentTable_canEnvironmentLimit (s, base, lim);
702 if (sRef_isPointer (sr))
704 ret = sRefSet_addIndirection (tmp);
706 else if (sRef_isAddress (sr))
708 ret = sRefSet_removeIndirection (tmp);
710 else if (sRef_isField (sr))
712 ret = sRefSet_accessField (tmp, sRef_getField (sr));
714 else if (sRef_isArrayFetch (sr))
716 if (sRef_isIndexKnown (sr))
718 ret = sRefSet_fetchKnown (tmp, sRef_getIndex (sr));
722 ret = sRefSet_fetchUnknown (tmp);
730 if (ind != ATINVALID)
732 ret = sRefSet_union (ret, s->values[ind]);
739 if (ind == ATINVALID) return sRefSet_undefined;
741 return sRefSet_newCopy (s->values[ind]);
745 environmentTable environmentTable_copy (environmentTable s)
747 if (environmentTable_isEmpty (s))
749 return environmentTable_undefined;
753 environmentTable t = (environmentTable) dmalloc (sizeof (*s));
756 t->nelements = s->nelements;
758 t->keys = (sRef *) dmalloc (sizeof (*s->keys) * s->nelements);
759 t->values = (sRefSet *) dmalloc (sizeof (*s->values) * t->nelements);
760 t->rangeValues = (rangeAt *) dmalloc (sizeof (*s->rangeValues) * t->nelements);
762 for (i = 0; i < s->nelements; i++)
764 t->keys[i] = s->keys[i];
765 t->values[i] = sRefSet_newCopy (s->values[i]);
766 t->rangeValues[i] = s->rangeValues[i];
774 environmentTable_levelPrune (environmentTable s, int lexlevel)
778 if (environmentTable_isEmpty (s))
785 int backcount = s->nelements - 1;
787 for (i = 0; i <= backcount; i++)
789 sRef key = s->keys[i];
791 if (sRef_lexLevel (key) > lexlevel)
794 for (j = backcount; j > i; j--)
800 if (sRef_lexLevel (s->keys[j]) <= lexlevel)
802 s->keys[i] = s->keys[j];
803 s->values[i] = s->values[j];
804 sRefSet_levelPrune (s->values[i], lexlevel);
805 /*@innerbreak@*/ break;
813 sRefSet_levelPrune (s->values[i], lexlevel);
822 ** like level union, but know that t2 was executed after t1. So if
823 ** t1 has x -> { a, b } and t2 has x -> { a }, then result has x -> { a }.
825 ** NOTE: t2 is "only".
828 environmentTable environmentTable_levelUnionSeq (/*@returned@*/ environmentTable t1,
829 /*@only@*/ environmentTable t2, int level)
831 if (environmentTable_isUndefined (t2))
836 if (environmentTable_isUndefined (t1))
838 t1 = environmentTable_newEmpty ();
842 environmentTable_levelPrune (t1, level);
845 environmentTable_elements (t2, key, value)
847 if (sRef_lexLevel (key) <= level)
849 int ind = environmentTable_lookupRefs (t1, key);
851 sRefSet_levelPrune (value, level);
853 if (ind == ATINVALID)
855 /* okay, t2 is killed */
856 /*@-exposetrans@*/ /*@-dependenttrans@*/
857 t1 = environmentTable_addSet (t1, key, value);
858 /*@=exposetrans@*/ /*@=dependenttrans@*/
862 sRefSet_free (t1->values[ind]);
864 /*@-dependenttrans@*/ /* okay, t2 is killed */
865 t1->values[ind] = value;
866 /*@=dependenttrans@*/
871 /*@-exposetrans@*/ /*@-dependenttrans@*/
872 sRefSet_free (value);
873 /*@=exposetrans@*/ /*@=dependenttrans@*/
876 } end_environmentTable_elements;
886 environmentTable_levelUnion (/*@returned@*/ environmentTable t1, environmentTable t2, int level)
888 if (environmentTable_isUndefined (t1))
890 if (environmentTable_isUndefined (t2))
896 t1 = environmentTable_newEmpty ();
901 environmentTable_levelPrune (t1, level);
904 environmentTable_elements (t2, key, cvalue)
906 sRefSet value = sRefSet_newCopy (cvalue);
908 if (sRef_lexLevel (key) <= level)
910 sRefSet_levelPrune (value, level);
912 if (sRefSet_size (value) > 0)
914 int ind = environmentTable_lookupRefs (t1, key);
916 if (ind == ATINVALID)
918 t1 = environmentTable_addSet (t1, key, value);
922 t1->values[ind] = sRefSet_union (t1->values[ind], value);
923 sRefSet_free (value);
928 sRefSet_free (value);
933 sRefSet_free (value);
935 } end_environmentTable_elements;
940 environmentTable environmentTable_levelUnionNew (environmentTable t1, environmentTable t2, int level)
942 environmentTable ret = environmentTable_levelUnion (environmentTable_copy (t1), t2, level);
948 environmentTable_unparse (environmentTable s)
950 cstring st = cstring_undefined;
952 if (environmentTable_isUndefined (s)) return (cstring_makeLiteral ("<NULL>"));
954 environmentTable_elements (s, key, value)
956 st = message ("%q\t%q -> %q\n", st, sRef_unparse (key),
957 sRefSet_unparse (value));
958 } end_environmentTable_elements;
968 environmentTable_fixSrefs (environmentTable s)
972 if (environmentTable_isUndefined (s)) return;
974 for (i = 0; i < s->nelements; i++)
976 sRef old = s->keys[i];
978 if (sRef_isLocalVar (old))
980 s->keys[i] = uentry_getSref (sRef_getUentry (old));
983 sRefSet_fixSrefs (s->values[i]);
988 environmentTable_free (/*@only@*/ environmentTable s)
992 if (environmentTable_isUndefined (s)) return;
994 for (i = 0; i < s->nelements; i++)
996 sRefSet_free (s->values[i]);
1005 environmentTable_checkGlobs (environmentTable t)
1007 environmentTable_elements (t, key, value)
1009 sRef root = sRef_getRootBase (key);
1011 if (sRef_isAliasCheckedGlobal (root))
1013 sRefSet_realElements (value, sr)
1015 root = sRef_getRootBase (sr);
1017 if (((sRef_isAliasCheckedGlobal (root)
1018 && !(sRef_similar (root, key)))
1019 || sRef_isAnyParam (root))
1020 && !sRef_isExposed (root))
1022 if (sRef_isAliasCheckedGlobal (key))
1024 if (!(sRef_isShared (key)
1025 && sRef_isShared (root)))
1028 (FLG_GLOBENVIRONMENT,
1030 ("Function returns with %q variable %q environmenting %q %q",
1031 cstring_makeLiteral (sRef_isRealGlobal (key)
1032 ? "global" : "file static"),
1034 cstring_makeLiteral (sRef_isAnyParam (root)
1035 ? "parameter" : "global"),
1042 } end_sRefSet_realElements;
1044 else if (sRef_isAnyParam (key) || sRef_isAnyParam (root))
1046 sRefSet_realElements (value, sr)
1048 root = sRef_getRootBase (sr);
1050 if (sRef_isAliasCheckedGlobal (root)
1051 && !sRef_isExposed (root)
1052 && !sRef_isDead (key)
1053 && !sRef_isShared (root))
1056 (FLG_GLOBENVIRONMENT,
1057 message ("Function returns with parameter %q environmenting %q %q",
1059 cstring_makeLiteral (sRef_isRealGlobal (root)
1060 ? "global" : "file static"),
1064 } end_sRefSet_realElements;
1070 } end_environmentTable_elements;