2 ** Splint - 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://www.splint.org
28 # include "lclintMacros.nf"
31 /*@constant int ATINVALID; @*/
35 rangeTable_canRangeAux (rangeTable p_s, sRef p_sr, int p_lim) /*@*/ ;
37 rangeTable_aliasedByLimit (rangeTable p_s, sRef p_sr, int p_lim) /*@*/ ;
39 rangeTable_aliasedByAux (rangeTable p_s, sRef p_sr, int p_lim) /*@*/ ;
44 return (rangeTable_undefined);
47 static /*@only@*/ /*@notnull@*/ rangeTable
48 rangeTable_newEmpty (void)
50 rangeTable s = (rangeTable) dmalloc (sizeof (*s));
53 s->nspace = rangeTableBASESIZE;
54 s->keys = (sRef *) dmalloc (sizeof (*s->keys) * rangeTableBASESIZE);
55 s->values = (sRefSet *) dmalloc (sizeof (*s->values) * rangeTableBASESIZE);
56 s->ranges = (sRefSet *) dmalloc (sizeof (*s->ranges) * rangeTableBASESIZE);
61 rangeTable_grow (/*@notnull@*/ rangeTable s)
64 o_sRefSet *oldvalues = s->values;
65 sRef *oldkeys = s->keys;
66 RangeAt *oldranges = s->ranges;
68 s->nspace += rangeTableBASESIZE;
70 s->values = (sRefSet *) dmalloc (sizeof (*s->values)
71 * (s->nelements + s->nspace));
72 s->keys = (sRef *) dmalloc (sizeof (*s->keys) * (s->nelements + rangeTableBASESIZE));
74 s->ranges = (sRef *) dmalloc (sizeof (*s->ranges) * (s->nelements + rangeTableBASESIZE));
77 if (s->keys == (sRef *) 0 || s->values == (sRefSet *)0 || s->ranges = (range_At*) 0 )
79 llfatalerror (cstring_makeLiteral ("rangeTable_grow: out of memory!"));
82 for (i = 0; i < s->nelements; i++)
84 s->values[i] = oldvalues[i];
85 s->keys[i] = oldkeys[i];
86 s->ranges[i] = oldranges[i];
93 static int rangeTable_lookupRefs (/*@notnull@*/ rangeTable s, sRef sr)
98 for (i = 0; i < rangeTable_size (s); i++)
100 if (sRef_same (sr, s->keys[i]))
110 ** sr rangees al (and anything al rangees!)
114 rangeTable_addMustRange (/*@returned@*/ rangeTable s,
115 /*@exposed@*/ sRef sr,
121 llassert (NORANGE (sr, al));
123 if (rangeTable_isUndefined (s))
125 s = rangeTable_newEmpty ();
130 ind = rangeTable_lookupRefs (s, sr);
133 ss = rangeTable_canRange (s, al);
136 if (ind == ATINVALID)
138 if (s->nspace <= 0) {
143 s->keys[s->nelements] = sr;
144 s->values[s->nelements] = sRefSet_single (al);
150 s->values[ind] = sRefSet_insert (s->values[ind], al);
153 s->values[ind] = sRefSet_unionExcept (s->values[ind], ss, s->keys[ind]);
160 rangeTable_addSet (/*@returned@*/ rangeTable s,
161 /*@exposed@*/ sRef key, /*@only@*/ sRefSet value)
163 if (!sRefSet_isEmpty (value))
165 if (rangeTable_isUndefined (s))
167 s = rangeTable_newEmpty ();
178 s->keys[s->nelements] = key;
179 s->values[s->nelements] = value;
184 sRefSet_free (value);
191 ** When rangees are cleared:
193 ** o remove all entries for sr
194 ** o replace all rangees for things which range sr with sr's rangees
196 ** Clear rangees for sr; if sr is a direct param reference, clear its rangees too.
199 static void rangeTable_clearRangeesAux (/*@notnull@*/ rangeTable p_s, sRef p_sr)
202 void rangeTable_clearRangees (rangeTable s, sRef sr)
204 if (rangeTable_isUndefined (s))
210 sRef rb = sRef_getRootBase (sr);
213 if (!sRef_isCvar (sr) && sRef_isLocalVar (rb))
215 int ind = rangeTable_lookupRefs (s, rb);
217 if (ind != ATINVALID)
219 sRefSet al = s->values[ind];
222 sRefSet_realElements (al, el)
225 if (sRef_isParam (el))
227 if (sRef_sameName (el, rb))
229 sRef fb = sRef_fixBase (sr, el);
231 rangeTable_clearRangeesAux (s, fb);
234 } end_sRefSet_realElements ;
238 rangeTable_clearRangeesAux (s, sr);
243 void rangeTable_clearRangeesAux (/*@notnull@*/ rangeTable s, sRef sr)
247 for (i = 0; i < s->nelements; i++)
249 sRef key = s->keys[i];
251 if (sRef_includedBy (key, sr))
253 sRefSet_clear (s->values[i]);
257 (void) sRefSet_deleteBase (s->values[i], sr);
263 ** returns set of all sRefs that must range sr (but are different from sr)
266 static /*@only@*/ sRefSet rangeTable_rangeedByAux (rangeTable s, sRef sr, int lim)
268 static bool hadWarning = FALSE;
269 sRefSet res = sRefSet_undefined;
272 llassert (!sRef_isConj (sr));
275 if (rangeTable_isUndefined (s) || lim >= RANGESEARCHLIMIT)
277 if (lim >= RANGESEARCHLIMIT && !hadWarning)
280 (message ("Range search limit exceeded, checking %q. "
281 "This either means there is a variable with at least "
282 "%d indirections, or there is a bug in Splint.",
289 return sRefSet_undefined;
295 if (sRef_isPointer (sr))
297 abl = rangeTable_rangeedByLimit (s, sRef_getBase (sr), lim);
298 res = sRefSet_addIndirection (abl);
300 else if (sRef_isAddress (sr))
302 abl = rangeTable_rangeedByLimit (s, sRef_getBase (sr), lim);
303 res = sRefSet_removeIndirection (abl);
305 else if (sRef_isField (sr))
307 abl = rangeTable_rangeedByLimit (s, sRef_getBase (sr), lim);
308 res = sRefSet_accessField (abl, sRef_getField (sr));
310 else if (sRef_isArrayFetch (sr))
312 abl = rangeTable_rangeedByLimit (s, sRef_getBase (sr), lim);
314 if (sRef_isIndexKnown (sr))
316 int idx = sRef_getIndex (sr);
318 res = sRefSet_fetchKnown (abl, idx);
322 res = sRefSet_fetchUnknown (abl);
327 abl = sRefSet_undefined;
333 for (i = 0; i < s->nelements; i++)
335 sRef elem = s->keys[i];
337 if (!sRef_same (sr, elem)) /* was sameName */
340 sRefSet_realElements (s->values[i], current)
343 if (sRef_similar (sr, current))
345 res = sRefSet_insert (res, sRef_fixOuterRef (elem));
346 /*@innerbreak@*/ break;
348 } end_sRefSet_realElements;
355 static /*@only@*/ sRefSet rangeTable_rangeedByLimit (rangeTable s, sRef sr, int lim)
360 if (sRef_isConj (sr))
362 res = sRefSet_unionFree (rangeTable_rangeedByLimit (s, sRef_getConjA (sr), lim),
363 rangeTable_rangeedByLimit (s, sRef_getConjB (sr), lim));
367 res = rangeTable_rangeedByAux (s, sr, lim + 1);
373 /*@only@*/ sRefSet rangeTable_rangeedBy (rangeTable s, sRef sr)
375 if (sRef_isConj (sr))
377 return (sRefSet_unionFree (rangeTable_rangeedBy (s, sRef_getConjA (sr)),
378 rangeTable_rangeedBy (s, sRef_getConjB (sr))));
381 return (rangeTable_rangeedByAux (s, sr, 0));
384 /*@only@*/ sRefSet rangeTable_canRange (rangeTable s, sRef sr)
389 if (sRef_isConj (sr))
391 res = sRefSet_unionFree (rangeTable_canRange (s, sRef_getConjA (sr)),
392 rangeTable_canRange (s, sRef_getConjB (sr)));
396 res = rangeTable_canRangeAux (s, sr, 0);
403 ** need to limit the depth of rangeing searches
406 static /*@only@*/ sRefSet rangeTable_canRangeLimit (rangeTable s, sRef sr, int lim)
410 if (sRef_isConj (sr))
412 sRefSet a = rangeTable_canRangeLimit (s, sRef_getConjA (sr), lim);
413 sRefSet b = rangeTable_canRangeLimit (s, sRef_getConjB (sr), lim);
415 res = sRefSet_unionFree (a, b);
419 res = rangeTable_canRangeAux (s, sr, lim + 1);
425 static /*@only@*/ sRefSet
426 rangeTable_canRangeAux (rangeTable s, sRef sr, int lim)
428 static bool hadWarning = FALSE;
429 llassert (!sRef_isConj (sr));
432 if (rangeTable_isUndefined (s) || lim >= RANGESEARCHLIMIT)
434 if (lim >= RANGESEARCHLIMIT && !hadWarning)
437 (message ("Range search limit exceeded, checking %q. "
438 "This either means there is a variable with at least "
439 "%d indirections, or there is a bug in Splint.",
446 return sRefSet_undefined;
450 int ind = rangeTable_lookupRefs (s, sr);
452 if (sRef_isPointer (sr) || sRef_isAddress (sr) || sRef_isField (sr)
453 || sRef_isArrayFetch (sr))
455 sRef base = sRef_getBase (sr);
456 sRefSet tmp = rangeTable_canRangeLimit (s, base, lim);
459 if (sRef_isPointer (sr))
461 ret = sRefSet_addIndirection (tmp);
463 else if (sRef_isAddress (sr))
465 ret = sRefSet_removeIndirection (tmp);
467 else if (sRef_isField (sr))
469 ret = sRefSet_accessField (tmp, sRef_getField (sr));
471 else if (sRef_isArrayFetch (sr))
473 if (sRef_isIndexKnown (sr))
475 ret = sRefSet_fetchKnown (tmp, sRef_getIndex (sr));
479 ret = sRefSet_fetchUnknown (tmp);
487 if (ind != ATINVALID)
489 ret = sRefSet_union (ret, s->values[ind]);
496 if (ind == ATINVALID) return sRefSet_undefined;
498 return sRefSet_newCopy (s->values[ind]);
502 rangeTable rangeTable_copy (rangeTable s)
504 if (rangeTable_isEmpty (s))
506 return rangeTable_undefined;
510 rangeTable t = (rangeTable) dmalloc (sizeof (*s));
513 t->nelements = s->nelements;
515 t->keys = (sRef *) dmalloc (sizeof (*s->keys) * s->nelements);
516 t->values = (sRefSet *) dmalloc (sizeof (*s->values) * t->nelements);
518 for (i = 0; i < s->nelements; i++)
520 t->keys[i] = s->keys[i];
521 t->values[i] = sRefSet_newCopy (s->values[i]);
529 rangeTable_levelPrune (rangeTable s, int lexlevel)
533 if (rangeTable_isEmpty (s))
540 int backcount = s->nelements - 1;
542 for (i = 0; i <= backcount; i++)
544 sRef key = s->keys[i];
546 if (sRef_lexLevel (key) > lexlevel)
549 for (j = backcount; j > i; j--)
555 if (sRef_lexLevel (s->keys[j]) <= lexlevel)
557 s->keys[i] = s->keys[j];
558 s->values[i] = s->values[j];
559 sRefSet_levelPrune (s->values[i], lexlevel);
560 /*@innerbreak@*/ break;
568 sRefSet_levelPrune (s->values[i], lexlevel);
577 ** like level union, but know that t2 was executed after t1. So if
578 ** t1 has x -> { a, b } and t2 has x -> { a }, then result has x -> { a }.
580 ** NOTE: t2 is "only".
583 rangeTable rangeTable_levelUnionSeq (/*@returned@*/ rangeTable t1,
584 /*@only@*/ rangeTable t2, int level)
586 if (rangeTable_isUndefined (t2))
591 if (rangeTable_isUndefined (t1))
593 t1 = rangeTable_newEmpty ();
597 rangeTable_levelPrune (t1, level);
600 rangeTable_elements (t2, key, value)
602 if (sRef_lexLevel (key) <= level)
604 int ind = rangeTable_lookupRefs (t1, key);
606 sRefSet_levelPrune (value, level);
608 if (ind == ATINVALID)
610 /* okay, t2 is killed */
611 /*@-exposetrans@*/ /*@-dependenttrans@*/
612 t1 = rangeTable_addSet (t1, key, value);
613 /*@=exposetrans@*/ /*@=dependenttrans@*/
617 sRefSet_free (t1->values[ind]);
619 /*@-dependenttrans@*/ /* okay, t2 is killed */
620 t1->values[ind] = value;
621 /*@=dependenttrans@*/
626 /*@-exposetrans@*/ /*@-dependenttrans@*/
627 sRefSet_free (value);
628 /*@=exposetrans@*/ /*@=dependenttrans@*/
631 } end_rangeTable_elements;
641 rangeTable_levelUnion (/*@returned@*/ rangeTable t1, rangeTable t2, int level)
643 if (rangeTable_isUndefined (t1))
645 if (rangeTable_isUndefined (t2))
651 t1 = rangeTable_newEmpty ();
656 rangeTable_levelPrune (t1, level);
659 rangeTable_elements (t2, key, cvalue)
661 sRefSet value = sRefSet_newCopy (cvalue);
663 if (sRef_lexLevel (key) <= level)
665 sRefSet_levelPrune (value, level);
667 if (sRefSet_size (value) > 0)
669 int ind = rangeTable_lookupRefs (t1, key);
671 if (ind == ATINVALID)
673 t1 = rangeTable_addSet (t1, key, value);
677 t1->values[ind] = sRefSet_union (t1->values[ind], value);
678 sRefSet_free (value);
683 sRefSet_free (value);
688 sRefSet_free (value);
690 } end_rangeTable_elements;
695 rangeTable rangeTable_levelUnionNew (rangeTable t1, rangeTable t2, int level)
697 rangeTable ret = rangeTable_levelUnion (rangeTable_copy (t1), t2, level);
703 rangeTable_unparse (rangeTable s)
705 cstring st = cstring_undefined;
707 if (rangeTable_isUndefined (s)) return (cstring_makeLiteral ("<NULL>"));
709 rangeTable_elements (s, key, value)
711 st = message ("%q\t%q -> %q\n", st, sRef_unparse (key),
712 sRefSet_unparse (value));
713 } end_rangeTable_elements;
723 rangeTable_fixSrefs (rangeTable s)
727 if (rangeTable_isUndefined (s)) return;
729 for (i = 0; i < s->nelements; i++)
731 sRef old = s->keys[i];
733 if (sRef_isLocalVar (old))
735 s->keys[i] = uentry_getSref (sRef_getUentry (old));
738 sRefSet_fixSrefs (s->values[i]);
743 rangeTable_free (/*@only@*/ rangeTable s)
747 if (rangeTable_isUndefined (s)) return;
749 for (i = 0; i < s->nelements; i++)
751 sRefSet_free (s->values[i]);
760 rangeTable_checkGlobs (rangeTable t)
762 rangeTable_elements (t, key, value)
764 sRef root = sRef_getRootBase (key);
766 if (sRef_isRangeCheckedGlobal (root))
768 sRefSet_realElements (value, sr)
770 root = sRef_getRootBase (sr);
772 if (((sRef_isRangeCheckedGlobal (root)
773 && !(sRef_similar (root, key)))
774 || sRef_isAnyParam (root))
775 && !sRef_isExposed (root))
777 if (sRef_isRangeCheckedGlobal (key))
779 if (!(sRef_isShared (key)
780 && sRef_isShared (root)))
785 ("Function returns with %q variable %q rangeing %q %q",
786 cstring_makeLiteral (sRef_isRealGlobal (key)
787 ? "global" : "file static"),
789 cstring_makeLiteral (sRef_isAnyParam (root)
790 ? "parameter" : "global"),
797 } end_sRefSet_realElements;
799 else if (sRef_isAnyParam (key) || sRef_isAnyParam (root))
801 sRefSet_realElements (value, sr)
803 root = sRef_getRootBase (sr);
805 if (sRef_isRangeCheckedGlobal (root)
806 && !sRef_isExposed (root)
807 && !sRef_isDead (key)
808 && !sRef_isShared (root))
812 message ("Function returns with parameter %q rangeing %q %q",
814 cstring_makeLiteral (sRef_isRealGlobal (root)
815 ? "global" : "file static"),
819 } end_sRefSet_realElements;
825 } end_rangeTable_elements;