]> andersk Git - splint.git/blob - src/aliasTable.c
58c3126d60c3e0a0e246d3e292b7973c7a4f2ee9
[splint.git] / src / aliasTable.c
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 University of Virginia,
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 **
20 ** For information on splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
23 */
24 /*
25 ** aliasTable.c
26 */
27
28 # include "splintMacros.nf"
29 # include "basic.h"
30
31 /*@constant int ATINVALID; @*/
32 # define ATINVALID -1
33
34 static sRefSet
35   aliasTable_canAliasAux (aliasTable p_s, sRef p_sr, int p_lim) /*@*/ ;
36 static sRefSet
37   aliasTable_aliasedByLimit (aliasTable p_s, sRef p_sr, int p_lim) /*@*/ ;
38 static sRefSet 
39   aliasTable_aliasedByAux (aliasTable p_s, sRef p_sr, int p_lim) /*@*/ ;
40
41 aliasTable
42 aliasTable_new ()
43 {
44   return (aliasTable_undefined);
45 }
46
47 static /*@only@*/ /*@notnull@*/ aliasTable
48 aliasTable_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
60 static void
61 aliasTable_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
88 static 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
108 aliasTable
109 aliasTable_addMustAlias (/*@returned@*/ aliasTable s,
110                          /*@exposed@*/ sRef sr,
111                          /*@exposed@*/ sRef al)
112 {
113   int ind;
114   sRefSet ss;
115   
116   llassert (NOALIAS (sr, al));
117   
118   DPRINTF (("Adding alias: %s / %s", sRef_unparseFull (sr),
119             sRef_unparseFull (al)));
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); 
132   DPRINTF (("Previous aliases: %s", sRefSet_unparse (ss)));
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]); 
152   DPRINTF (("New aliases: %s", sRefSet_unparse (s->values[ind])));
153
154   sRefSet_free (ss);
155   return s;
156 }
157
158 static 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
198 static void aliasTable_clearAliasesAux (/*@notnull@*/ aliasTable p_s, sRef p_sr)
199    /*@modifies p_s@*/ ;
200
201 void 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
241 static
242 void 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
265 static /*@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 "
281                       "%d indirections, or there is a bug in Splint.",
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
354 static /*@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
405 static /*@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
424 static /*@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 "
438                       "%d indirections, or there is a bug in Splint.",
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             }
490           
491           sRefSet_free (tmp);
492           return ret;
493         }
494       
495       if (ind == ATINVALID) return sRefSet_undefined;      
496       
497       return sRefSet_newCopy (s->values[ind]);
498     }
499 }
500
501 aliasTable 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
527 static void
528 aliasTable_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
582 aliasTable 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
639 aliasTable 
640 aliasTable_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
694 aliasTable 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
702 aliasTable_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      {
710        st = message ("%q\t%q -> %q\n", st, sRef_unparseFull (key), 
711                      sRefSet_unparseFull (value));
712      } end_aliasTable_elements;
713
714    return st;
715 }
716
717 /*
718 ** bogus!
719 */
720
721 void
722 aliasTable_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
741 void
742 aliasTable_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
758 void 
759 aliasTable_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
827 # ifdef DEBUGSPLINT
828
829 /*
830 ** For debugging only
831 */
832
833 void aliasTable_checkValid (aliasTable t)
834 {
835   aliasTable_elements (t, key, value)
836     {
837       sRef_checkCompletelyReasonable (key);
838
839       sRefSet_elements (value, sr) 
840         {
841           sRef_checkCompletelyReasonable (sr);
842         } end_sRefSet_elements ;
843     } end_aliasTable_elements ;
844 }
845 # endif
This page took 0.606627 seconds and 3 git commands to generate.