]> andersk Git - splint.git/blame - src/exprChecks.c
Changed to used /\ and requires instead of bufferConstraint
[splint.git] / src / exprChecks.c
CommitLineData
616915dd 1/*
2** LCLint - annotation-assisted static program checker
3** Copyright (C) 1994-2000 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 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
23*/
24/*
25** exprChecks.c
26*/
27
28# include "lclintMacros.nf"
29# include "basic.h"
30# include "cgrammar.h"
31# include "cgrammar_tokens.h"
32# include "aliasChecks.h"
33# include "exprChecks.h"
34
35/*
36** for now, allow exprChecks to access exprNode.
37** may remove this in future
38*/
39
40/*@access exprNode@*/
41
42static bool checkCallModifyAux (sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
43static bool checkModifyValAux (sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
44static bool checkModifyAux (sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
45static void checkSafeReturnExpr (/*@notnull@*/ exprNode p_e);
46
47/*
48** called at end of expression statement
49**
50** of e->kind is not an assign, empty, body or modop
51** verify the the value is void
52**
53*/
54
55void
56exprNode_checkStatement (exprNode e)
57{
58 bool hasError = FALSE;
59
60 if (!exprNode_isError (e))
61 {
62 exprKind ek = e->kind;
63
64 if (ek == XPR_CALL && !(ctype_isRealVoid (e->typ)))
65 {
66 if (ctype_isKnown (e->typ))
67 {
68 if (ctype_isManifestBool (ctype_realishType (e->typ)))
69 {
70 hasError = optgenerror
71 (FLG_RETVALBOOL,
72 message ("Return value (type %t) ignored: %s",
73 e->typ,
74 exprNode_unparseFirst (e)),
75 e->loc);
76 }
77 else if (ctype_isDirectInt (e->typ))
78 {
79 hasError = optgenerror
80 (FLG_RETVALINT,
81 message ("Return value (type %t) ignored: %s",
82 e->typ,
83 exprNode_unparseFirst (e)),
84 e->loc);
85 }
86 else
87 {
88 hasError = optgenerror
89 (FLG_RETVALOTHER,
90 message ("Return value (type %t) ignored: %s",
91 e->typ,
92 exprNode_unparseFirst (e)),
93 e->loc);
94 }
95 }
96 }
97
98 if (!hasError && !(exprNode_mayEscape (e))
99 && !(e->canBreak)) /* control changes are effects too! */
100 {
101 if (sRefSet_hasRealElement (e->sets)
102 || sRefSet_hasRealElement (e->msets))
103 {
104 ; /* okay */
105 }
106 else
107 {
108 if (sRefSet_isEmpty (e->sets) && sRefSet_isEmpty (e->msets))
109 {
110 voptgenerror
111 (FLG_NOEFFECT,
112 message ("Statement has no effect: %s",
113 exprNode_unparseFirst (e)),
114 e->loc);
115 }
116 else
117 {
118 if (context_maybeSet (FLG_NOEFFECTUNCON))
119 {
120 if (sRefSet_hasUnconstrained (e->sets))
121 {
122 voptgenerror
123 (FLG_NOEFFECTUNCON,
124 message ("Statement has no effect (possible "
125 "undected modification through "
126 "call to %q): %s",
127 sRefSet_unparseUnconstrained (e->sets),
128 exprNode_unparseFirst (e)),
129 e->loc);
130 }
131 else if (sRefSet_hasUnconstrained (e->msets))
132 {
133 voptgenerror
134 (FLG_NOEFFECTUNCON,
135 message ("Statement has no effect (possible "
136 "undected modification through "
137 "call to %q): %s",
138 sRefSet_unparseUnconstrained (e->msets),
139 exprNode_unparseFirst (e)),
140 e->loc);
141 }
142 else
143 {
144 ; /* statement has unknown modification */
145 }
146 }
147 }
148 }
149 }
150 }
151}
152
153static bool
154checkRepExposed (sRef base, /*@notnull@*/ exprNode e, sRef alias,
155 /*@unused@*/ exprNode unused)
156{
157 ctype btype;
158
159 if (sRef_isInvalid (alias) || sRef_sameName (base, alias))
160 {
161 btype = sRef_getType (base);
162
163 if (ctype_isAbstract (btype) && ctype_isVisiblySharable (e->typ))
164 {
165 voptgenerror (FLG_RETEXPOSE,
166 message ("Return value exposes rep of %s: %s",
167 ctype_unparse (btype),
168 exprNode_unparse (e)),
169 e->loc);
170 return TRUE;
171 }
172 }
173 else
174 {
175 sRef rbase = sRef_getRootBase (base);
176 btype = sRef_getType (rbase);
177
178 if (ctype_isAbstract (btype) && ctype_isVisiblySharable (e->typ))
179 {
180 voptgenerror
181 (FLG_RETEXPOSE,
182 message ("Return value may expose rep of %s through alias %q: %s",
183 ctype_unparse (btype),
184 sRef_unparse (rbase),
185 exprNode_unparse (e)),
186 e->loc);
187 return TRUE;
188 }
189 }
190
191 return FALSE;
192}
193
194static bool
195checkRefGlobParam (sRef base, /*@notnull@*/ exprNode e,
196 sRef alias, /*@unused@*/ exprNode unused)
197{
198 if (sRef_isInvalid (alias) || sRef_sameName (base, alias))
199 {
200 ctype ct = e->typ;
201
202 if (ctype_isUnknown (ct))
203 {
204 ct = sRef_getType (base);
205 }
206
207 if (ctype_isVisiblySharable (ct))
208 {
209 if (sRef_isGlobal (base))
210 {
211 voptgenerror
212 (FLG_RETALIAS,
213 message ("Function returns reference to global %q: %s",
214 sRef_unparse (base),
215 exprNode_unparse (e)),
216 e->loc);
217
218 return TRUE;
219 }
220 else if (sRef_isAnyParam (base))
221 {
222 uentryList params = context_getParams ();
223 int paramno = sRef_getParam (base);
224
225 if (paramno < uentryList_size (params))
226 {
227 uentry arg = uentryList_getN (params, paramno);
228 sRef ref = uentry_getSref (arg);
229
230 if (uentry_isReturned (arg)
231 || sRef_isOnly (ref)
232 || sRef_isExposed (ref)
233 || sRef_isRefCounted (ref))
234 {
235 ; /* okay */
236 }
237 else
238 {
239 voptgenerror
240 (FLG_RETALIAS,
241 message ("Function returns reference to parameter %q: %s",
242 sRef_unparse (base),
243 exprNode_unparse (e)),
244 e->loc);
245 }
246 }
247 else
248 {
249 llbuglit ("ret alias: bad paramno");
250 }
251
252 return TRUE;
253 }
254 else
255 {
256 return FALSE;
257 }
258 }
259 }
260 else
261 {
262 if (ctype_isVisiblySharable (e->typ))
263 {
264 if (sRef_isGlobal (base))
265 {
266 voptgenerror
267 (FLG_RETALIAS,
268 message ("Function may return reference to global %q through alias %q: %s",
269 sRef_unparse (alias),
270 sRef_unparse (base),
271 exprNode_unparse (e)),
272 e->loc);
273 return TRUE;
274 }
275 else if (sRef_isAnyParam (base) && !(sRef_isOnly (base)))
276 {
277 uentryList params = context_getParams ();
278 int paramno = sRef_getParam (base);
279
280 if (paramno < uentryList_size (params))
281 {
282 uentry arg = uentryList_getN (params, paramno);
283
284 if (!uentry_isReturned (arg))
285 {
286 voptgenerror
287 (FLG_RETALIAS,
288 message
289 ("Function may return reference to parameter %q through alias %q: %s",
290 sRef_unparse (base),
291 sRef_unparse (alias),
292 exprNode_unparse (e)),
293 e->loc);
294
295 return TRUE;
296 }
297 }
298 else
299 {
300 voptgenerror
301 (FLG_RETALIAS,
302 message
303 ("Function may return reference to parameter %q through alias %q: %s",
304 sRef_unparse (base),
305 sRef_unparse (alias),
306 exprNode_unparse (e)),
307 e->loc);
308
309 return TRUE;
310 }
311 }
312 else
313 {
314 return FALSE;
315 }
316 }
317 }
318 return FALSE;
319}
320
321
322void
323exprNode_checkModify (exprNode e, exprNode err)
324{
325 llassert (exprNode_isDefined (e));
326
327 DPRINTF (("Check modify: %s", exprNode_unparse (e)));
328
329 if (sRef_isValid (e->sref))
330 {
331 sRef_aliasCheckPred (checkModifyAux, sRef_isReference, e->sref, e, err);
332 }
333}
334
335void
336exprNode_checkModifyVal (exprNode e, exprNode err)
337{
338 llassert (exprNode_isDefined (e));
339
340 DPRINTF (("Check modify val: %s", exprNode_unparse (e)));
341
342 if (sRef_isValid (e->sref))
343 {
344 sRef_aliasCheckPred (checkModifyValAux, sRef_isReference, e->sref, e, err);
345 }
346}
347
348void
349exprChecks_checkNullReturn (fileloc loc)
350{
351 if (!context_inRealFunction ())
352 {
353 /*
354 llmsg ("exprChecks_checkNullReturnExpr: not in function context");
355 */
356 return;
357 }
358 else
359 {
360 if (ctype_isFunction (context_currentFunctionType ()))
361 {
362 ctype tr = ctype_returnValue (context_currentFunctionType ());
363
364 if (!ctype_isFirstVoid (tr))
365 {
366 if (ctype_isUnknown (tr))
367 {
368 voptgenerror
369 (FLG_CONTROL,
370 cstring_makeLiteral ("Empty return in function declared to implicitly return int"),
371 loc);
372 }
373 else
374 {
375 voptgenerror (FLG_CONTROL,
376 message ("Empty return in function declared to return %t", tr),
377 loc);
378 }
379 }
380 }
381 }
382}
383
384void
385exprNode_checkReturn (exprNode e)
386{
387 if (!exprNode_isError (e))
388 {
389 if (!context_inRealFunction ())
390 {
391 if (context_inMacro ())
392 {
393 llerror (FLG_CONTROL,
394 message ("Macro %s uses return (not functional)",
395 context_inFunctionName ()));
396 }
397 else
398 {
399 /*
400 llbuglit ("exprNode_checkReturn: not in function context");
401 */
402 }
403 }
404 else
405 {
406 if (ctype_isFunction (context_currentFunctionType ()))
407 {
408 checkSafeReturnExpr (e);
409 }
410 else
411 {
412 ;
413 }
414 }
415 }
416}
417
418void
419exprNode_checkPred (cstring c, exprNode e)
420{
421 ctype ct;
422
423 if (exprNode_isError (e))
424 return;
425
426 ct = exprNode_getType (e);
427
428 if (exprNode_isAssign (e))
429 {
430 voptgenerror
431 (FLG_PREDASSIGN,
432 message ("Test expression for %s is assignment expression: %s",
433 c, exprNode_unparse (e)),
434 e->loc);
435 }
436
437 if (ctype_isRealBool (ct))
438 {
439 ;
440 }
441 else if (ctype_isRealPointer (ct))
442 {
443 voptgenerror
444 (FLG_PREDBOOLPTR,
445 message ("Test expression for %s not %s, type %t: %s", c,
446 context_printBoolName (),
447 ct, exprNode_unparse (e)),
448 e->loc);
449 }
450 else if (ctype_isRealInt (ct))
451 {
452 voptgenerror
453 (FLG_PREDBOOLINT,
454 message ("Test expression for %s not %s, type %t: %s", c,
455 context_printBoolName (), ct, exprNode_unparse (e)),
456 e->loc);
457 }
458 else
459 {
460 voptgenerror
461 (FLG_PREDBOOLOTHERS,
462 message ("Test expression for %s not %s, type %t: %s", c,
463 context_printBoolName (), ct, exprNode_unparse (e)),
464 e->loc);
465 }
466}
467
468void
469exprChecks_checkUsedGlobs (globSet decl, globSet used)
470{
471 fileloc fl = uentry_whereSpecified (context_getHeader ());
472
473 if (fileloc_isUndefined (fl))
474 {
475 fl = uentry_whereDeclared (context_getHeader ());
476 }
477
478 globSet_allElements (decl, el)
479 {
480 if (!globSet_member (used, el))
481 {
482 if (sRef_isSpecInternalState (el)
483 || sRef_isNothing (el))
484 {
485 ;
486 }
487 else
488 {
489 cstring sname = sRef_unparse (el);
490
491 if (fileloc_isLib (fl))
492 {
493 voptgenerror (FLG_USEALLGLOBS,
494 message ("Global %s listed (%q) but not used",
495 sname, fileloc_unparse (fl)),
496 g_currentloc);
497 }
498 else
499 {
500 voptgenerror (FLG_USEALLGLOBS,
501 message ("Global %s listed but not used", sname),
502 fl);
503 }
504
505 cstring_free (sname);
506 }
507 }
508 } end_globSet_allElements;
509}
510
511void
512exprNode_checkAllMods (sRefSet mods, uentry ue)
513{
514 bool realParams = FALSE;
515 uentry le = context_getHeader ();
516 fileloc fl = uentry_whereSpecified (le);
517 uentryList specParamNames = uentryList_undefined;
518 uentryList paramNames = context_getParams ();
519
520 if (uentry_isFunction (le))
521 {
522 specParamNames = uentry_getParams (le);
523
524 if (uentryList_isUndefined (specParamNames))
525 {
526 ; /* unknown params */
527 }
528 else if (uentryList_size (paramNames) != uentryList_size (specParamNames))
529 {
530 llbug
531 (message ("exprNode_checkAllMods: parameter lists have different sizes: "
532 "%q (%d) / %q (%d)",
533 uentryList_unparse (paramNames),
534 uentryList_size (paramNames),
535 uentryList_unparse (specParamNames),
536 uentryList_size (specParamNames)));
537 }
538 else if (uentryList_size (paramNames) > 0
539 && !uentry_hasRealName (uentryList_getN (specParamNames, 0)))
540 {
541 /* loaded from a library */
542 }
543 else
544 {
545 realParams = TRUE;
546 }
547 }
548
549 sRefSet_allElements (mods, sr)
550 {
551 if (sRef_isNothing (sr) || sRef_isSpecState (sr))
552 {
553 ; /* should report on anything? */
554 }
555 else if (sRef_isInternalState (sr))
556 {
557 if (!sRef_isModified (sr))
558 {
559 if (sRefSet_hasStatic (mods))
560 {
561 ; /* okay */
562 }
563 else
564 {
565 if (optgenerror
566 (FLG_MUSTMOD,
567 message
568 ("Function %s specified to modify internal state "
569 "but no internal state is modified",
570 uentry_rawName (ue)),
571 uentry_whereLast (ue)))
572 {
573 uentry_showWhereSpecified (le);
574 }
575 }
576 }
577 }
578 else
579 {
580 if (!sRef_isModified (sr))
581 {
582 cstring sname = realParams ? sRef_unparse (sr) : sRef_unparse (sr);
583
584 if (fileloc_isLib (fl) && !realParams)
585 {
586 voptgenerror
587 (FLG_MUSTMOD,
588 message ("Suspect object listed (%q) in modifies "
589 "clause of %s not modified: %s",
590 fileloc_unparse (fl),
591 uentry_rawName (ue),
592 sname),
593 uentry_whereLast (ue));
594 }
595 else
596 {
597 if (optgenerror
598 (FLG_MUSTMOD,
599 message ("Suspect object listed in modifies of %s "
600 "not modified: %s",
601 uentry_rawName (ue),
602 sname),
603 uentry_whereLast (ue)))
604 {
605 uentry_showWhereSpecified (le);
606 }
607 }
608 cstring_free (sname);
609 }
610 }
611 } end_sRefSet_allElements;
612}
613
614void exprNode_checkMacroBody (/*@only@*/ exprNode e)
615{
616 if (!exprNode_isError (e))
617 {
618 uentry hdr;
619
620 if (!(context_inFunctionLike () || context_inMacroConstant ()
621 || context_inMacroUnknown ()))
622 {
623 llcontbug
624 (message
625 ("exprNode_checkMacroBody: not in macro function or constant: %q",
626 context_unparse ()));
627 exprNode_free (e);
628 return;
629 }
630
631 hdr = context_getHeader ();
632
633 if (e->kind == XPR_STMTLIST || e->kind == XPR_BODY)
634 {
635 voptgenerror
636 (FLG_MACROSTMT,
637 message
638 ("Macro %q definition is statement list (recommend "
639 "do { ... } while (0) constuction to ensure multiple "
640 "statement macro is syntactic function)",
641 uentry_getName (hdr)),
642 fileloc_isDefined (e->loc) ? e->loc : g_currentloc);
643 }
644
645 if (context_inMacroConstant ())
646 {
647 ctype t = uentry_getType (hdr);
648
649 uentry_setDefined (hdr, e->loc);
650
651 if (!(exprNode_matchType (t, e)))
652 {
653 cstring uname = uentry_getName (hdr);
654
655 if (cstring_equal (uname, context_getTrueName ())
656 || cstring_equal (uname, context_getFalseName ()))
657 {
658 /*
659 ** We need to do something special to allow FALSE and TRUE
660 ** to be defined without reporting errors. This is a tad
661 ** bogus, but otherwise lots of things would break.
662 */
663
664
665 llassert (ctype_isManifestBool (t));
666 /* Should also check type of e is a reasonable (?) bool type. */
667 }
668 else
669 {
670 if (optgenerror
671 (FLG_INCONDEFS,
672 message
673 ("Constant %q specified as %s, but defined as %s: %s",
674 uentry_getName (hdr),
675 ctype_unparse (t),
676 ctype_unparse (e->typ),
677 exprNode_unparse (e)),
678 e->loc))
679 {
680 uentry_showWhereSpecified (hdr);
681 }
682 }
683
684 cstring_free (uname);
685 }
686 else
687 {
688 if (context_maybeSet (FLG_NULLSTATE)
689 && ctype_isUA(t)
690 && ctype_isRealPointer (t)
691 && exprNode_isNullValue (e))
692 {
693 uentry ue = usymtab_getTypeEntry (ctype_typeId (t));
694 sRef sr = uentry_getSref (ue);
695
696 if (!sRef_possiblyNull (sr))
697 {
698 vgenhinterror
699 (FLG_NULLSTATE,
700 message ("Constant %q of non-null type %s defined "
701 "as null: %s",
702 uentry_getName (hdr), ctype_unparse (t),
703 exprNode_unparse (e)),
704 message ("If %s can be null, add a /*@null@*/ "
705 "qualifer to its typedef.",
706 ctype_unparse (t)),
707 e->loc);
708 }
709
710 uentry_mergeConstantValue (hdr, e->val);
711 e->val = multiVal_undefined;
712 }
713 }
714 }
715 else if (context_inMacroFunction () || context_inMacroUnknown ())
716 {
717 ctype rettype = context_getRetType ();
718
719 if (context_isMacroMissingParams ())
720 {
721 llassert (context_inMacroFunction ());
722
723 /*
724 ** # define newname oldname
725 **
726 ** newname is a function
727 ** specification of oldname should match
728 ** specification of newname.
729 */
730
731 if (!ctype_isFunction (e->typ))
732 {
733 voptgenerror
734 (FLG_INCONDEFS,
735 message ("Function %s defined by unparameterized "
736 "macro not corresponding to function",
737 context_inFunctionName ()),
738 e->loc);
739 }
740 else
741 {
742 uentry ue = exprNode_getUentry (e);
743
744 if (uentry_isValid (ue))
745 {
746 /*
747 ** Okay, for now --- should check for consistency
748 */
749 /*
750 ** uentry oldue = usymtab_lookup (cfname);
751 */
752
753 /* check var conformance here! */
754 }
755 else
756 {
757 voptgenerror
758 (FLG_INCONDEFS,
759 message ("Function %s defined by unparameterized "
760 "macro not corresponding to function",
761 context_inFunctionName ()),
762 e->loc);
763 }
764
765 e->typ = ctype_returnValue (e->typ);
766 rettype = e->typ; /* avoid aditional errors */
767 }
768 }
769
770 if (ctype_isVoid (rettype) || ctype_isUnknown (rettype))
771 {
772 ; /* don't complain when void macros have values */
773 }
774 else if (!exprNode_matchType (rettype, e))
775 {
776 if (optgenerror
777 (FLG_INCONDEFS,
778 message ("Function %q specified to return %s, "
779 "implemented as macro having type %s: %s",
780 uentry_getName (hdr),
781 ctype_unparse (rettype), ctype_unparse (e->typ),
782 exprNode_unparse (e)),
783 e->loc))
784 {
785 uentry_showWhereSpecified (hdr);
786 }
787 }
788 else
789 {
790 switch (e->kind)
791 {
792 /* these expressions have values: */
793 case XPR_PARENS: case XPR_ASSIGN:
794 case XPR_EMPTY: case XPR_VAR:
795 case XPR_OP: case XPR_POSTOP:
796 case XPR_PREOP: case XPR_CALL:
797 case XPR_SIZEOFT: case XPR_SIZEOF:
798 case XPR_ALIGNOFT: case XPR_ALIGNOF:
799 case XPR_CAST: case XPR_FETCH:
800 case XPR_COMMA: case XPR_COND:
801 case XPR_ARROW: case XPR_CONST:
802 case XPR_STRINGLITERAL: case XPR_NUMLIT:
803 case XPR_FACCESS: case XPR_OFFSETOF:
804
805 checkReturnTransfer (e, hdr);
806 break;
807
808 /* these expressions don't */
809 case XPR_LABEL:
810 case XPR_VAARG: case XPR_ITER:
811 case XPR_FOR: case XPR_FORPRED:
812 case XPR_GOTO: case XPR_CONTINUE:
813 case XPR_BREAK: case XPR_RETURN:
814 case XPR_NULLRETURN: case XPR_IF:
815 case XPR_IFELSE: case XPR_DOWHILE:
816 case XPR_WHILE: case XPR_STMT:
817 case XPR_STMTLIST: case XPR_SWITCH:
818 case XPR_INIT: case XPR_BODY:
819 case XPR_NODE: case XPR_ITERCALL:
820 case XPR_TOK: case XPR_CASE:
821 case XPR_FTCASE: case XPR_FTDEFAULT:
822 case XPR_DEFAULT: case XPR_WHILEPRED:
823 case XPR_BLOCK: case XPR_INITBLOCK:
824 if (optgenerror
825 (FLG_INCONDEFS,
826 message ("Function %q specified to return %s, "
827 "implemented as macro with no result: %s",
828 uentry_getName (hdr),
829 ctype_unparse (rettype),
830 exprNode_unparse (e)),
831 e->loc))
832 {
833 uentry_showWhereSpecified (hdr);
834 }
835 }
836 }
837
838 usymtab_checkFinalScope (FALSE);
839 }
840 else
841 {
842 llbug (message ("exprNode_checkMacroBody: not in macro function: %q", context_unparse ()));
843 }
844
845 exprNode_free (e);
846 }
847
848 context_exitFunction ();
849 return;
850}
851
852void exprNode_checkFunctionBody (exprNode body)
853{
854 if (!exprNode_isError (body))
855 {
856 bool noret = context_getFlag (FLG_NORETURN);
857 bool checkret = exprNode_mustEscape (body);
858
859 if (!checkret
860 && noret
861 && !exprNode_errorEscape (body)
862 && context_inRealFunction ()
863 && ctype_isFunction (context_currentFunctionType ()))
864 {
865 ctype tr = ctype_returnValue (context_currentFunctionType ());
866
867 if (!ctype_isFirstVoid (tr))
868 {
869 if (ctype_isUnknown (tr))
870 {
871 voptgenerror
872 (FLG_NORETURN,
873 cstring_makeLiteral ("Path with no return in function declared to implicity return int"),
874 g_currentloc);
875 }
876 else
877 {
878 voptgenerror
879 (FLG_NORETURN,
880 message ("Path with no return in function declared to return %t",
881 tr),
882 g_currentloc);
883 }
884 }
885 }
886
4ab867d6 887 /*@i44*/ /* drl added call*/
888 // exprNode_checkFunction (context_getHeader (), body);
616915dd 889
890 if (!checkret)
891 {
892 context_returnFunction ();
893 }
894 }
895}
896/*drl modified */
897
470b7798 898extern constraintList implicitFcnConstraints;
899
bb25bea6 900void exprNode_checkFunction (/*@unused@*/ uentry ue, exprNode body)
616915dd 901{
902 constraintList c, t;
9280addf 903 constraintList c2, fix;
616915dd 904
9280addf 905 // return;
90bc41f7 906
907 // context_setFlag(FLG_ORCONSTRAINT, TRUE);
bb25bea6 908 context_enterInnerContext ();
909
616915dd 910 exprNode_generateConstraints (body);
911
912 c = uentry_getFcnPreconditions (ue);
913 DPRINTF(("function constraints\n"));
914 DPRINTF (("\n\n\n\n\n\n\n"));
915
616915dd 916
917 if (c)
918 {
84c9ffbf 919
616915dd 920 DPRINTF ( (message ("Function preconditions are %s \n\n\n\n\n", constraintList_printDetailed (c) ) ) );
921
bb25bea6 922 body->requiresConstraints = reflectChangesFreePre (body->requiresConstraints, c);
923
9280addf 924 c2 = constraintList_copy (c);
925 fix = constraintList_makeFixedArrayConstraints (body->uses);
bb25bea6 926 c2 = reflectChangesFreePre (c2, fix);
927 constraintList_free(fix);
90bc41f7 928 if ( context_getFlag (FLG_ORCONSTRAINT) )
929 {
bb25bea6 930 t = reflectChangesOr (body->requiresConstraints, c2 );
90bc41f7 931 }
932 else
933 {
bb25bea6 934 t = reflectChanges (body->requiresConstraints, c2);
90bc41f7 935 }
bb25bea6 936
937 constraintList_free(body->requiresConstraints);
470b7798 938 DPRINTF ( (message ("The body has the required constraints: %s", constraintList_printDetailed (t) ) ) );
616915dd 939
bb25bea6 940 body->requiresConstraints = t;
941
942 t = constraintList_mergeEnsures (c, body->ensuresConstraints);
943 constraintList_free(body->ensuresConstraints);
944
945 body->ensuresConstraints = t;
946
947 DPRINTF ( (message ("The body has the ensures constraints: %s", constraintList_printDetailed (t) ) ) );
948 constraintList_free(c2);
616915dd 949 }
bb25bea6 950
616915dd 951 if (c)
952 {
953 DPRINTF((message ("The Function %s has the preconditions %s", uentry_unparse(ue), constraintList_printDetailed(c) ) ) );
954 }
955 else
956 {
957 DPRINTF((message ("The Function %s has no preconditions", uentry_unparse(ue) ) ) );
958 }
959
470b7798 960 if ( implicitFcnConstraints)
961 {
962 if (context_getFlag (FLG_IMPLICTCONSTRAINT) )
963 {
bb25bea6 964 body->requiresConstraints = reflectChangesFreePre (body->requiresConstraints, implicitFcnConstraints );
470b7798 965 }
966 }
967
616915dd 968 constraintList_printError(body->requiresConstraints, g_currentloc);
969 constraintList_printError(body->ensuresConstraints, g_currentloc);
970
971 // ConPrint (message ("Unable to resolve function constraints:\n%s", constraintList_printDetailed(body->requiresConstraints) ), g_currentloc);
972
973 // ConPrint (message ("LCLint has found function post conditions:\n%s", constraintList_printDetailed(body->ensuresConstraints) ), g_currentloc);
974
975 // printf ("The required constraints are:\n%s", constraintList_printDetailed(body->requiresConstraints) );
976 // printf ("The ensures constraints are:\n%s", constraintList_printDetailed(body->ensuresConstraints) );
977
bb25bea6 978 if (c)
979 constraintList_free(c);
4ab867d6 980
981 context_exitInnerPlain();
982
bb25bea6 983 /*is it okay not to free this?*/
4ab867d6 984 exprNode_free (body);
616915dd 985}
986
987void exprChecks_checkEmptyMacroBody (void)
988{
989 uentry hdr;
990
991 if (!(context_inFunctionLike () || context_inMacroConstant ()
992 || context_inMacroUnknown ()))
993 {
994 llcontbug
995 (message ("exprNode_checkEmptyMacroBody: not in macro function or constant: %q",
996 context_unparse ()));
997 return;
998 }
999
1000 hdr = context_getHeader ();
1001
1002 beginLine ();
1003
1004 if (uentry_isFunction (hdr))
1005 {
1006 voptgenerror
1007 (FLG_MACROEMPTY,
1008 message
1009 ("Macro definition for %q is empty", uentry_getName (hdr)),
1010 g_currentloc);
1011
1012 usymtab_checkFinalScope (FALSE);
1013 }
1014
1015 context_exitFunction ();
1016 return;
1017}
1018
1019void exprNode_checkIterBody (/*@only@*/ exprNode body)
1020{
1021 context_exitAllClauses ();
1022
1023 context_exitFunction ();
1024 exprNode_free (body);
1025}
1026
1027void exprNode_checkIterEnd (/*@only@*/ exprNode body)
1028{
1029 context_exitAllClauses ();
1030 context_exitFunction ();
1031 exprNode_free (body);
1032}
1033
1034static
1035bool checkModifyAuxAux (sRef s, exprNode f, sRef alias, exprNode err)
1036{
1037 bool hasMods = context_hasMods ();
1038 flagcode errCode = hasMods ? FLG_MODIFIES : FLG_MODNOMODS;
1039
1040 if (exprNode_isDefined (f))
1041 {
1042 f->sets = sRefSet_insert (f->sets, s);
1043 }
1044
1045 if (context_getFlag (FLG_MODIFIES)
1046 && (hasMods || context_getFlag (FLG_MODNOMODS)))
1047 {
1048 sRefSet mods = context_modList ();
1049
1050 if (!sRef_canModify (s, mods))
1051 {
1052 sRef rb = sRef_getRootBase (s);
1053
1054
1055 if (sRef_isGlobal (rb))
1056 {
1057 if (!context_checkGlobMod (rb))
1058 {
1059 return FALSE;
1060 }
1061 }
1062
1063 if (sRef_isInvalid (alias) || sRef_sameName (s, alias))
1064 {
1065 if (sRef_isLocalVar (sRef_getRootBase (s)))
1066 {
1067 voptgenerror
1068 (errCode,
1069 message
1070 ("Undocumented modification of internal state (%q): %s",
1071 sRef_unparse (s), exprNode_unparse (err)),
1072 exprNode_isDefined (f) ? f->loc : g_currentloc);
1073 }
1074 else
1075 {
1076 if (sRef_isSystemState (s))
1077 {
1078 if (errCode == FLG_MODNOMODS)
1079 {
1080 if (context_getFlag (FLG_MODNOMODS))
1081 {
1082 errCode = FLG_MODFILESYSTEM;
1083 }
1084 }
1085 else
1086 {
1087 errCode = FLG_MODFILESYSTEM;
1088 }
1089 }
1090
1091 voptgenerror
1092 (errCode,
1093 message ("Undocumented modification of %q: %s",
1094 sRef_unparse (s), exprNode_unparse (err)),
1095 exprNode_isDefined (f) ? f->loc : g_currentloc);
1096 }
1097
1098 return TRUE;
1099 }
1100 else
1101 {
1102 if (sRef_isReference (s) && !sRef_isAddress (alias))
1103 {
1104 voptgenerror
1105 (errCode,
1106 message
1107 ("Possible undocumented modification of %q through alias %q: %s",
1108 sRef_unparse (s),
1109 sRef_unparse (alias),
1110 exprNode_unparse (err)),
1111 exprNode_isDefined (f) ? f->loc : g_currentloc);
1112 return TRUE;
1113 }
1114 }
1115 }
1116 }
1117 else
1118 {
1119 if (context_maybeSet (FLG_MUSTMOD))
1120 {
1121 (void) sRef_canModify (s, context_modList ());
1122 }
1123
1124 if (sRef_isRefsField (s))
1125 {
1126 sRef_setModified (s);
1127 }
1128 }
1129
1130 return FALSE;
1131}
1132
1133static
1134bool checkModifyAux (sRef s, exprNode f, sRef alias, exprNode err)
1135{
1136 DPRINTF (("Check modify aux: %s", sRef_unparseFull (s)));
1137
1138 if (sRef_isReference (s) && sRef_isObserver (s)
1139 && context_maybeSet (FLG_MODOBSERVER))
1140 {
1141 cstring sname;
1142
1143 if (sRef_isPointer (s))
1144 {
1145 sRef base = sRef_getBase (s);
1146 sname = sRef_unparse (base);
1147 }
1148 else
1149 {
1150 if (sRef_isAddress (s))
1151 {
1152 sRef p = sRef_constructPointer (s);
1153 sname = sRef_unparse (p);
1154 }
1155 else
1156 {
1157 sname = sRef_unparse (s);
1158 }
1159 }
1160
1161 if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1162 {
1163 if (sRef_isMeaningful (s))
1164 {
1165 if (optgenerror
1166 (FLG_MODOBSERVER,
1167 message ("Suspect modification of observer %s: %s",
1168 sname, exprNode_unparse (err)),
1169 exprNode_isDefined (f) ? f->loc : g_currentloc))
1170 {
1171 sRef_showExpInfo (s);
1172 }
1173 }
1174 else
1175 {
1176 voptgenerror
1177 (FLG_MODOBSERVER,
1178 message ("Suspect modification of observer returned by "
1179 "function call: %s",
1180 exprNode_unparse (err)),
1181 exprNode_isDefined (f) ? f->loc : g_currentloc);
1182 }
1183 }
1184 else
1185 {
1186 if (optgenerror
1187 (FLG_MODOBSERVER,
1188 message ("Suspect modification of observer %s through alias %q: %s",
1189 sname, sRef_unparse (alias), exprNode_unparse (err)),
1190 exprNode_isDefined (f) ? f->loc : g_currentloc))
1191 {
1192 sRef_showExpInfo (s);
1193 }
1194 }
1195
1196 cstring_free (sname);
1197 }
1198
1199 (void) checkModifyAuxAux (s, f, alias, err);
1200 return FALSE;
1201}
1202
1203static
1204bool checkModifyValAux (sRef s, exprNode f, sRef alias, exprNode err)
1205{
1206 (void) checkModifyAuxAux (s, f, alias, err);
1207 return FALSE;
1208}
1209
1210static
1211bool checkCallModifyAux (sRef s, exprNode f, sRef alias, exprNode err)
1212{
1213 bool result = FALSE;
1214
1215 if (sRef_isObserver (s) && context_maybeSet (FLG_MODOBSERVER))
1216 {
1217 sRef p = sRef_isAddress (s) ? sRef_constructPointer (s) : s;
1218 cstring sname = sRef_unparse (p);
1219
1220 if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1221 {
1222 if (sRef_isMeaningful (s))
1223 {
1224 result = optgenerror
1225 (FLG_MODOBSERVER,
1226 message ("Suspect modification of observer %s: %s",
1227 sname, exprNode_unparse (err)),
1228 exprNode_isDefined (f) ? f->loc : g_currentloc);
1229 }
1230 else
1231 {
1232 result = optgenerror
1233 (FLG_MODOBSERVER,
1234 message ("Suspect modification of observer returned by "
1235 "function call: %s",
1236 exprNode_unparse (err)),
1237 exprNode_isDefined (f) ? f->loc : g_currentloc);
1238 }
1239 }
1240 else
1241 {
1242 result = optgenerror
1243 (FLG_MODOBSERVER,
1244 message
1245 ("Suspect modification of observer %s through alias %q: %s",
1246 sname, sRef_unparse (alias), exprNode_unparse (err)),
1247 exprNode_isDefined (f) ? f->loc : g_currentloc);
1248 }
1249
1250 cstring_free (sname);
1251 }
1252 else if (context_maybeSet (FLG_MODIFIES))
1253 {
1254 if (!(sRef_canModifyVal (s, context_modList ())))
1255 {
1256 sRef p = sRef_isAddress (s) ? sRef_constructPointer (s) : s;
1257 cstring sname = sRef_unparse (p);
1258 bool hasMods = context_hasMods ();
1259 sRef rb = sRef_getRootBase (s);
1260 flagcode errCode = hasMods ? FLG_MODIFIES : FLG_MODNOMODS;
1261 bool check = TRUE;
1262
1263 if (sRef_isGlobal (rb))
1264 {
1265 uentry ue = sRef_getUentry (rb);
1266
1267 /* be more specific here! */
1268 if (!uentry_isCheckedModify (ue))
1269 {
1270 check = FALSE;
1271 }
1272 }
1273
1274 if (check)
1275 {
1276 if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1277 {
1278 if (sRef_isLocalVar (sRef_getRootBase (s)))
1279 {
1280 voptgenerror
1281 (errCode,
1282 message
1283 ("Undocumented modification of internal "
1284 "state (%q) through call to %s: %s",
1285 sRef_unparse (s), exprNode_unparse (f),
1286 exprNode_unparse (err)),
1287 exprNode_isDefined (f) ? f->loc : g_currentloc);
1288 }
1289 else
1290 {
1291 if (sRef_isSystemState (s))
1292 {
1293 if (errCode == FLG_MODNOMODS)
1294 {
1295 if (context_getFlag (FLG_MODNOMODS))
1296 {
1297 errCode = FLG_MODFILESYSTEM;
1298 }
1299 }
1300 else
1301 {
1302 errCode = FLG_MODFILESYSTEM;
1303 }
1304 }
1305
1306 result = optgenerror
1307 (errCode,
1308 message ("Undocumented modification of %s "
1309 "possible from call to %s: %s",
1310 sname,
1311 exprNode_unparse (f),
1312 exprNode_unparse (err)),
1313 exprNode_isDefined (f) ? f->loc : g_currentloc);
1314 }
1315 }
1316 else
1317 {
1318 result = optgenerror
1319 (errCode,
1320 message ("Undocumented modification of %s possible "
1321 "from call to %s (through alias %q): %s",
1322 sname,
1323 exprNode_unparse (f),
1324 sRef_unparse (alias),
1325 exprNode_unparse (err)),
1326 exprNode_isDefined (f) ? f->loc : g_currentloc);
1327 }
1328 }
1329 cstring_free (sname);
1330 }
1331 }
1332 else
1333 {
1334 if (context_maybeSet (FLG_MUSTMOD))
1335 {
1336 (void) sRef_canModifyVal (s, context_modList ());
1337 }
1338 }
1339
1340 return result;
1341}
1342
1343void exprNode_checkCallModifyVal (sRef s, exprNodeList args, exprNode f, exprNode err)
1344{
1345 s = sRef_fixBaseParam (s, args);
1346 sRef_aliasCheckPred (checkCallModifyAux, NULL, s, f, err);
1347}
1348
1349void
1350exprChecks_checkExport (uentry e)
1351{
1352 if (context_checkExport (e))
1353 {
1354 fileloc fl = uentry_whereDeclared (e);
1355
1356 if (fileloc_isHeader (fl) && !fileloc_isLib (fl)
1357 && !fileloc_isImport (fl) && !uentry_isStatic (e))
1358 {
1359 if (uentry_isFunction (e) ||
1360 (uentry_isVariable (e) && ctype_isFunction (uentry_getType (e))))
1361 {
1362 voptgenerror
1363 (FLG_EXPORTFCN,
1364 message ("Function exported, but not specified: %q",
1365 uentry_getName (e)),
1366 fl);
1367 }
1368 else if (uentry_isExpandedMacro (e))
1369 {
1370 voptgenerror
1371 (FLG_EXPORTMACRO,
1372 message ("Expanded macro exported, but not specified: %q",
1373 uentry_getName (e)),
1374 fl);
1375 }
1376 else if (uentry_isVariable (e) && !uentry_isParam (e))
1377 {
1378 voptgenerror
1379 (FLG_EXPORTVAR,
1380 message ("Variable exported, but not specified: %q",
1381 uentry_getName (e)),
1382 fl);
1383 }
1384 else if (uentry_isEitherConstant (e))
1385 {
1386 voptgenerror
1387 (FLG_EXPORTCONST,
1388 message ("Constant exported, but not specified: %q",
1389 uentry_getName (e)),
1390 fl);
1391 }
1392 else if (uentry_isIter (e) || uentry_isEndIter (e))
1393 {
1394 voptgenerror
1395 (FLG_EXPORTITER,
1396 message ("Iterator exported, but not specified: %q",
1397 uentry_getName (e)),
1398 fl);
1399 }
1400
1401 else if (uentry_isDatatype (e))
1402 {
1403 ; /* error already reported */
1404 }
1405 else
1406 {
1407 BADEXIT;
1408 }
1409 }
1410 }
1411}
1412
1413static void checkSafeReturnExpr (/*@notnull@*/ exprNode e)
1414{
1415 ctype tr = ctype_returnValue (context_currentFunctionType ());
1416 ctype te = exprNode_getType (e);
1417
1418 if (!ctype_forceMatch (tr, te) && !exprNode_matchLiteral (tr, e))
1419 {
1420 (void) gentypeerror
1421 (te, e, tr, exprNode_undefined,
1422 message ("Return value type %t does not match declared type %t: %s",
1423 te, tr, exprNode_unparse (e)),
1424 e->loc);
1425 }
1426 else
1427 {
1428 sRef ret = e->sref;
1429 uentry rval = context_getHeader ();
1430 sRef resultref = uentry_getSref (rval);
1431
1432 checkReturnTransfer (e, rval);
1433
1434 if (!(sRef_isExposed (uentry_getSref (context_getHeader ()))
1435 || sRef_isObserver (uentry_getSref (context_getHeader ())))
1436 && (context_getFlag (FLG_RETALIAS)
1437 || context_getFlag (FLG_RETEXPOSE)))
1438 {
1439 sRef base = sRef_getRootBase (ret);
1440 ctype rtype = e->typ;
1441
1442 if (ctype_isUnknown (rtype))
1443 {
1444 rtype = tr;
1445 }
1446
1447 if (ctype_isVisiblySharable (rtype))
1448 {
1449 if (context_getFlag (FLG_RETALIAS))
1450 {
1451 sRef_aliasCheckPred (checkRefGlobParam, NULL, base,
1452 e, exprNode_undefined);
1453 }
1454
1455 if (context_getFlag (FLG_RETEXPOSE) && sRef_isIReference (ret)
1456 && !sRef_isExposed (resultref) && !sRef_isObserver (resultref))
1457 {
1458 sRef_aliasCheckPred (checkRepExposed, NULL, base, e,
1459 exprNode_undefined);
1460 }
1461 }
1462 }
1463 }
1464}
1465
This page took 0.243652 seconds and 5 git commands to generate.