]> andersk Git - splint.git/blame - src/aliasTable.c
Updated libary version number.
[splint.git] / src / aliasTable.c
CommitLineData
616915dd 1/*
11db3170 2** Splint - annotation-assisted static program checker
c59f5181 3** Copyright (C) 1994-2003 University of Virginia,
616915dd 4** Massachusetts Institute of Technology
5**
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.
10**
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.
15**
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.
19**
155af98d 20** For information on splint: info@splint.org
21** To report a bug: splint-bug@splint.org
11db3170 22** For more information: http://www.splint.org
616915dd 23*/
24/*
25** aliasTable.c
26*/
27
1b8ae690 28# include "splintMacros.nf"
616915dd 29# include "basic.h"
30
31/*@constant int ATINVALID; @*/
32# define ATINVALID -1
33
34static sRefSet
35 aliasTable_canAliasAux (aliasTable p_s, sRef p_sr, int p_lim) /*@*/ ;
36static sRefSet
37 aliasTable_aliasedByLimit (aliasTable p_s, sRef p_sr, int p_lim) /*@*/ ;
38static sRefSet
39 aliasTable_aliasedByAux (aliasTable p_s, sRef p_sr, int p_lim) /*@*/ ;
40
41aliasTable
42aliasTable_new ()
43{
44 return (aliasTable_undefined);
45}
46
47static /*@only@*/ /*@notnull@*/ aliasTable
48aliasTable_newEmpty (void)
49{
50 aliasTable s = (aliasTable) dmalloc (sizeof (*s));
51
52 s->nelements = 0;
53 s->nspace = aliasTableBASESIZE;
54 s->keys = (sRef *) dmalloc (sizeof (*s->keys) * aliasTableBASESIZE);
55 s->values = (sRefSet *) dmalloc (sizeof (*s->values) * aliasTableBASESIZE);
56
57 return (s);
58}
59
60static void
61aliasTable_grow (/*@notnull@*/ aliasTable s)
62{
63 int i;
64 o_sRefSet *oldvalues = s->values;
65 sRef *oldkeys = s->keys;
66
67 s->nspace += aliasTableBASESIZE;
68
69 s->values = (sRefSet *) dmalloc (sizeof (*s->values)
70 * (s->nelements + s->nspace));
71 s->keys = (sRef *) dmalloc (sizeof (*s->keys) * (s->nelements + aliasTableBASESIZE));
72
73 if (s->keys == (sRef *) 0 || s->values == (sRefSet *)0)
74 {
75 llfatalerror (cstring_makeLiteral ("aliasTable_grow: out of memory!"));
76 }
77
78 for (i = 0; i < s->nelements; i++)
79 {
80 s->values[i] = oldvalues[i];
81 s->keys[i] = oldkeys[i];
82 }
83
84 sfree (oldvalues);
85 sfree (oldkeys);
86}
87
88static int aliasTable_lookupRefs (/*@notnull@*/ aliasTable s, sRef sr)
89{
90 int i;
91
92
93 for (i = 0; i < aliasTable_size (s); i++)
94 {
95 if (sRef_same (sr, s->keys[i]))
96 {
97 return i;
98 }
99 }
100
101 return ATINVALID;
102}
103
104/*
105** sr aliases al (and anything al aliases!)
106*/
107
108aliasTable
109aliasTable_addMustAlias (/*@returned@*/ aliasTable s,
110 /*@exposed@*/ sRef sr,
28bf4b0b 111 /*@exposed@*/ sRef al)
616915dd 112{
113 int ind;
114 sRefSet ss;
115
116 llassert (NOALIAS (sr, al));
28bf4b0b 117
118 DPRINTF (("Adding alias: %s / %s", sRef_unparseFull (sr),
119 sRef_unparseFull (al)));
616915dd 120
121 if (aliasTable_isUndefined (s))
122 {
123 s = aliasTable_newEmpty ();
124 ind = ATINVALID;
125 }
126 else
127 {
128 ind = aliasTable_lookupRefs (s, sr);
129 }
130
131 ss = aliasTable_canAlias (s, al);
28bf4b0b 132 DPRINTF (("Previous aliases: %s", sRefSet_unparse (ss)));
616915dd 133
134 if (ind == ATINVALID)
135 {
136 if (s->nspace <= 0) {
137 aliasTable_grow (s);
138 }
139
140 s->nspace--;
141 s->keys[s->nelements] = sr;
142 s->values[s->nelements] = sRefSet_single (al);
143 ind = s->nelements;
144 s->nelements++;
145 }
146 else
147 {
148 s->values[ind] = sRefSet_insert (s->values[ind], al);
149 }
150
151 s->values[ind] = sRefSet_unionExcept (s->values[ind], ss, s->keys[ind]);
28bf4b0b 152 DPRINTF (("New aliases: %s", sRefSet_unparse (s->values[ind])));
616915dd 153
154 sRefSet_free (ss);
155 return s;
156}
157
158static aliasTable
159 aliasTable_addSet (/*@returned@*/ aliasTable s,
160 /*@exposed@*/ sRef key, /*@only@*/ sRefSet value)
161{
162 if (!sRefSet_isEmpty (value))
163 {
164 if (aliasTable_isUndefined (s))
165 {
166 s = aliasTable_newEmpty ();
167 }
168 else
169 {
170 if (s->nspace <= 0)
171 {
172 aliasTable_grow (s);
173 }
174 }
175
176 s->nspace--;
177 s->keys[s->nelements] = key;
178 s->values[s->nelements] = value;
179 s->nelements++;
180 }
181 else
182 {
183 sRefSet_free (value);
184 }
185
186 return s;
187}
188
189/*
190** When aliases are cleared:
191**
192** o remove all entries for sr
193** o replace all aliases for things which alias sr with sr's aliases
194**
195** Clear aliases for sr; if sr is a direct param reference, clear its aliases too.
196*/
197
198static void aliasTable_clearAliasesAux (/*@notnull@*/ aliasTable p_s, sRef p_sr)
199 /*@modifies p_s@*/ ;
200
201void aliasTable_clearAliases (aliasTable s, sRef sr)
202{
203 if (aliasTable_isUndefined (s))
204 {
205 return;
206 }
207 else
208 {
209 sRef rb = sRef_getRootBase (sr);
210
211
212 if (!sRef_isCvar (sr) && sRef_isLocalVar (rb))
213 {
214 int ind = aliasTable_lookupRefs (s, rb);
215
216 if (ind != ATINVALID)
217 {
218 sRefSet al = s->values[ind];
219
220
221 sRefSet_realElements (al, el)
222 {
223
224 if (sRef_isParam (el))
225 {
226 if (sRef_sameName (el, rb))
227 {
228 sRef fb = sRef_fixBase (sr, el);
229
230 aliasTable_clearAliasesAux (s, fb);
231 }
232 }
233 } end_sRefSet_realElements ;
234 }
235 }
236
237 aliasTable_clearAliasesAux (s, sr);
238 }
239}
240
241static
242void aliasTable_clearAliasesAux (/*@notnull@*/ aliasTable s, sRef sr)
243{
244 int i;
245
246 for (i = 0; i < s->nelements; i++)
247 {
248 sRef key = s->keys[i];
249
250 if (sRef_includedBy (key, sr))
251 {
252 sRefSet_clear (s->values[i]);
253 }
254 else
255 {
256 (void) sRefSet_deleteBase (s->values[i], sr);
257 }
258 }
259}
260
261/*
262** returns set of all sRefs that must alias sr (but are different from sr)
263*/
264
265static /*@only@*/ sRefSet aliasTable_aliasedByAux (aliasTable s, sRef sr, int lim)
266{
267 static bool hadWarning = FALSE;
268 sRefSet res = sRefSet_undefined;
269 int i;
270
271 llassert (!sRef_isConj (sr));
272
273
274 if (aliasTable_isUndefined (s) || lim >= ALIASSEARCHLIMIT)
275 {
276 if (lim >= ALIASSEARCHLIMIT && !hadWarning)
277 {
278 llquietbug
279 (message ("Alias search limit exceeded, checking %q. "
280 "This either means there is a variable with at least "
11db3170 281 "%d indirections, or there is a bug in Splint.",
616915dd 282 sRef_unparse (sr),
283 ALIASSEARCHLIMIT));
284
285 hadWarning = TRUE;
286 }
287
288 return sRefSet_undefined;
289 }
290 else
291 {
292 sRefSet abl;
293
294 if (sRef_isPointer (sr))
295 {
296 abl = aliasTable_aliasedByLimit (s, sRef_getBase (sr), lim);
297 res = sRefSet_addIndirection (abl);
298 }
299 else if (sRef_isAddress (sr))
300 {
301 abl = aliasTable_aliasedByLimit (s, sRef_getBase (sr), lim);
302 res = sRefSet_removeIndirection (abl);
303 }
304 else if (sRef_isField (sr))
305 {
306 abl = aliasTable_aliasedByLimit (s, sRef_getBase (sr), lim);
307 res = sRefSet_accessField (abl, sRef_getField (sr));
308 }
309 else if (sRef_isArrayFetch (sr))
310 {
311 abl = aliasTable_aliasedByLimit (s, sRef_getBase (sr), lim);
312
313 if (sRef_isIndexKnown (sr))
314 {
315 int idx = sRef_getIndex (sr);
316
317 res = sRefSet_fetchKnown (abl, idx);
318 }
319 else
320 {
321 res = sRefSet_fetchUnknown (abl);
322 }
323 }
324 else
325 {
326 abl = sRefSet_undefined;
327 }
328
329 sRefSet_free (abl);
330 }
331
332 for (i = 0; i < s->nelements; i++)
333 {
334 sRef elem = s->keys[i];
335
336 if (!sRef_same (sr, elem)) /* was sameName */
337 {
338
339 sRefSet_realElements (s->values[i], current)
340 {
341
342 if (sRef_similar (sr, current))
343 {
344 res = sRefSet_insert (res, sRef_fixOuterRef (elem));
345 /*@innerbreak@*/ break;
346 }
347 } end_sRefSet_realElements;
348 }
349 }
350
351 return res;
352}
353
354static /*@only@*/ sRefSet aliasTable_aliasedByLimit (aliasTable s, sRef sr, int lim)
355{
356 sRefSet res;
357
358
359 if (sRef_isConj (sr))
360 {
361 res = sRefSet_unionFree (aliasTable_aliasedByLimit (s, sRef_getConjA (sr), lim),
362 aliasTable_aliasedByLimit (s, sRef_getConjB (sr), lim));
363 }
364 else
365 {
366 res = aliasTable_aliasedByAux (s, sr, lim + 1);
367 }
368
369 return res;
370}
371
372/*@only@*/ sRefSet aliasTable_aliasedBy (aliasTable s, sRef sr)
373{
374 if (sRef_isConj (sr))
375 {
376 return (sRefSet_unionFree (aliasTable_aliasedBy (s, sRef_getConjA (sr)),
377 aliasTable_aliasedBy (s, sRef_getConjB (sr))));
378 }
379
380 return (aliasTable_aliasedByAux (s, sr, 0));
381}
382
383/*@only@*/ sRefSet aliasTable_canAlias (aliasTable s, sRef sr)
384{
385 sRefSet res;
386
387
388 if (sRef_isConj (sr))
389 {
390 res = sRefSet_unionFree (aliasTable_canAlias (s, sRef_getConjA (sr)),
391 aliasTable_canAlias (s, sRef_getConjB (sr)));
392 }
393 else
394 {
395 res = aliasTable_canAliasAux (s, sr, 0);
396 }
397
398 return res;
399}
400
401/*
402** need to limit the depth of aliasing searches
403*/
404
405static /*@only@*/ sRefSet aliasTable_canAliasLimit (aliasTable s, sRef sr, int lim)
406{
407 sRefSet res;
408
409 if (sRef_isConj (sr))
410 {
411 sRefSet a = aliasTable_canAliasLimit (s, sRef_getConjA (sr), lim);
412 sRefSet b = aliasTable_canAliasLimit (s, sRef_getConjB (sr), lim);
413
414 res = sRefSet_unionFree (a, b);
415 }
416 else
417 {
418 res = aliasTable_canAliasAux (s, sr, lim + 1);
419 }
420
421 return res;
422}
423
424static /*@only@*/ sRefSet
425 aliasTable_canAliasAux (aliasTable s, sRef sr, int lim)
426{
427 static bool hadWarning = FALSE;
428 llassert (!sRef_isConj (sr));
429
430
431 if (aliasTable_isUndefined (s) || lim >= ALIASSEARCHLIMIT)
432 {
433 if (lim >= ALIASSEARCHLIMIT && !hadWarning)
434 {
435 llquietbug
436 (message ("Alias search limit exceeded, checking %q. "
437 "This either means there is a variable with at least "
11db3170 438 "%d indirections, or there is a bug in Splint.",
616915dd 439 sRef_unparse (sr),
440 ALIASSEARCHLIMIT));
441
442 hadWarning = TRUE;
443 }
444
445 return sRefSet_undefined;
446 }
447 else
448 {
449 int ind = aliasTable_lookupRefs (s, sr);
450
451 if (sRef_isPointer (sr) || sRef_isAddress (sr) || sRef_isField (sr)
452 || sRef_isArrayFetch (sr))
453 {
454 sRef base = sRef_getBase (sr);
455 sRefSet tmp = aliasTable_canAliasLimit (s, base, lim);
456 sRefSet ret;
457
458 if (sRef_isPointer (sr))
459 {
460 ret = sRefSet_addIndirection (tmp);
461 }
462 else if (sRef_isAddress (sr))
463 {
464 ret = sRefSet_removeIndirection (tmp);
465 }
466 else if (sRef_isField (sr))
467 {
468 ret = sRefSet_accessField (tmp, sRef_getField (sr));
469 }
470 else if (sRef_isArrayFetch (sr))
471 {
472 if (sRef_isIndexKnown (sr))
473 {
474 ret = sRefSet_fetchKnown (tmp, sRef_getIndex (sr));
475 }
476 else
477 {
478 ret = sRefSet_fetchUnknown (tmp);
479 }
480 }
481 else
482 {
483 BADBRANCH;
484 }
485
486 if (ind != ATINVALID)
487 {
488 ret = sRefSet_union (ret, s->values[ind]);
489 }
28bf4b0b 490
616915dd 491 sRefSet_free (tmp);
28bf4b0b 492 return ret;
616915dd 493 }
494
495 if (ind == ATINVALID) return sRefSet_undefined;
496
497 return sRefSet_newCopy (s->values[ind]);
498 }
499}
500
501aliasTable aliasTable_copy (aliasTable s)
502{
503 if (aliasTable_isEmpty (s))
504 {
505 return aliasTable_undefined;
506 }
507 else
508 {
509 aliasTable t = (aliasTable) dmalloc (sizeof (*s));
510 int i;
511
512 t->nelements = s->nelements;
513 t->nspace = 0;
514 t->keys = (sRef *) dmalloc (sizeof (*s->keys) * s->nelements);
515 t->values = (sRefSet *) dmalloc (sizeof (*s->values) * t->nelements);
516
517 for (i = 0; i < s->nelements; i++)
518 {
519 t->keys[i] = s->keys[i];
520 t->values[i] = sRefSet_newCopy (s->values[i]);
521 }
522
523 return t;
524 }
525}
526
527static void
528aliasTable_levelPrune (aliasTable s, int lexlevel)
529{
530
531
532 if (aliasTable_isEmpty (s))
533 {
534 return;
535 }
536 else
537 {
538 int i;
539 int backcount = s->nelements - 1;
540
541 for (i = 0; i <= backcount; i++)
542 {
543 sRef key = s->keys[i];
544
545 if (sRef_lexLevel (key) > lexlevel)
546 {
547 int j;
548 for (j = backcount; j > i; j--)
549 {
550 backcount--;
551 s->nelements--;
552 s->nspace++;
553
554 if (sRef_lexLevel (s->keys[j]) <= lexlevel)
555 {
556 s->keys[i] = s->keys[j];
557 s->values[i] = s->values[j];
558 sRefSet_levelPrune (s->values[i], lexlevel);
559 /*@innerbreak@*/ break;
560 }
561 }
562 if (backcount == i)
563 s->nelements--;
564 }
565 else
566 {
567 sRefSet_levelPrune (s->values[i], lexlevel);
568 }
569 }
570 }
571}
572
573/*
574** levelUnionSeq
575**
576** like level union, but know that t2 was executed after t1. So if
577** t1 has x -> { a, b } and t2 has x -> { a }, then result has x -> { a }.
578**
579** NOTE: t2 is "only".
580*/
581
582aliasTable aliasTable_levelUnionSeq (/*@returned@*/ aliasTable t1,
583 /*@only@*/ aliasTable t2, int level)
584{
585 if (aliasTable_isUndefined (t2))
586 {
587 return t1;
588 }
589
590 if (aliasTable_isUndefined (t1))
591 {
592 t1 = aliasTable_newEmpty ();
593 }
594 else
595 {
596 aliasTable_levelPrune (t1, level);
597 }
598
599 aliasTable_elements (t2, key, value)
600 {
601 if (sRef_lexLevel (key) <= level)
602 {
603 int ind = aliasTable_lookupRefs (t1, key);
604
605 sRefSet_levelPrune (value, level);
606
607 if (ind == ATINVALID)
608 {
609 /* okay, t2 is killed */
610 /*@-exposetrans@*/ /*@-dependenttrans@*/
611 t1 = aliasTable_addSet (t1, key, value);
612 /*@=exposetrans@*/ /*@=dependenttrans@*/
613 }
614 else
615 {
616 sRefSet_free (t1->values[ind]);
617
618 /*@-dependenttrans@*/ /* okay, t2 is killed */
619 t1->values[ind] = value;
620 /*@=dependenttrans@*/
621 }
622 }
623 else
624 {
625 /*@-exposetrans@*/ /*@-dependenttrans@*/
626 sRefSet_free (value);
627 /*@=exposetrans@*/ /*@=dependenttrans@*/
628 }
629
630 } end_aliasTable_elements;
631
632 sfree (t2->keys);
633 sfree (t2->values);
634 sfree (t2);
635
636 return t1;
637}
638
639aliasTable
640aliasTable_levelUnion (/*@returned@*/ aliasTable t1, aliasTable t2, int level)
641{
642 if (aliasTable_isUndefined (t1))
643 {
644 if (aliasTable_isUndefined (t2))
645 {
646 return t1;
647 }
648 else
649 {
650 t1 = aliasTable_newEmpty ();
651 }
652 }
653 else
654 {
655 aliasTable_levelPrune (t1, level);
656 }
657
658 aliasTable_elements (t2, key, cvalue)
659 {
660 sRefSet value = sRefSet_newCopy (cvalue);
661
662 if (sRef_lexLevel (key) <= level)
663 {
664 sRefSet_levelPrune (value, level);
665
666 if (sRefSet_size (value) > 0)
667 {
668 int ind = aliasTable_lookupRefs (t1, key);
669
670 if (ind == ATINVALID)
671 {
672 t1 = aliasTable_addSet (t1, key, value);
673 }
674 else
675 {
676 t1->values[ind] = sRefSet_union (t1->values[ind], value);
677 sRefSet_free (value);
678 }
679 }
680 else
681 {
682 sRefSet_free (value);
683 }
684 }
685 else
686 {
687 sRefSet_free (value);
688 }
689 } end_aliasTable_elements;
690
691 return t1;
692}
693
694aliasTable aliasTable_levelUnionNew (aliasTable t1, aliasTable t2, int level)
695{
696 aliasTable ret = aliasTable_levelUnion (aliasTable_copy (t1), t2, level);
697
698 return ret;
699}
700
701/*@only@*/ cstring
702aliasTable_unparse (aliasTable s)
703{
704 cstring st = cstring_undefined;
705
706 if (aliasTable_isUndefined (s)) return (cstring_makeLiteral ("<NULL>"));
707
708 aliasTable_elements (s, key, value)
709 {
28bf4b0b 710 st = message ("%q\t%q -> %q\n", st, sRef_unparseFull (key),
711 sRefSet_unparseFull (value));
616915dd 712 } end_aliasTable_elements;
713
714 return st;
715}
716
717/*
718** bogus!
719*/
720
721void
722aliasTable_fixSrefs (aliasTable s)
723{
724 int i;
725
726 if (aliasTable_isUndefined (s)) return;
727
728 for (i = 0; i < s->nelements; i++)
729 {
730 sRef old = s->keys[i];
731
732 if (sRef_isLocalVar (old))
733 {
734 s->keys[i] = uentry_getSref (sRef_getUentry (old));
735 }
736
737 sRefSet_fixSrefs (s->values[i]);
738 }
739}
740
741void
742aliasTable_free (/*@only@*/ aliasTable s)
743{
744 int i;
745
746 if (aliasTable_isUndefined (s)) return;
747
748 for (i = 0; i < s->nelements; i++)
749 {
750 sRefSet_free (s->values[i]);
751 }
752
753 sfree (s->values);
754 sfree (s->keys);
755 sfree (s);
756}
757
758void
759aliasTable_checkGlobs (aliasTable t)
760{
761 aliasTable_elements (t, key, value)
762 {
763 sRef root = sRef_getRootBase (key);
764
765 if (sRef_isAliasCheckedGlobal (root))
766 {
767 sRefSet_realElements (value, sr)
768 {
769 root = sRef_getRootBase (sr);
770
771 if (((sRef_isAliasCheckedGlobal (root)
772 && !(sRef_similar (root, key)))
773 || sRef_isAnyParam (root))
774 && !sRef_isExposed (root))
775 {
776 if (sRef_isAliasCheckedGlobal (key))
777 {
778 if (!(sRef_isShared (key)
779 && sRef_isShared (root)))
780 {
781 voptgenerror
782 (FLG_GLOBALIAS,
783 message
784 ("Function returns with %q variable %q aliasing %q %q",
785 cstring_makeLiteral (sRef_isRealGlobal (key)
786 ? "global" : "file static"),
787 sRef_unparse (key),
788 cstring_makeLiteral (sRef_isAnyParam (root)
789 ? "parameter" : "global"),
790 sRef_unparse (sr)),
791 g_currentloc);
792 }
793 }
794
795 }
796 } end_sRefSet_realElements;
797 }
798 else if (sRef_isAnyParam (key) || sRef_isAnyParam (root))
799 {
800 sRefSet_realElements (value, sr)
801 {
802 root = sRef_getRootBase (sr);
803
804 if (sRef_isAliasCheckedGlobal (root)
805 && !sRef_isExposed (root)
806 && !sRef_isDead (key)
807 && !sRef_isShared (root))
808 {
809 voptgenerror
810 (FLG_GLOBALIAS,
811 message ("Function returns with parameter %q aliasing %q %q",
812 sRef_unparse (key),
813 cstring_makeLiteral (sRef_isRealGlobal (root)
814 ? "global" : "file static"),
815 sRef_unparse (sr)),
816 g_currentloc);
817 }
818 } end_sRefSet_realElements;
819 }
820 else
821 {
822 ;
823 }
824 } end_aliasTable_elements;
825}
826
6483a926 827# ifdef DEBUGSPLINT
616915dd 828
6483a926 829/*
830** For debugging only
831*/
832
833void aliasTable_checkValid (aliasTable t)
834{
835 aliasTable_elements (t, key, value)
836 {
02b84d4b 837 sRef_checkCompletelyReasonable (key);
616915dd 838
6483a926 839 sRefSet_elements (value, sr)
840 {
02b84d4b 841 sRef_checkCompletelyReasonable (sr);
6483a926 842 } end_sRefSet_elements ;
843 } end_aliasTable_elements ;
844}
845# endif
This page took 0.17309 seconds and 5 git commands to generate.