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