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