Main Page   Alphabetical List   Compound List   File List   Compound Members   File Members  

exprChecks.c

Go to the documentation of this file.
00001 /*
00002 ** LCLint - annotation-assisted static program checker
00003 ** Copyright (C) 1994-2000 University of Virginia,
00004 **         Massachusetts Institute of Technology
00005 **
00006 ** This program is free software; you can redistribute it and/or modify it
00007 ** under the terms of the GNU General Public License as published by the
00008 ** Free Software Foundation; either version 2 of the License, or (at your
00009 ** option) any later version.
00010 ** 
00011 ** This program is distributed in the hope that it will be useful, but
00012 ** WITHOUT ANY WARRANTY; without even the implied warranty of
00013 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 ** General Public License for more details.
00015 ** 
00016 ** The GNU General Public License is available from http://www.gnu.org/ or
00017 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00018 ** MA 02111-1307, USA.
00019 **
00020 ** For information on lclint: lclint-request@cs.virginia.edu
00021 ** To report a bug: lclint-bug@cs.virginia.edu
00022 ** For more information: http://lclint.cs.virginia.edu
00023 */
00024 /*
00025 ** exprChecks.c
00026 */
00027 
00028 # include "lclintMacros.nf"
00029 # include "basic.h"
00030 # include "cgrammar.h"
00031 # include "cgrammar_tokens.h"
00032 # include "aliasChecks.h"
00033 # include "exprChecks.h"
00034 
00035 /*
00036 ** for now, allow exprChecks to access exprNode.
00037 ** may remove this in future
00038 */
00039 
00040 /*@access exprNode@*/
00041 
00042 static bool checkCallModifyAux (sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
00043 static bool checkModifyValAux (sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
00044 static bool checkModifyAux (sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
00045 static void checkSafeReturnExpr (/*@notnull@*/ exprNode p_e);
00046 
00047 /*
00048 ** called at end of expression statement
00049 **
00050 **  of e->kind is not an assign, empty, body or modop
00051 **         verify the the value is void
00052 **
00053 */
00054 
00055 void
00056 exprNode_checkStatement (exprNode e)
00057 {
00058   bool hasError = FALSE;
00059 
00060   if (!exprNode_isError (e))
00061     {
00062       exprKind ek = e->kind;
00063 
00064       if (ek == XPR_CALL && !(ctype_isRealVoid (e->typ)))
00065         { 
00066           if (ctype_isKnown (e->typ))
00067             {
00068               if (ctype_isManifestBool (ctype_realishType (e->typ)))
00069                 {
00070                   hasError = optgenerror 
00071                     (FLG_RETVALBOOL,
00072                      message ("Return value (type %t) ignored: %s",
00073                               e->typ,
00074                               exprNode_unparseFirst (e)),
00075                      e->loc);
00076                 }
00077               else if (ctype_isDirectInt (e->typ))
00078                 {
00079                   hasError = optgenerror 
00080                     (FLG_RETVALINT,
00081                      message ("Return value (type %t) ignored: %s",
00082                               e->typ,
00083                               exprNode_unparseFirst (e)),
00084                      e->loc);
00085                 }
00086               else
00087                 {
00088                   hasError = optgenerror 
00089                     (FLG_RETVALOTHER,
00090                      message ("Return value (type %t) ignored: %s",
00091                               e->typ,
00092                               exprNode_unparseFirst (e)),
00093                      e->loc);
00094                 }
00095             }
00096         }
00097 
00098       if (!hasError && !(exprNode_mayEscape (e))
00099           && !(e->canBreak)) /* control changes are effects too! */
00100         {
00101           if (sRefSet_hasRealElement (e->sets)
00102               || sRefSet_hasRealElement (e->msets))
00103             {
00104               ; /* okay */
00105             }
00106           else
00107             {
00108               if (sRefSet_isEmpty (e->sets) && sRefSet_isEmpty (e->msets))
00109                 {
00110                   voptgenerror
00111                     (FLG_NOEFFECT,
00112                      message ("Statement has no effect: %s",
00113                               exprNode_unparseFirst (e)),
00114                      e->loc);
00115                 }
00116               else
00117                 {
00118                   if (context_maybeSet (FLG_NOEFFECTUNCON))
00119                     {
00120                       if (sRefSet_hasUnconstrained (e->sets))
00121                         {
00122                           voptgenerror
00123                             (FLG_NOEFFECTUNCON,
00124                              message ("Statement has no effect (possible "
00125                                       "undected modification through "
00126                                       "call to %q): %s",
00127                                       sRefSet_unparseUnconstrained (e->sets),
00128                                       exprNode_unparseFirst (e)),
00129                              e->loc);
00130                         }
00131                       else if (sRefSet_hasUnconstrained (e->msets))
00132                         {
00133                           voptgenerror
00134                             (FLG_NOEFFECTUNCON,
00135                              message ("Statement has no effect (possible "
00136                                       "undected modification through "
00137                                       "call to %q): %s",
00138                                       sRefSet_unparseUnconstrained (e->msets),
00139                                       exprNode_unparseFirst (e)),
00140                              e->loc);
00141                         }
00142                       else
00143                         {
00144                           ; /* statement has unknown modification */
00145                         }
00146                     }
00147                 }
00148             }
00149         }
00150     }
00151 }
00152 
00153 static bool
00154 checkRepExposed (sRef base, /*@notnull@*/ exprNode e, sRef alias, 
00155                  /*@unused@*/ exprNode unused)
00156 {
00157   ctype btype;
00158 
00159   if (sRef_isInvalid (alias) || sRef_sameName (base, alias))
00160     {
00161       btype = sRef_getType (base);
00162 
00163       if (ctype_isAbstract (btype) && ctype_isVisiblySharable (e->typ))
00164         {
00165           voptgenerror (FLG_RETEXPOSE,
00166                         message ("Return value exposes rep of %s: %s",
00167                                  ctype_unparse (btype),
00168                                  exprNode_unparse (e)),
00169                         e->loc);
00170           return TRUE;
00171         }
00172     }
00173   else
00174     {
00175       sRef rbase = sRef_getRootBase (base);
00176       btype = sRef_getType (rbase);
00177                       
00178       if (ctype_isAbstract (btype) && ctype_isVisiblySharable (e->typ))
00179         {
00180           voptgenerror 
00181             (FLG_RETEXPOSE,
00182              message ("Return value may expose rep of %s through alias %q: %s",
00183                       ctype_unparse (btype),
00184                       sRef_unparse (rbase),
00185                       exprNode_unparse (e)),
00186              e->loc);
00187           return TRUE;
00188         }
00189     }
00190 
00191   return FALSE;
00192 }
00193 
00194 static bool
00195 checkRefGlobParam (sRef base, /*@notnull@*/ exprNode e,
00196                    sRef alias, /*@unused@*/ exprNode unused)
00197 {
00198   if (sRef_isInvalid (alias) || sRef_sameName (base, alias))
00199     {
00200       ctype ct = e->typ;
00201 
00202       if (ctype_isUnknown (ct))
00203         {
00204           ct = sRef_getType (base);
00205         }
00206  
00207       if (ctype_isVisiblySharable (ct))
00208         {
00209           if (sRef_isGlobal (base))
00210             {
00211               voptgenerror
00212                 (FLG_RETALIAS,
00213                  message ("Function returns reference to global %q: %s",
00214                           sRef_unparse (base),
00215                           exprNode_unparse (e)),
00216                  e->loc);
00217 
00218               return TRUE;
00219             }
00220           else if (sRef_isAnyParam (base))
00221             {
00222               uentryList params = context_getParams ();
00223               int paramno = sRef_getParam (base);
00224 
00225               if (paramno < uentryList_size (params))
00226                 {
00227                   uentry arg = uentryList_getN (params, paramno);
00228                   sRef ref = uentry_getSref (arg);
00229 
00230                   if (uentry_isReturned (arg) 
00231                       || sRef_isOnly (ref) 
00232                       || sRef_isExposed (ref)
00233                       || sRef_isRefCounted (ref))
00234                     {
00235                       ; /* okay */
00236                     }
00237                   else
00238                     {
00239                       voptgenerror 
00240                         (FLG_RETALIAS,
00241                          message ("Function returns reference to parameter %q: %s",
00242                                   sRef_unparse (base),
00243                                   exprNode_unparse (e)),
00244                          e->loc);
00245                     }
00246                 }
00247               else
00248                 {
00249                   llbuglit ("ret alias: bad paramno");
00250                 }
00251               
00252               return TRUE;
00253             }
00254           else
00255             {
00256               return FALSE;
00257             }
00258         }
00259     }
00260   else
00261     {
00262       if (ctype_isVisiblySharable (e->typ))
00263         {
00264           if (sRef_isGlobal (base))
00265             {
00266               voptgenerror 
00267                 (FLG_RETALIAS,
00268                  message ("Function may return reference to global %q through alias %q: %s",
00269                           sRef_unparse (alias),
00270                           sRef_unparse (base),
00271                           exprNode_unparse (e)),
00272                  e->loc);
00273               return TRUE;
00274             }
00275           else if (sRef_isAnyParam (base) && !(sRef_isOnly (base)))
00276             {
00277               uentryList params = context_getParams ();
00278               int paramno = sRef_getParam (base);
00279               
00280               if (paramno < uentryList_size (params))
00281                 {
00282                   uentry arg = uentryList_getN (params, paramno);
00283                   
00284                   if (!uentry_isReturned (arg))
00285                     {
00286                       voptgenerror 
00287                         (FLG_RETALIAS,
00288                          message 
00289                          ("Function may return reference to parameter %q through alias %q: %s",
00290                           sRef_unparse (base),
00291                           sRef_unparse (alias),
00292                           exprNode_unparse (e)),
00293                          e->loc);
00294                       
00295                       return TRUE;
00296                     }
00297                 }
00298               else
00299                 {
00300                   voptgenerror 
00301                     (FLG_RETALIAS,
00302                      message 
00303                      ("Function may return reference to parameter %q through alias %q: %s",
00304                       sRef_unparse (base),
00305                       sRef_unparse (alias),
00306                       exprNode_unparse (e)),
00307                      e->loc);
00308                   
00309                   return TRUE;
00310                 }
00311             }
00312           else
00313             {
00314               return FALSE;
00315             }
00316         }
00317     }
00318   return FALSE;
00319 }
00320 
00321 
00322 void
00323 exprNode_checkModify (exprNode e, exprNode err)
00324 {
00325   llassert (exprNode_isDefined (e));
00326 
00327   DPRINTF (("Check modify: %s", exprNode_unparse (e)));
00328 
00329   if (sRef_isValid (e->sref))
00330     {
00331       sRef_aliasCheckPred (checkModifyAux, sRef_isReference, e->sref, e, err);
00332     }
00333 }
00334 
00335 void
00336 exprNode_checkModifyVal (exprNode e, exprNode err)
00337 {
00338   llassert (exprNode_isDefined (e));
00339   
00340   DPRINTF (("Check modify val: %s", exprNode_unparse (e)));
00341 
00342   if (sRef_isValid (e->sref))
00343     {
00344       sRef_aliasCheckPred (checkModifyValAux, sRef_isReference, e->sref, e, err);
00345     }
00346 }
00347 
00348 void
00349 exprChecks_checkNullReturn (fileloc loc)
00350 {
00351   if (!context_inRealFunction ())
00352     {
00353       /*
00354       llmsg ("exprChecks_checkNullReturnExpr: not in function context");
00355       */
00356       return;
00357     }
00358   else
00359     {
00360       if (ctype_isFunction (context_currentFunctionType ()))
00361         {
00362           ctype tr = ctype_returnValue (context_currentFunctionType ());
00363 
00364           if (!ctype_isFirstVoid (tr))
00365             {
00366               if (ctype_isUnknown (tr))
00367                 {
00368                   voptgenerror
00369                     (FLG_CONTROL,
00370                      cstring_makeLiteral ("Empty return in function declared to implicitly return int"),
00371                      loc);
00372                 }
00373               else
00374                 {
00375                   voptgenerror (FLG_CONTROL,
00376                                 message ("Empty return in function declared to return %t", tr),
00377                                 loc);
00378                 }
00379             }
00380         }
00381     }
00382 }
00383 
00384 void
00385 exprNode_checkReturn (exprNode e)
00386 {
00387   if (!exprNode_isError (e))
00388     {
00389       if (!context_inRealFunction ())
00390         {
00391           if (context_inMacro ())
00392             {
00393               llerror (FLG_CONTROL,
00394                        message ("Macro %s uses return (not functional)",
00395                                 context_inFunctionName ()));
00396             }
00397           else
00398             {
00399               /*
00400                 llbuglit ("exprNode_checkReturn: not in function context");
00401                 */
00402             }
00403         }
00404       else
00405         {
00406           if (ctype_isFunction (context_currentFunctionType ()))
00407             {
00408               checkSafeReturnExpr (e);
00409             }
00410           else
00411             {
00412               ;
00413             }
00414         }
00415     }
00416 }
00417 
00418 void
00419 exprNode_checkPred (cstring c, exprNode e)
00420 {
00421   ctype ct;
00422 
00423   if (exprNode_isError (e))
00424     return;
00425 
00426   ct = exprNode_getType (e);
00427 
00428   if (exprNode_isAssign (e))
00429     {
00430       voptgenerror 
00431         (FLG_PREDASSIGN,
00432          message ("Test expression for %s is assignment expression: %s", 
00433                   c, exprNode_unparse (e)),
00434          e->loc);
00435     }
00436 
00437   if (ctype_isRealBool (ct))
00438     {
00439      ;
00440     }
00441   else if (ctype_isRealPointer (ct))
00442     {
00443       voptgenerror
00444         (FLG_PREDBOOLPTR,
00445          message ("Test expression for %s not %s, type %t: %s", c, 
00446                   context_printBoolName (), 
00447                   ct, exprNode_unparse (e)),
00448          e->loc);
00449     }
00450   else if (ctype_isRealInt (ct))
00451     {
00452       voptgenerror 
00453         (FLG_PREDBOOLINT,
00454          message ("Test expression for %s not %s, type %t: %s", c, 
00455                   context_printBoolName (), ct, exprNode_unparse (e)),
00456          e->loc);
00457     }
00458   else
00459     {
00460       voptgenerror 
00461         (FLG_PREDBOOLOTHERS,
00462          message ("Test expression for %s not %s, type %t: %s", c, 
00463                   context_printBoolName (), ct, exprNode_unparse (e)),
00464          e->loc);
00465     }
00466 }
00467 
00468 void
00469 exprChecks_checkUsedGlobs (globSet decl, globSet used)
00470 {
00471   fileloc fl = uentry_whereSpecified (context_getHeader ());
00472 
00473   if (fileloc_isUndefined (fl))
00474     {
00475       fl = uentry_whereDeclared (context_getHeader ());
00476     }
00477 
00478   globSet_allElements (decl, el)
00479     {
00480       if (!globSet_member (used, el))
00481         {
00482           if (sRef_isSpecInternalState (el)
00483               || sRef_isNothing (el))
00484             {
00485               ;
00486             }
00487           else
00488             {
00489               cstring sname = sRef_unparse (el);
00490               
00491               if (fileloc_isLib (fl))
00492                 {
00493                   voptgenerror (FLG_USEALLGLOBS,
00494                                 message ("Global %s listed (%q) but not used", 
00495                                          sname, fileloc_unparse (fl)),
00496                                 g_currentloc);
00497                 }               
00498               else
00499                 {
00500                   voptgenerror (FLG_USEALLGLOBS,
00501                                 message ("Global %s listed but not used", sname),
00502                                 fl);
00503                 }
00504 
00505               cstring_free (sname);
00506             }
00507         }
00508     } end_globSet_allElements;
00509 }
00510 
00511 void
00512 exprNode_checkAllMods (sRefSet mods, uentry ue)
00513 {
00514   bool realParams = FALSE;
00515   uentry le = context_getHeader ();
00516   fileloc fl = uentry_whereSpecified (le);
00517   uentryList specParamNames = uentryList_undefined;
00518   uentryList paramNames = context_getParams ();
00519 
00520   if (uentry_isFunction (le))
00521     {
00522       specParamNames = uentry_getParams (le);  
00523 
00524       if (uentryList_isUndefined (specParamNames))
00525         {
00526           ; /* unknown params */
00527         }
00528       else if (uentryList_size (paramNames) != uentryList_size (specParamNames))
00529         {
00530           llbug
00531             (message ("exprNode_checkAllMods: parameter lists have different sizes: "
00532                       "%q (%d) / %q (%d)",
00533                       uentryList_unparse (paramNames),
00534                       uentryList_size (paramNames),
00535                       uentryList_unparse (specParamNames),
00536                       uentryList_size (specParamNames)));
00537         }
00538       else if (uentryList_size (paramNames) > 0 
00539                && !uentry_hasRealName (uentryList_getN (specParamNames, 0)))
00540         {
00541           /* loaded from a library */
00542         }
00543       else
00544         {
00545           realParams = TRUE;
00546         }
00547     }
00548 
00549   sRefSet_allElements (mods, sr)
00550     {
00551       if (sRef_isNothing (sr) || sRef_isSpecState (sr))
00552         {
00553           ; /* should report on anything? */
00554         }
00555       else if (sRef_isInternalState (sr))
00556         {
00557           if (!sRef_isModified (sr))
00558             {
00559               if (sRefSet_hasStatic (mods))
00560                 {
00561                   ; /* okay */
00562                 }
00563               else
00564                 {
00565                   if (optgenerror 
00566                       (FLG_MUSTMOD,
00567                        message
00568                        ("Function %s specified to modify internal state "
00569                         "but no internal state is modified", 
00570                         uentry_rawName (ue)),
00571                        uentry_whereLast (ue)))
00572                     {
00573                       uentry_showWhereSpecified (le);
00574                     }
00575                 }
00576             }
00577         }
00578       else 
00579         {
00580           if (!sRef_isModified (sr))
00581             {
00582               cstring sname = realParams ? sRef_unparse (sr) : sRef_unparse (sr);
00583               
00584               if (fileloc_isLib (fl) && !realParams)
00585                 {
00586                   voptgenerror 
00587                     (FLG_MUSTMOD,
00588                      message ("Suspect object listed (%q) in modifies "
00589                               "clause of %s not modified: %s", 
00590                               fileloc_unparse (fl),
00591                               uentry_rawName (ue),
00592                               sname),
00593                      uentry_whereLast (ue));
00594                 }               
00595               else
00596                 {
00597                   if (optgenerror 
00598                       (FLG_MUSTMOD,
00599                        message ("Suspect object listed in modifies of %s "
00600                                 "not modified: %s", 
00601                                 uentry_rawName (ue),
00602                                 sname),
00603                        uentry_whereLast (ue)))
00604                     {
00605                       uentry_showWhereSpecified (le);
00606                     }
00607                 }
00608               cstring_free (sname);
00609             }
00610         }
00611     } end_sRefSet_allElements;
00612 }
00613 
00614 void exprNode_checkMacroBody (/*@only@*/ exprNode e)
00615 {
00616   if (!exprNode_isError (e))
00617     {
00618       uentry hdr;
00619 
00620       if (!(context_inFunctionLike () || context_inMacroConstant ()
00621             || context_inMacroUnknown ()))
00622         {
00623           llcontbug 
00624             (message 
00625              ("exprNode_checkMacroBody: not in macro function or constant: %q", 
00626               context_unparse ()));
00627           exprNode_free (e);
00628           return;
00629         }
00630 
00631       hdr = context_getHeader ();
00632       
00633       if (e->kind == XPR_STMTLIST || e->kind == XPR_BODY)
00634         {
00635           voptgenerror 
00636             (FLG_MACROSTMT,
00637              message 
00638              ("Macro %q definition is statement list (recommend "
00639               "do { ... } while (0) constuction to ensure multiple "
00640               "statement macro is syntactic function)",
00641               uentry_getName (hdr)),
00642              fileloc_isDefined (e->loc) ? e->loc : g_currentloc);
00643         }
00644       
00645       if (context_inMacroConstant ())
00646         {
00647           ctype t = uentry_getType (hdr);
00648 
00649           uentry_setDefined (hdr, e->loc);
00650           
00651           if (!(exprNode_matchType (t, e)))
00652             {
00653               cstring uname = uentry_getName (hdr);
00654 
00655               if (cstring_equal (uname, context_getTrueName ())
00656                   || cstring_equal (uname, context_getFalseName ()))
00657                 {
00658                   /* 
00659                   ** We need to do something special to allow FALSE and TRUE
00660                   ** to be defined without reporting errors.  This is a tad
00661                   ** bogus, but otherwise lots of things would break.
00662                   */
00663 
00664 
00665                   llassert (ctype_isManifestBool (t));
00666                   /* Should also check type of e is a reasonable (?) bool type. */
00667                 }
00668               else 
00669                 {
00670                   if (optgenerror 
00671                       (FLG_INCONDEFS,
00672                        message
00673                        ("Constant %q specified as %s, but defined as %s: %s",
00674                         uentry_getName (hdr),
00675                         ctype_unparse (t),
00676                         ctype_unparse (e->typ),
00677                         exprNode_unparse (e)),
00678                        e->loc))
00679                     {
00680                       uentry_showWhereSpecified (hdr);
00681                     }
00682                 }
00683 
00684               cstring_free (uname);
00685             }
00686           else
00687             {
00688               if (context_maybeSet (FLG_NULLSTATE)
00689                   && ctype_isUA(t) 
00690                   && ctype_isRealPointer (t)
00691                   && exprNode_isNullValue (e))
00692                 {
00693                   uentry ue = usymtab_getTypeEntry (ctype_typeId (t));
00694                   sRef   sr = uentry_getSref (ue);
00695                   
00696                   if (!sRef_possiblyNull (sr))
00697                     {
00698                       vgenhinterror 
00699                         (FLG_NULLSTATE,
00700                          message ("Constant %q of non-null type %s defined "
00701                                   "as null: %s",
00702                                   uentry_getName (hdr), ctype_unparse (t),
00703                                   exprNode_unparse (e)),
00704                          message ("If %s can be null, add a /*@null@*/ "
00705                                   "qualifer to its typedef.",
00706                                   ctype_unparse (t)),
00707                          e->loc);
00708                     }
00709                   
00710                   uentry_mergeConstantValue (hdr, e->val);
00711                   e->val = multiVal_undefined;
00712                 }
00713             }
00714         }
00715       else if (context_inMacroFunction () || context_inMacroUnknown ())
00716         {
00717           ctype rettype = context_getRetType ();
00718 
00719           if (context_isMacroMissingParams ())
00720             {
00721               llassert (context_inMacroFunction ());
00722 
00723               /*
00724               ** # define newname oldname
00725               **
00726               ** newname is a function
00727               ** specification of oldname should match
00728               ** specification of newname.
00729               */
00730 
00731               if (!ctype_isFunction (e->typ))
00732                 {
00733                   voptgenerror 
00734                     (FLG_INCONDEFS,
00735                      message ("Function %s defined by unparameterized "
00736                               "macro not corresponding to function",
00737                               context_inFunctionName ()),
00738                      e->loc);
00739                 }
00740               else
00741                 {
00742                   uentry ue = exprNode_getUentry (e);
00743 
00744                   if (uentry_isValid (ue))
00745                     {
00746                       /*
00747                       ** Okay, for now --- should check for consistency
00748                       */
00749                       /*
00750                       ** uentry oldue = usymtab_lookup (cfname);
00751                       */
00752 
00753                       /* check var conformance here! */
00754                     }
00755                   else
00756                     {
00757                       voptgenerror
00758                         (FLG_INCONDEFS,
00759                          message ("Function %s defined by unparameterized "
00760                                   "macro not corresponding to function",
00761                                   context_inFunctionName ()),
00762                          e->loc);
00763                     }
00764                   
00765                   e->typ = ctype_returnValue (e->typ);
00766                   rettype = e->typ; /* avoid aditional errors */
00767                 }
00768             }
00769 
00770           if (ctype_isVoid (rettype) || ctype_isUnknown (rettype))
00771             {
00772              ; /* don't complain when void macros have values */
00773             }       
00774           else if (!exprNode_matchType (rettype, e))
00775             {
00776               if (optgenerror 
00777                   (FLG_INCONDEFS,
00778                    message ("Function %q specified to return %s, "
00779                             "implemented as macro having type %s: %s",
00780                             uentry_getName (hdr),
00781                             ctype_unparse (rettype), ctype_unparse (e->typ),
00782                             exprNode_unparse (e)),
00783                    e->loc))
00784                 {
00785                   uentry_showWhereSpecified (hdr);
00786                 }
00787             }
00788           else
00789             {
00790               switch (e->kind)
00791                 {
00792                   /* these expressions have values: */
00793                 case XPR_PARENS: case XPR_ASSIGN: 
00794                 case XPR_EMPTY: case XPR_VAR:
00795                 case XPR_OP: case XPR_POSTOP: 
00796                 case XPR_PREOP: case XPR_CALL: 
00797                 case XPR_SIZEOFT: case XPR_SIZEOF: 
00798                 case XPR_ALIGNOFT: case XPR_ALIGNOF: 
00799                 case XPR_CAST: case XPR_FETCH: 
00800                 case XPR_COMMA: case XPR_COND: 
00801                 case XPR_ARROW: case XPR_CONST: 
00802                 case XPR_STRINGLITERAL: case XPR_NUMLIT:
00803                 case XPR_FACCESS: case XPR_OFFSETOF:
00804 
00805                   checkReturnTransfer (e, hdr);
00806                   break;
00807 
00808                   /* these expressions don't */
00809                 case XPR_LABEL:
00810                 case XPR_VAARG: case XPR_ITER: 
00811                 case XPR_FOR: case XPR_FORPRED:
00812                 case XPR_GOTO: case XPR_CONTINUE: 
00813                 case XPR_BREAK: case XPR_RETURN:
00814                 case XPR_NULLRETURN: case XPR_IF: 
00815                 case XPR_IFELSE: case XPR_DOWHILE:
00816                 case XPR_WHILE: case XPR_STMT: 
00817                 case XPR_STMTLIST: case XPR_SWITCH:
00818                 case XPR_INIT: case XPR_BODY: 
00819                 case XPR_NODE: case XPR_ITERCALL:
00820                 case XPR_TOK: case XPR_CASE: 
00821                 case XPR_FTCASE: case XPR_FTDEFAULT:
00822                 case XPR_DEFAULT: case XPR_WHILEPRED:
00823                 case XPR_BLOCK: case XPR_INITBLOCK:
00824                   if (optgenerror 
00825                       (FLG_INCONDEFS,
00826                        message ("Function %q specified to return %s, "
00827                                 "implemented as macro with no result: %s",
00828                                 uentry_getName (hdr),
00829                                 ctype_unparse (rettype), 
00830                                 exprNode_unparse (e)),
00831                        e->loc))
00832                     {
00833                       uentry_showWhereSpecified (hdr);
00834                     }
00835                 }
00836             }
00837 
00838           usymtab_checkFinalScope (FALSE);
00839         }
00840       else
00841         {
00842           llbug (message ("exprNode_checkMacroBody: not in macro function: %q", context_unparse ()));
00843         }
00844 
00845       exprNode_free (e);
00846     }
00847 
00848   context_exitFunction ();
00849   return;
00850 }
00851 
00852 void exprNode_checkFunctionBody (exprNode body)
00853 {
00854   if (!exprNode_isError (body))
00855     {
00856       bool noret = context_getFlag (FLG_NORETURN);
00857       bool checkret = exprNode_mustEscape (body);
00858 
00859       if (!checkret 
00860           && noret 
00861           && !exprNode_errorEscape (body)
00862           && context_inRealFunction ()
00863           && ctype_isFunction (context_currentFunctionType ()))
00864         {
00865           ctype tr = ctype_returnValue (context_currentFunctionType ());
00866           
00867           if (!ctype_isFirstVoid (tr)) 
00868             {
00869               if (ctype_isUnknown (tr))
00870                 {
00871                   voptgenerror 
00872                     (FLG_NORETURN,
00873                      cstring_makeLiteral ("Path with no return in function declared to implicity return int"), 
00874                      g_currentloc);
00875                 }
00876               else
00877                 {
00878                   voptgenerror 
00879                     (FLG_NORETURN,
00880                      message ("Path with no return in function declared to return %t", 
00881                               tr),
00882                      g_currentloc);
00883                 }
00884             }
00885         }
00886       
00887       if (!checkret)
00888         {
00889           context_returnFunction ();
00890         }
00891     }
00892 }
00893       
00894 void exprNode_checkFunction (/*@unused@*/ uentry ue, /*@only@*/ exprNode body)
00895 {
00896   exprNode_free (body);
00897   }
00898 
00899 void exprChecks_checkEmptyMacroBody (void)
00900 {
00901   uentry hdr;
00902   
00903   if (!(context_inFunctionLike () || context_inMacroConstant ()
00904         || context_inMacroUnknown ()))
00905     {
00906       llcontbug 
00907         (message ("exprNode_checkEmptyMacroBody: not in macro function or constant: %q", 
00908                   context_unparse ()));
00909       return;
00910     }
00911   
00912   hdr = context_getHeader ();
00913   
00914   beginLine ();
00915   
00916   if (uentry_isFunction (hdr))
00917     {
00918       voptgenerror 
00919         (FLG_MACROEMPTY,
00920          message 
00921          ("Macro definition for %q is empty", uentry_getName (hdr)),
00922          g_currentloc);
00923 
00924       usymtab_checkFinalScope (FALSE);
00925     }
00926 
00927   context_exitFunction ();
00928   return;
00929 }
00930 
00931 void exprNode_checkIterBody (/*@only@*/ exprNode body)
00932 {
00933   context_exitAllClauses ();
00934 
00935   context_exitFunction ();
00936   exprNode_free (body);
00937 }
00938 
00939 void exprNode_checkIterEnd (/*@only@*/ exprNode body)
00940 {
00941   context_exitAllClauses ();
00942   context_exitFunction ();
00943   exprNode_free (body);
00944 }
00945 
00946 static
00947 bool checkModifyAuxAux (sRef s, exprNode f, sRef alias, exprNode err)
00948 {
00949   bool hasMods = context_hasMods ();
00950   flagcode errCode = hasMods ? FLG_MODIFIES : FLG_MODNOMODS;
00951 
00952   if (exprNode_isDefined (f))
00953     {
00954       f->sets = sRefSet_insert (f->sets, s); 
00955     }
00956 
00957   if (context_getFlag (FLG_MODIFIES) 
00958       && (hasMods || context_getFlag (FLG_MODNOMODS)))
00959     {
00960       sRefSet mods = context_modList ();
00961       
00962       if (!sRef_canModify (s, mods))
00963         {
00964           sRef rb = sRef_getRootBase (s);
00965          
00966           
00967           if (sRef_isGlobal (rb))
00968             {
00969               if (!context_checkGlobMod (rb))
00970                 {
00971                                   return FALSE;
00972                 }
00973             }
00974 
00975           if (sRef_isInvalid (alias) || sRef_sameName (s, alias))
00976             {
00977               if (sRef_isLocalVar (sRef_getRootBase (s)))
00978                 {
00979                   voptgenerror 
00980                     (errCode,
00981                      message 
00982                      ("Undocumented modification of internal state (%q): %s", 
00983                       sRef_unparse (s), exprNode_unparse (err)), 
00984                      exprNode_isDefined (f) ? f->loc : g_currentloc);
00985                 }
00986               else
00987                 {
00988                   if (sRef_isSystemState (s))
00989                     {
00990                       if (errCode == FLG_MODNOMODS) 
00991                         {
00992                           if (context_getFlag (FLG_MODNOMODS))
00993                             {
00994                               errCode = FLG_MODFILESYSTEM;
00995                             }
00996                         }
00997                       else
00998                         {
00999                           errCode = FLG_MODFILESYSTEM;
01000                         }
01001                     }
01002 
01003                   voptgenerror 
01004                     (errCode,
01005                      message ("Undocumented modification of %q: %s", 
01006                               sRef_unparse (s), exprNode_unparse (err)), 
01007                      exprNode_isDefined (f) ? f->loc : g_currentloc);
01008                 }
01009               
01010               return TRUE;
01011             }
01012           else
01013             {
01014               if (sRef_isReference (s) && !sRef_isAddress (alias))
01015                 {
01016                   voptgenerror 
01017                     (errCode,
01018                      message
01019                      ("Possible undocumented modification of %q through alias %q: %s", 
01020                       sRef_unparse (s),
01021                       sRef_unparse (alias),
01022                       exprNode_unparse (err)),
01023                      exprNode_isDefined (f) ? f->loc : g_currentloc);
01024                   return TRUE;
01025                 }
01026             }
01027         }
01028     }
01029   else
01030     {
01031       if (context_maybeSet (FLG_MUSTMOD))
01032         {
01033           (void) sRef_canModify (s, context_modList ());
01034         }
01035       
01036       if (sRef_isRefsField (s))
01037         {
01038           sRef_setModified (s);
01039         }
01040     }
01041   
01042   return FALSE;
01043 }
01044 
01045 static
01046 bool checkModifyAux (sRef s, exprNode f, sRef alias, exprNode err)
01047 {
01048   DPRINTF (("Check modify aux: %s", sRef_unparseFull (s)));
01049 
01050   if (sRef_isReference (s) && sRef_isObserver (s) 
01051       && context_maybeSet (FLG_MODOBSERVER))
01052     {    
01053       cstring sname;
01054       
01055       if (sRef_isPointer (s)) 
01056         {
01057           sRef base = sRef_getBase (s);
01058           sname = sRef_unparse (base);
01059         }
01060       else 
01061         {
01062           if (sRef_isAddress (s))
01063             {
01064               sRef p = sRef_constructPointer (s);
01065               sname = sRef_unparse (p);
01066             }
01067           else
01068             {
01069               sname = sRef_unparse (s);
01070             }
01071         }
01072       
01073       if (!sRef_isValid (alias) || sRef_sameName (s, alias))
01074         {
01075           if (sRef_isMeaningful (s))
01076             {
01077               if (optgenerror 
01078                   (FLG_MODOBSERVER,
01079                    message ("Suspect modification of observer %s: %s", 
01080                             sname, exprNode_unparse (err)), 
01081                    exprNode_isDefined (f) ? f->loc : g_currentloc))
01082                 {
01083                   sRef_showExpInfo (s);
01084                 }
01085             }
01086           else
01087             {
01088               voptgenerror 
01089                 (FLG_MODOBSERVER,
01090                  message ("Suspect modification of observer returned by "
01091                           "function call: %s", 
01092                           exprNode_unparse (err)), 
01093                  exprNode_isDefined (f) ? f->loc : g_currentloc);
01094             }
01095         }
01096       else
01097         {
01098           if (optgenerror
01099               (FLG_MODOBSERVER,
01100                message ("Suspect modification of observer %s through alias %q: %s", 
01101                         sname, sRef_unparse (alias), exprNode_unparse (err)), 
01102                exprNode_isDefined (f) ? f->loc : g_currentloc))
01103             {
01104               sRef_showExpInfo (s);
01105             }
01106         }
01107       
01108       cstring_free (sname);
01109     }
01110   
01111   (void) checkModifyAuxAux (s, f, alias, err);
01112   return FALSE;
01113 }
01114 
01115 static
01116 bool checkModifyValAux (sRef s, exprNode f, sRef alias, exprNode err)
01117 {
01118   (void) checkModifyAuxAux (s, f, alias, err);
01119   return FALSE;
01120 }
01121 
01122 static
01123 bool checkCallModifyAux (sRef s, exprNode f, sRef alias, exprNode err)
01124 {
01125   bool result = FALSE;
01126 
01127   if (sRef_isObserver (s) && context_maybeSet (FLG_MODOBSERVER))
01128     {    
01129       sRef p = sRef_isAddress (s) ? sRef_constructPointer (s) : s;
01130       cstring sname = sRef_unparse (p);
01131 
01132       if (!sRef_isValid (alias) || sRef_sameName (s, alias))
01133         {
01134           if (sRef_isMeaningful (s))
01135             {
01136               result = optgenerror 
01137                 (FLG_MODOBSERVER,
01138                  message ("Suspect modification of observer %s: %s", 
01139                           sname, exprNode_unparse (err)), 
01140                  exprNode_isDefined (f) ? f->loc : g_currentloc);
01141             }
01142           else
01143             {
01144               result = optgenerror 
01145                 (FLG_MODOBSERVER,
01146                  message ("Suspect modification of observer returned by "
01147                           "function call: %s", 
01148                           exprNode_unparse (err)), 
01149                  exprNode_isDefined (f) ? f->loc : g_currentloc);
01150             }
01151         }
01152       else
01153         {
01154           result = optgenerror 
01155             (FLG_MODOBSERVER,
01156              message
01157              ("Suspect modification of observer %s through alias %q: %s", 
01158               sname, sRef_unparse (alias), exprNode_unparse (err)), 
01159              exprNode_isDefined (f) ? f->loc : g_currentloc);
01160         }
01161       
01162       cstring_free (sname);
01163     }
01164   else if (context_maybeSet (FLG_MODIFIES))
01165     {
01166       if (!(sRef_canModifyVal (s, context_modList ())))
01167         {
01168           sRef p = sRef_isAddress (s) ? sRef_constructPointer (s) : s;
01169           cstring sname = sRef_unparse (p);
01170           bool hasMods = context_hasMods ();
01171           sRef rb = sRef_getRootBase (s);
01172           flagcode errCode = hasMods ? FLG_MODIFIES : FLG_MODNOMODS;
01173           bool check = TRUE;
01174           
01175           if (sRef_isGlobal (rb))
01176             {
01177               uentry ue = sRef_getUentry (rb);
01178               
01179               /* be more specific here! */
01180               if (!uentry_isCheckedModify (ue))
01181                 {
01182                   check = FALSE;
01183                 }
01184             }
01185           
01186           if (check)
01187             {
01188               if (!sRef_isValid (alias) || sRef_sameName (s, alias))
01189                 {
01190                   if (sRef_isLocalVar (sRef_getRootBase (s)))
01191                     {
01192                       voptgenerror 
01193                         (errCode,
01194                          message 
01195                          ("Undocumented modification of internal "
01196                           "state (%q) through call to %s: %s", 
01197                           sRef_unparse (s), exprNode_unparse (f),
01198                           exprNode_unparse (err)), 
01199                          exprNode_isDefined (f) ? f->loc : g_currentloc);
01200                     }
01201                   else
01202                     {
01203                       if (sRef_isSystemState (s))
01204                         {
01205                           if (errCode == FLG_MODNOMODS) 
01206                             {
01207                               if (context_getFlag (FLG_MODNOMODS))
01208                                 {
01209                                   errCode = FLG_MODFILESYSTEM;
01210                                 }
01211                             }
01212                           else
01213                             {
01214                               errCode = FLG_MODFILESYSTEM;
01215                             }
01216                         }
01217                       
01218                       result = optgenerror 
01219                         (errCode,
01220                          message ("Undocumented modification of %s "
01221                                   "possible from call to %s: %s", 
01222                                   sname,
01223                                   exprNode_unparse (f),
01224                                   exprNode_unparse (err)),
01225                          exprNode_isDefined (f) ? f->loc : g_currentloc);
01226                     }
01227                 }
01228               else
01229                 {
01230                   result = optgenerror
01231                     (errCode,
01232                      message ("Undocumented modification of %s possible "
01233                               "from call to %s (through alias %q): %s", 
01234                               sname,
01235                               exprNode_unparse (f), 
01236                               sRef_unparse (alias), 
01237                               exprNode_unparse (err)),
01238                      exprNode_isDefined (f) ? f->loc : g_currentloc);
01239                 }
01240             }
01241           cstring_free (sname);
01242         }
01243     }
01244   else
01245     {
01246       if (context_maybeSet (FLG_MUSTMOD))
01247         {
01248           (void) sRef_canModifyVal (s, context_modList ());
01249         }
01250     }
01251 
01252   return result;
01253 }
01254 
01255 void exprNode_checkCallModifyVal (sRef s, exprNodeList args, exprNode f, exprNode err)
01256 {
01257   s = sRef_fixBaseParam (s, args);
01258   sRef_aliasCheckPred (checkCallModifyAux, NULL, s, f, err);
01259 }
01260 
01261 void
01262 exprChecks_checkExport (uentry e)
01263 {
01264   if (context_checkExport (e))
01265     {
01266       fileloc fl = uentry_whereDeclared (e);
01267       
01268       if (fileloc_isHeader (fl) && !fileloc_isLib (fl) 
01269           && !fileloc_isImport (fl) && !uentry_isStatic (e))
01270         {
01271           if (uentry_isFunction (e) || 
01272               (uentry_isVariable (e) && ctype_isFunction (uentry_getType (e))))
01273             {
01274               voptgenerror 
01275                 (FLG_EXPORTFCN,
01276                  message ("Function exported, but not specified: %q", 
01277                           uentry_getName (e)),
01278                  fl);
01279             }
01280           else if (uentry_isExpandedMacro (e))
01281             {
01282               voptgenerror
01283                 (FLG_EXPORTMACRO,
01284                  message ("Expanded macro exported, but not specified: %q", 
01285                           uentry_getName (e)),
01286                  fl);
01287             }
01288           else if (uentry_isVariable (e) && !uentry_isParam (e)) 
01289             {
01290               voptgenerror 
01291                 (FLG_EXPORTVAR,
01292                  message ("Variable exported, but not specified: %q", 
01293                           uentry_getName (e)),
01294                  fl);
01295             }
01296           else if (uentry_isEitherConstant (e))
01297             {
01298               voptgenerror 
01299                 (FLG_EXPORTCONST,
01300                  message ("Constant exported, but not specified: %q", 
01301                           uentry_getName (e)),
01302                  fl);
01303             }
01304           else if (uentry_isIter (e) || uentry_isEndIter (e))
01305             {
01306               voptgenerror 
01307                 (FLG_EXPORTITER,
01308                  message ("Iterator exported, but not specified: %q", 
01309                           uentry_getName (e)),
01310                  fl);
01311             }
01312 
01313           else if (uentry_isDatatype (e))
01314             {
01315               ; /* error already reported */
01316             }
01317           else
01318             {
01319               BADEXIT;
01320             }
01321         }
01322     }
01323 }
01324 
01325 static void checkSafeReturnExpr (/*@notnull@*/ exprNode e)
01326 {
01327   ctype tr = ctype_returnValue (context_currentFunctionType ());
01328   ctype te = exprNode_getType (e);
01329 
01330   if (!ctype_forceMatch (tr, te) && !exprNode_matchLiteral (tr, e))
01331     {
01332       (void) gentypeerror
01333         (te, e, tr, exprNode_undefined,
01334          message ("Return value type %t does not match declared type %t: %s",
01335                   te, tr, exprNode_unparse (e)),
01336          e->loc);
01337     }
01338   else
01339     {
01340       sRef ret = e->sref;
01341       uentry rval = context_getHeader ();
01342       sRef resultref = uentry_getSref (rval);
01343 
01344       checkReturnTransfer (e, rval);
01345 
01346       if (!(sRef_isExposed (uentry_getSref (context_getHeader ()))
01347             || sRef_isObserver (uentry_getSref (context_getHeader ())))
01348           && (context_getFlag (FLG_RETALIAS) 
01349               || context_getFlag (FLG_RETEXPOSE)))
01350         {
01351           sRef base = sRef_getRootBase (ret);
01352           ctype rtype = e->typ;
01353 
01354           if (ctype_isUnknown (rtype))
01355             {
01356               rtype = tr;
01357             }
01358 
01359           if (ctype_isVisiblySharable (rtype))
01360             {
01361               if (context_getFlag (FLG_RETALIAS))
01362                 {
01363                   sRef_aliasCheckPred (checkRefGlobParam, NULL, base, 
01364                                        e, exprNode_undefined);
01365                 }
01366               
01367               if (context_getFlag (FLG_RETEXPOSE) && sRef_isIReference (ret) 
01368                   && !sRef_isExposed (resultref) && !sRef_isObserver (resultref))
01369                 {
01370                   sRef_aliasCheckPred (checkRepExposed, NULL, base, e, 
01371                                        exprNode_undefined);
01372                 }
01373             }
01374         }
01375     }
01376 }
01377 

Generated at Fri Nov 3 18:57:40 2000 for LCLint by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000