2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 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 splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
28 # include "splintMacros.nf"
31 /*@constant int stateClauseListBASESIZE;@*/
32 # define stateClauseListBASESIZE MIDBASESIZE
34 static /*@notnull@*/ stateClauseList
stateClauseList_new (void)
36 stateClauseList s
= (stateClauseList
) dmalloc (sizeof (*s
));
39 s
->nspace
= stateClauseListBASESIZE
;
40 s
->elements
= (stateClause
*)
41 dmalloc (sizeof (*s
->elements
) * stateClauseListBASESIZE
);
47 stateClauseList_grow (stateClauseList s
)
50 stateClause
*newelements
;
52 llassert (stateClauseList_isDefined (s
));
54 s
->nspace
+= stateClauseListBASESIZE
;
56 newelements
= (stateClause
*)
57 dmalloc (sizeof (*newelements
) * (s
->nelements
+ s
->nspace
));
59 for (i
= 0; i
< s
->nelements
; i
++)
61 newelements
[i
] = s
->elements
[i
];
65 s
->elements
= newelements
;
68 stateClauseList
stateClauseList_add (stateClauseList s
, stateClause el
)
70 DPRINTF (("Adding: %s", stateClause_unparse (el
)));
72 if (stateClauseList_isUndefined (s
))
74 s
= stateClauseList_new ();
78 stateClauseList_elements (s
, cl
)
80 if (stateClause_sameKind (cl
, el
))
84 message ("Multiple %q clauses for one function (ignoring second)",
85 stateClause_unparseKind (cl
)),
88 stateClause_free (el
);
91 } end_stateClauseList_elements
;
96 stateClauseList_grow (s
);
100 s
->elements
[s
->nelements
] = el
;
106 cstring
stateClauseList_unparse (stateClauseList s
)
108 cstring st
= cstring_undefined
;
111 if (stateClauseList_isDefined (s
))
113 for (i
= 0; i
< stateClauseList_size (s
); i
++)
117 st
= message ("%q;", stateClause_unparse (s
->elements
[i
]));
120 st
= message ("%q %q;", st
, stateClause_unparse (s
->elements
[i
]));
127 stateClauseList
stateClauseList_copy (stateClauseList s
)
129 if (stateClauseList_isDefined (s
))
131 stateClauseList t
= (stateClauseList
) dmalloc (sizeof (*t
));
134 t
->nelements
= s
->nelements
;
137 if (s
->nelements
> 0)
139 t
->elements
= (stateClause
*) dmalloc (sizeof (*t
->elements
) * t
->nelements
);
140 for (i
= 0; i
< s
->nelements
; i
++)
142 t
->elements
[i
] = stateClause_copy (s
->elements
[i
]);
154 return stateClauseList_undefined
;
159 stateClauseList_free (stateClauseList s
)
161 if (!stateClauseList_isUndefined (s
))
165 for (i
= 0; i
< s
->nelements
; i
++)
167 stateClause_free (s
->elements
[i
]);
175 cstring
stateClauseList_dump (stateClauseList s
)
177 cstring st
= cstring_undefined
;
179 if (stateClauseList_isUndefined (s
)) return st
;
181 stateClauseList_elements (s
, current
)
183 st
= message ("%q%q$", st
, stateClause_dump (current
));
184 } end_stateClauseList_elements
;
189 stateClauseList
stateClauseList_undump (char **s
)
192 stateClauseList pn
= stateClauseList_new ();
197 while (c
!= '#' && c
!= '@')
199 stateClause sc
= stateClause_undump (s
);
201 pn
= stateClauseList_add (pn
, sc
);
202 reader_checkChar (s
, '$');
211 int stateClauseList_compare (stateClauseList s1
, stateClauseList s2
)
213 if (stateClauseList_isUndefined (s1
)
214 && stateClauseList_isUndefined (s2
))
220 if (s1
- s2
> 0) /* evans 2001-08-21: was (int) s1 > (int) s2) */
230 # endif /* DEADCODE */
232 static /*@exposed@*/ sRefSet
233 stateClauseList_getClause (stateClauseList s
, stateClause k
)
235 stateClauseList_elements (s
, el
)
237 if (stateClause_matchKind (el
, k
))
239 return stateClause_getRefs (el
);
241 } end_stateClauseList_elements
;
243 return sRefSet_undefined
;
246 void stateClauseList_checkAll (uentry ue
)
248 stateClauseList clauses
= uentry_getStateClauseList (ue
);
249 sRef res
= uentry_getSref (ue
);
250 bool specialResult
= FALSE
;
252 DPRINTF (("Check state clauses: %s", uentry_unparseFull (ue
)));
254 stateClauseList_elements (clauses
, cl
)
256 bool isPre
= stateClause_isBeforeOnly (cl
);
258 if (stateClause_isGlobal (cl
))
264 sRefSet refs
= stateClause_getRefs (cl
);
266 sRefSet_allElements (refs
, el
)
268 sRef rb
= sRef_getRootBase (el
);
270 DPRINTF (("Check: %s", sRef_unparse (el
)));
272 if (sRef_isResult (rb
))
275 ** The result type is now know, need to set it:
278 if (ctype_isUnknown (sRef_getType (rb
)))
280 ctype utype
= uentry_getType (ue
);
281 llassert (ctype_isFunction (utype
));
283 sRef_setTypeFull (rb
, ctype_getReturnType (utype
));
284 DPRINTF (("el: %s", sRef_unparseFull (el
)));
288 if (stateClause_setsMetaState (cl
))
290 qual q
= stateClause_getMetaQual (cl
);
291 annotationInfo qa
= qual_getAnnotationInfo (q
);
293 if (!annotationInfo_matchesContextRef (qa
, el
))
296 (FLG_ANNOTATIONERROR
,
297 message ("Attribute annotation %s used on inappropriate reference %q in %q clause of %q: %q",
300 stateClause_unparseKind (cl
),
302 stateClause_unparse (cl
)),
303 uentry_whereLast (ue
)))
305 /* annotationInfo_showContextError (ainfo, ue); */
310 if (sRef_isResult (rb
))
316 message ("Function result is used in %q clause of %q "
317 "(%q applies to the state before function is "
318 "called, so should not use result): %q",
319 stateClause_unparseKind (cl
),
321 stateClause_unparseKind (cl
),
323 uentry_whereLast (ue
));
327 if (!sRef_isStateSpecial (res
))
329 DPRINTF (("Here we are: %s", sRef_unparseFull (res
)));
333 sstate pstate
= sRef_getDefState (res
);
335 if (!sRef_makeStateSpecial (res
))
339 message ("Function result is used in %q clause of %q "
340 "but was previously annotated with %s: %q",
341 stateClause_unparseKind (cl
),
343 sstate_unparse (pstate
),
345 uentry_whereLast (ue
)))
347 specialResult
= TRUE
;
353 DPRINTF (("Fixing result type! %s", sRef_unparseFull (el
)));
354 (void) sRef_fixResultType (el
, sRef_getType (res
), ue
);
357 else if (sRef_isParam (rb
))
359 DPRINTF (("Make special: %s", sRef_unparseFull (rb
)));
361 if (!sRef_makeStateSpecial (rb
))
363 if (fileloc_isXHFile (uentry_whereLast (ue
)))
365 ; /* Okay to override in .xh files */
367 else if (stateClause_isQual (cl
))
369 ; /* qual clauses don't interfere with definition state */
375 message ("Reference %q used in %q clause of %q, "
376 "but was previously annotated with %s: %q",
378 stateClause_unparseKind (cl
),
380 sstate_unparse (sRef_getDefState (res
)),
382 uentry_whereLast (ue
));
386 DPRINTF (("Made special: %s", sRef_unparseFull (rb
)));
388 else if (sRef_isInvalid (rb
))
390 /*@innercontinue@*/ continue;
395 /*@innercontinue@*/ continue;
398 if (stateClause_isMemoryAllocation (cl
))
400 if (!ctype_isVisiblySharable (sRef_getType (el
)))
403 (FLG_ANNOTATIONERROR
,
404 /*@-sefparams@*/ /* This is okay because its fresh storage. */
406 ("%q clauses includes %q of "
407 "non-dynamically allocated type %s",
408 cstring_capitalizeFree (stateClause_unparseKind (cl
)),
410 ctype_unparse (sRef_getType (el
))),
411 uentry_whereLast (ue
));
416 } end_sRefSet_allElements
;
418 } end_stateClauseList_elements
;
421 void stateClauseList_checkEqual (uentry old
, uentry unew
)
423 stateClauseList oldClauses
= uentry_getStateClauseList (old
);
424 stateClauseList newClauses
= uentry_getStateClauseList (unew
);
426 if (stateClauseList_isDefined (newClauses
))
428 stateClauseList_elements (newClauses
, cl
)
430 if (stateClause_isGlobal (cl
))
436 sRefSet sc
= stateClauseList_getClause (oldClauses
, cl
);
438 if (!sRefSet_equal (sc
, stateClause_getRefs (cl
)))
442 message ("Function %q %rdeclared with inconsistent %q clause: %q",
443 uentry_getName (old
),
444 uentry_isDeclared (old
),
445 stateClause_unparseKind (cl
),
446 sRefSet_unparsePlain (stateClause_getRefs (cl
))),
449 uentry_showWhereLastExtra (old
, sRefSet_unparsePlain (sc
));
453 } end_stateClauseList_elements
;
455 stateClauseList_elements (oldClauses
, cl
)
457 if (stateClause_isGlobal (cl
))
459 ; /* Don't handle globals for now */
463 sRefSet sc
= stateClauseList_getClause (newClauses
, cl
);
465 if (sRefSet_isUndefined (sc
) && !sRefSet_isEmpty (stateClause_getRefs (cl
)))
469 message ("Function %q %rdeclared without %q clause (either "
470 "use no special clauses in redeclaration, or "
471 "they must match exactly: %q",
472 uentry_getName (old
),
473 uentry_isDeclared (old
),
474 stateClause_unparseKind (cl
),
475 sRefSet_unparsePlain (stateClause_getRefs (cl
))),
478 uentry_showWhereLastExtra (old
, sRefSet_unparsePlain (sc
));
482 } end_stateClauseList_elements
;