00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
00037
00038
00039
00040
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 ( exprNode p_e);
00046
00047
00048
00049
00050
00051
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))
00100 {
00101 if (sRefSet_hasRealElement (e->sets)
00102 || sRefSet_hasRealElement (e->msets))
00103 {
00104 ;
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 ;
00145 }
00146 }
00147 }
00148 }
00149 }
00150 }
00151 }
00152
00153 static bool
00154 checkRepExposed (sRef base, exprNode e, sRef alias,
00155 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, exprNode e,
00196 sRef alias, 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 ;
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
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
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 ;
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
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 ;
00554 }
00555 else if (sRef_isInternalState (sr))
00556 {
00557 if (!sRef_isModified (sr))
00558 {
00559 if (sRefSet_hasStatic (mods))
00560 {
00561 ;
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 ( 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
00660
00661
00662
00663
00664
00665 llassert (ctype_isManifestBool (t));
00666
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
00725
00726
00727
00728
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
00748
00749
00750
00751
00752
00753
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;
00767 }
00768 }
00769
00770 if (ctype_isVoid (rettype) || ctype_isUnknown (rettype))
00771 {
00772 ;
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
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
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 ( uentry ue, 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 ( exprNode body)
00932 {
00933 context_exitAllClauses ();
00934
00935 context_exitFunction ();
00936 exprNode_free (body);
00937 }
00938
00939 void exprNode_checkIterEnd ( 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
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 ;
01316 }
01317 else
01318 {
01319 BADEXIT;
01320 }
01321 }
01322 }
01323 }
01324
01325 static void checkSafeReturnExpr ( 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