]> andersk Git - splint.git/blob - src/exprChecks.c
Added (limited) support for implicit annotations.
[splint.git] / src / exprChecks.c
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
42 static bool checkCallModifyAux (sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
43 static bool checkModifyValAux (sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
44 static bool checkModifyAux (sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
45 static 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
55 void
56 exprNode_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
153 static bool
154 checkRepExposed (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
194 static bool
195 checkRefGlobParam (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
322 void
323 exprNode_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
335 void
336 exprNode_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
348 void
349 exprChecks_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
384 void
385 exprNode_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
418 void
419 exprNode_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
468 void
469 exprChecks_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
511 void
512 exprNode_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
614 void 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
852 void 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
887       /* drl added call*/
888       exprNode_checkFunction (context_getHeader (), body);
889       
890       if (!checkret)
891         {
892           context_returnFunction ();
893         }
894     }
895 }
896 /*drl modified */
897
898 extern constraintList implicitFcnConstraints;
899
900 void exprNode_checkFunction (/*@unused@*/ uentry ue, /*@only@*/ exprNode body)
901 {
902   constraintList c, t;
903  constraintList c2, fix;
904
905  //  return;
906   
907   exprNode_generateConstraints (body);
908   
909   c =   uentry_getFcnPreconditions (ue);
910   DPRINTF(("function constraints\n"));
911   DPRINTF (("\n\n\n\n\n\n\n"));
912
913   context_enterInnerContext ();
914   
915    if (c)
916      {
917        llassert (c);
918        DPRINTF ( (message ("Function preconditions are %s \n\n\n\n\n", constraintList_printDetailed (c) ) ) );
919        
920        t = reflectChanges (body->requiresConstraints, constraintList_copy (c) );
921        body->requiresConstraints = constraintList_copy (t);
922
923        c2  =  constraintList_copy (c);
924        fix =  constraintList_makeFixedArrayConstraints (body->uses);
925        c2  =  reflectChanges (c2, constraintList_copy(fix) );
926        
927        t = reflectChanges (body->requiresConstraints, constraintList_copy (c2) );
928        body->requiresConstraints = constraintList_copy (t);
929        
930        DPRINTF ( (message ("The body has the required constraints: %s", constraintList_printDetailed (t) ) ) );
931        t = constraintList_mergeEnsures (c, body->ensuresConstraints);
932
933    body->ensuresConstraints = constraintList_copy (t);
934    
935    DPRINTF ( (message ("The body has the ensures constraints: %s", constraintList_printDetailed (t) ) ) );
936      }
937
938    if (c)
939      {
940        DPRINTF((message ("The Function %s has the preconditions %s", uentry_unparse(ue), constraintList_printDetailed(c) ) ) );
941      }
942    else
943      {
944        DPRINTF((message ("The Function %s has no preconditions", uentry_unparse(ue) ) ) );
945      }
946
947    if ( implicitFcnConstraints)
948      {
949           if (context_getFlag (FLG_IMPLICTCONSTRAINT) )
950               {
951                 body->requiresConstraints = reflectChanges (body->requiresConstraints, constraintList_copy (implicitFcnConstraints) );
952               }
953      }
954    
955    constraintList_printError(body->requiresConstraints, g_currentloc);
956    constraintList_printError(body->ensuresConstraints, g_currentloc);
957    
958    //   ConPrint (message ("Unable to resolve function constraints:\n%s", constraintList_printDetailed(body->requiresConstraints) ), g_currentloc);
959
960    //   ConPrint (message ("LCLint has found function post conditions:\n%s", constraintList_printDetailed(body->ensuresConstraints) ), g_currentloc);
961   
962      //  printf ("The required constraints are:\n%s", constraintList_printDetailed(body->requiresConstraints) );
963      //   printf ("The ensures constraints are:\n%s", constraintList_printDetailed(body->ensuresConstraints) );
964    
965    context_exitInnerPlain();
966    /* exprNode_free (body); */
967 }
968
969 void exprChecks_checkEmptyMacroBody (void)
970 {
971   uentry hdr;
972   
973   if (!(context_inFunctionLike () || context_inMacroConstant ()
974         || context_inMacroUnknown ()))
975     {
976       llcontbug 
977         (message ("exprNode_checkEmptyMacroBody: not in macro function or constant: %q", 
978                   context_unparse ()));
979       return;
980     }
981   
982   hdr = context_getHeader ();
983   
984   beginLine ();
985   
986   if (uentry_isFunction (hdr))
987     {
988       voptgenerror 
989         (FLG_MACROEMPTY,
990          message 
991          ("Macro definition for %q is empty", uentry_getName (hdr)),
992          g_currentloc);
993
994       usymtab_checkFinalScope (FALSE);
995     }
996
997   context_exitFunction ();
998   return;
999 }
1000
1001 void exprNode_checkIterBody (/*@only@*/ exprNode body)
1002 {
1003   context_exitAllClauses ();
1004
1005   context_exitFunction ();
1006   exprNode_free (body);
1007 }
1008
1009 void exprNode_checkIterEnd (/*@only@*/ exprNode body)
1010 {
1011   context_exitAllClauses ();
1012   context_exitFunction ();
1013   exprNode_free (body);
1014 }
1015
1016 static
1017 bool checkModifyAuxAux (sRef s, exprNode f, sRef alias, exprNode err)
1018 {
1019   bool hasMods = context_hasMods ();
1020   flagcode errCode = hasMods ? FLG_MODIFIES : FLG_MODNOMODS;
1021
1022   if (exprNode_isDefined (f))
1023     {
1024       f->sets = sRefSet_insert (f->sets, s); 
1025     }
1026
1027   if (context_getFlag (FLG_MODIFIES) 
1028       && (hasMods || context_getFlag (FLG_MODNOMODS)))
1029     {
1030       sRefSet mods = context_modList ();
1031       
1032       if (!sRef_canModify (s, mods))
1033         {
1034           sRef rb = sRef_getRootBase (s);
1035          
1036           
1037           if (sRef_isGlobal (rb))
1038             {
1039               if (!context_checkGlobMod (rb))
1040                 {
1041                                   return FALSE;
1042                 }
1043             }
1044
1045           if (sRef_isInvalid (alias) || sRef_sameName (s, alias))
1046             {
1047               if (sRef_isLocalVar (sRef_getRootBase (s)))
1048                 {
1049                   voptgenerror 
1050                     (errCode,
1051                      message 
1052                      ("Undocumented modification of internal state (%q): %s", 
1053                       sRef_unparse (s), exprNode_unparse (err)), 
1054                      exprNode_isDefined (f) ? f->loc : g_currentloc);
1055                 }
1056               else
1057                 {
1058                   if (sRef_isSystemState (s))
1059                     {
1060                       if (errCode == FLG_MODNOMODS) 
1061                         {
1062                           if (context_getFlag (FLG_MODNOMODS))
1063                             {
1064                               errCode = FLG_MODFILESYSTEM;
1065                             }
1066                         }
1067                       else
1068                         {
1069                           errCode = FLG_MODFILESYSTEM;
1070                         }
1071                     }
1072
1073                   voptgenerror 
1074                     (errCode,
1075                      message ("Undocumented modification of %q: %s", 
1076                               sRef_unparse (s), exprNode_unparse (err)), 
1077                      exprNode_isDefined (f) ? f->loc : g_currentloc);
1078                 }
1079               
1080               return TRUE;
1081             }
1082           else
1083             {
1084               if (sRef_isReference (s) && !sRef_isAddress (alias))
1085                 {
1086                   voptgenerror 
1087                     (errCode,
1088                      message
1089                      ("Possible undocumented modification of %q through alias %q: %s", 
1090                       sRef_unparse (s),
1091                       sRef_unparse (alias),
1092                       exprNode_unparse (err)),
1093                      exprNode_isDefined (f) ? f->loc : g_currentloc);
1094                   return TRUE;
1095                 }
1096             }
1097         }
1098     }
1099   else
1100     {
1101       if (context_maybeSet (FLG_MUSTMOD))
1102         {
1103           (void) sRef_canModify (s, context_modList ());
1104         }
1105       
1106       if (sRef_isRefsField (s))
1107         {
1108           sRef_setModified (s);
1109         }
1110     }
1111   
1112   return FALSE;
1113 }
1114
1115 static
1116 bool checkModifyAux (sRef s, exprNode f, sRef alias, exprNode err)
1117 {
1118   DPRINTF (("Check modify aux: %s", sRef_unparseFull (s)));
1119
1120   if (sRef_isReference (s) && sRef_isObserver (s) 
1121       && context_maybeSet (FLG_MODOBSERVER))
1122     {    
1123       cstring sname;
1124       
1125       if (sRef_isPointer (s)) 
1126         {
1127           sRef base = sRef_getBase (s);
1128           sname = sRef_unparse (base);
1129         }
1130       else 
1131         {
1132           if (sRef_isAddress (s))
1133             {
1134               sRef p = sRef_constructPointer (s);
1135               sname = sRef_unparse (p);
1136             }
1137           else
1138             {
1139               sname = sRef_unparse (s);
1140             }
1141         }
1142       
1143       if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1144         {
1145           if (sRef_isMeaningful (s))
1146             {
1147               if (optgenerror 
1148                   (FLG_MODOBSERVER,
1149                    message ("Suspect modification of observer %s: %s", 
1150                             sname, exprNode_unparse (err)), 
1151                    exprNode_isDefined (f) ? f->loc : g_currentloc))
1152                 {
1153                   sRef_showExpInfo (s);
1154                 }
1155             }
1156           else
1157             {
1158               voptgenerror 
1159                 (FLG_MODOBSERVER,
1160                  message ("Suspect modification of observer returned by "
1161                           "function call: %s", 
1162                           exprNode_unparse (err)), 
1163                  exprNode_isDefined (f) ? f->loc : g_currentloc);
1164             }
1165         }
1166       else
1167         {
1168           if (optgenerror
1169               (FLG_MODOBSERVER,
1170                message ("Suspect modification of observer %s through alias %q: %s", 
1171                         sname, sRef_unparse (alias), exprNode_unparse (err)), 
1172                exprNode_isDefined (f) ? f->loc : g_currentloc))
1173             {
1174               sRef_showExpInfo (s);
1175             }
1176         }
1177       
1178       cstring_free (sname);
1179     }
1180   
1181   (void) checkModifyAuxAux (s, f, alias, err);
1182   return FALSE;
1183 }
1184
1185 static
1186 bool checkModifyValAux (sRef s, exprNode f, sRef alias, exprNode err)
1187 {
1188   (void) checkModifyAuxAux (s, f, alias, err);
1189   return FALSE;
1190 }
1191
1192 static
1193 bool checkCallModifyAux (sRef s, exprNode f, sRef alias, exprNode err)
1194 {
1195   bool result = FALSE;
1196
1197   if (sRef_isObserver (s) && context_maybeSet (FLG_MODOBSERVER))
1198     {    
1199       sRef p = sRef_isAddress (s) ? sRef_constructPointer (s) : s;
1200       cstring sname = sRef_unparse (p);
1201
1202       if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1203         {
1204           if (sRef_isMeaningful (s))
1205             {
1206               result = optgenerror 
1207                 (FLG_MODOBSERVER,
1208                  message ("Suspect modification of observer %s: %s", 
1209                           sname, exprNode_unparse (err)), 
1210                  exprNode_isDefined (f) ? f->loc : g_currentloc);
1211             }
1212           else
1213             {
1214               result = optgenerror 
1215                 (FLG_MODOBSERVER,
1216                  message ("Suspect modification of observer returned by "
1217                           "function call: %s", 
1218                           exprNode_unparse (err)), 
1219                  exprNode_isDefined (f) ? f->loc : g_currentloc);
1220             }
1221         }
1222       else
1223         {
1224           result = optgenerror 
1225             (FLG_MODOBSERVER,
1226              message
1227              ("Suspect modification of observer %s through alias %q: %s", 
1228               sname, sRef_unparse (alias), exprNode_unparse (err)), 
1229              exprNode_isDefined (f) ? f->loc : g_currentloc);
1230         }
1231       
1232       cstring_free (sname);
1233     }
1234   else if (context_maybeSet (FLG_MODIFIES))
1235     {
1236       if (!(sRef_canModifyVal (s, context_modList ())))
1237         {
1238           sRef p = sRef_isAddress (s) ? sRef_constructPointer (s) : s;
1239           cstring sname = sRef_unparse (p);
1240           bool hasMods = context_hasMods ();
1241           sRef rb = sRef_getRootBase (s);
1242           flagcode errCode = hasMods ? FLG_MODIFIES : FLG_MODNOMODS;
1243           bool check = TRUE;
1244           
1245           if (sRef_isGlobal (rb))
1246             {
1247               uentry ue = sRef_getUentry (rb);
1248               
1249               /* be more specific here! */
1250               if (!uentry_isCheckedModify (ue))
1251                 {
1252                   check = FALSE;
1253                 }
1254             }
1255           
1256           if (check)
1257             {
1258               if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1259                 {
1260                   if (sRef_isLocalVar (sRef_getRootBase (s)))
1261                     {
1262                       voptgenerror 
1263                         (errCode,
1264                          message 
1265                          ("Undocumented modification of internal "
1266                           "state (%q) through call to %s: %s", 
1267                           sRef_unparse (s), exprNode_unparse (f),
1268                           exprNode_unparse (err)), 
1269                          exprNode_isDefined (f) ? f->loc : g_currentloc);
1270                     }
1271                   else
1272                     {
1273                       if (sRef_isSystemState (s))
1274                         {
1275                           if (errCode == FLG_MODNOMODS) 
1276                             {
1277                               if (context_getFlag (FLG_MODNOMODS))
1278                                 {
1279                                   errCode = FLG_MODFILESYSTEM;
1280                                 }
1281                             }
1282                           else
1283                             {
1284                               errCode = FLG_MODFILESYSTEM;
1285                             }
1286                         }
1287                       
1288                       result = optgenerror 
1289                         (errCode,
1290                          message ("Undocumented modification of %s "
1291                                   "possible from call to %s: %s", 
1292                                   sname,
1293                                   exprNode_unparse (f),
1294                                   exprNode_unparse (err)),
1295                          exprNode_isDefined (f) ? f->loc : g_currentloc);
1296                     }
1297                 }
1298               else
1299                 {
1300                   result = optgenerror
1301                     (errCode,
1302                      message ("Undocumented modification of %s possible "
1303                               "from call to %s (through alias %q): %s", 
1304                               sname,
1305                               exprNode_unparse (f), 
1306                               sRef_unparse (alias), 
1307                               exprNode_unparse (err)),
1308                      exprNode_isDefined (f) ? f->loc : g_currentloc);
1309                 }
1310             }
1311           cstring_free (sname);
1312         }
1313     }
1314   else
1315     {
1316       if (context_maybeSet (FLG_MUSTMOD))
1317         {
1318           (void) sRef_canModifyVal (s, context_modList ());
1319         }
1320     }
1321
1322   return result;
1323 }
1324
1325 void exprNode_checkCallModifyVal (sRef s, exprNodeList args, exprNode f, exprNode err)
1326 {
1327   s = sRef_fixBaseParam (s, args);
1328   sRef_aliasCheckPred (checkCallModifyAux, NULL, s, f, err);
1329 }
1330
1331 void
1332 exprChecks_checkExport (uentry e)
1333 {
1334   if (context_checkExport (e))
1335     {
1336       fileloc fl = uentry_whereDeclared (e);
1337       
1338       if (fileloc_isHeader (fl) && !fileloc_isLib (fl) 
1339           && !fileloc_isImport (fl) && !uentry_isStatic (e))
1340         {
1341           if (uentry_isFunction (e) || 
1342               (uentry_isVariable (e) && ctype_isFunction (uentry_getType (e))))
1343             {
1344               voptgenerror 
1345                 (FLG_EXPORTFCN,
1346                  message ("Function exported, but not specified: %q", 
1347                           uentry_getName (e)),
1348                  fl);
1349             }
1350           else if (uentry_isExpandedMacro (e))
1351             {
1352               voptgenerror
1353                 (FLG_EXPORTMACRO,
1354                  message ("Expanded macro exported, but not specified: %q", 
1355                           uentry_getName (e)),
1356                  fl);
1357             }
1358           else if (uentry_isVariable (e) && !uentry_isParam (e)) 
1359             {
1360               voptgenerror 
1361                 (FLG_EXPORTVAR,
1362                  message ("Variable exported, but not specified: %q", 
1363                           uentry_getName (e)),
1364                  fl);
1365             }
1366           else if (uentry_isEitherConstant (e))
1367             {
1368               voptgenerror 
1369                 (FLG_EXPORTCONST,
1370                  message ("Constant exported, but not specified: %q", 
1371                           uentry_getName (e)),
1372                  fl);
1373             }
1374           else if (uentry_isIter (e) || uentry_isEndIter (e))
1375             {
1376               voptgenerror 
1377                 (FLG_EXPORTITER,
1378                  message ("Iterator exported, but not specified: %q", 
1379                           uentry_getName (e)),
1380                  fl);
1381             }
1382
1383           else if (uentry_isDatatype (e))
1384             {
1385               ; /* error already reported */
1386             }
1387           else
1388             {
1389               BADEXIT;
1390             }
1391         }
1392     }
1393 }
1394
1395 static void checkSafeReturnExpr (/*@notnull@*/ exprNode e)
1396 {
1397   ctype tr = ctype_returnValue (context_currentFunctionType ());
1398   ctype te = exprNode_getType (e);
1399
1400   if (!ctype_forceMatch (tr, te) && !exprNode_matchLiteral (tr, e))
1401     {
1402       (void) gentypeerror
1403         (te, e, tr, exprNode_undefined,
1404          message ("Return value type %t does not match declared type %t: %s",
1405                   te, tr, exprNode_unparse (e)),
1406          e->loc);
1407     }
1408   else
1409     {
1410       sRef ret = e->sref;
1411       uentry rval = context_getHeader ();
1412       sRef resultref = uentry_getSref (rval);
1413
1414       checkReturnTransfer (e, rval);
1415
1416       if (!(sRef_isExposed (uentry_getSref (context_getHeader ()))
1417             || sRef_isObserver (uentry_getSref (context_getHeader ())))
1418           && (context_getFlag (FLG_RETALIAS) 
1419               || context_getFlag (FLG_RETEXPOSE)))
1420         {
1421           sRef base = sRef_getRootBase (ret);
1422           ctype rtype = e->typ;
1423
1424           if (ctype_isUnknown (rtype))
1425             {
1426               rtype = tr;
1427             }
1428
1429           if (ctype_isVisiblySharable (rtype))
1430             {
1431               if (context_getFlag (FLG_RETALIAS))
1432                 {
1433                   sRef_aliasCheckPred (checkRefGlobParam, NULL, base, 
1434                                        e, exprNode_undefined);
1435                 }
1436               
1437               if (context_getFlag (FLG_RETEXPOSE) && sRef_isIReference (ret) 
1438                   && !sRef_isExposed (resultref) && !sRef_isObserver (resultref))
1439                 {
1440                   sRef_aliasCheckPred (checkRepExposed, NULL, base, e, 
1441                                        exprNode_undefined);
1442                 }
1443             }
1444         }
1445     }
1446 }
1447
This page took 0.150092 seconds and 5 git commands to generate.