2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2000 University of Virginia,
4 ** Massachusetts Institute of Technology
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.
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.
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.
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
28 # include "lclintMacros.nf"
30 # include "cgrammar.h"
31 # include "cgrammar_tokens.h"
32 # include "aliasChecks.h"
33 # include "exprChecks.h"
36 ** for now, allow exprChecks to access exprNode.
37 ** may remove this in future
42 static bool checkCallModifyAux (sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
43 static bool checkModifyValAux (sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
44 static bool checkModifyAux (sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
45 static void checkSafeReturnExpr (/*@notnull@*/ exprNode p_e);
48 ** called at end of expression statement
50 ** of e->kind is not an assign, empty, body or modop
51 ** verify the the value is void
56 exprNode_checkStatement (exprNode e)
58 bool hasError = FALSE;
60 if (!exprNode_isError (e))
62 exprKind ek = e->kind;
64 if (ek == XPR_CALL && !(ctype_isRealVoid (e->typ)))
66 if (ctype_isKnown (e->typ))
68 if (ctype_isManifestBool (ctype_realishType (e->typ)))
70 hasError = optgenerror
72 message ("Return value (type %t) ignored: %s",
74 exprNode_unparseFirst (e)),
77 else if (ctype_isDirectInt (e->typ))
79 hasError = optgenerror
81 message ("Return value (type %t) ignored: %s",
83 exprNode_unparseFirst (e)),
88 hasError = optgenerror
90 message ("Return value (type %t) ignored: %s",
92 exprNode_unparseFirst (e)),
98 if (!hasError && !(exprNode_mayEscape (e))
99 && !(e->canBreak)) /* control changes are effects too! */
101 if (sRefSet_hasRealElement (e->sets)
102 || sRefSet_hasRealElement (e->msets))
108 if (sRefSet_isEmpty (e->sets) && sRefSet_isEmpty (e->msets))
112 message ("Statement has no effect: %s",
113 exprNode_unparseFirst (e)),
118 if (context_maybeSet (FLG_NOEFFECTUNCON))
120 if (sRefSet_hasUnconstrained (e->sets))
124 message ("Statement has no effect (possible "
125 "undected modification through "
127 sRefSet_unparseUnconstrained (e->sets),
128 exprNode_unparseFirst (e)),
131 else if (sRefSet_hasUnconstrained (e->msets))
135 message ("Statement has no effect (possible "
136 "undected modification through "
138 sRefSet_unparseUnconstrained (e->msets),
139 exprNode_unparseFirst (e)),
144 ; /* statement has unknown modification */
154 checkRepExposed (sRef base, /*@notnull@*/ exprNode e, sRef alias,
155 /*@unused@*/ exprNode unused)
159 if (sRef_isInvalid (alias) || sRef_sameName (base, alias))
161 btype = sRef_getType (base);
163 if (ctype_isAbstract (btype) && ctype_isVisiblySharable (e->typ))
165 voptgenerror (FLG_RETEXPOSE,
166 message ("Return value exposes rep of %s: %s",
167 ctype_unparse (btype),
168 exprNode_unparse (e)),
175 sRef rbase = sRef_getRootBase (base);
176 btype = sRef_getType (rbase);
178 if (ctype_isAbstract (btype) && ctype_isVisiblySharable (e->typ))
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)),
195 checkRefGlobParam (sRef base, /*@notnull@*/ exprNode e,
196 sRef alias, /*@unused@*/ exprNode unused)
198 if (sRef_isInvalid (alias) || sRef_sameName (base, alias))
202 if (ctype_isUnknown (ct))
204 ct = sRef_getType (base);
207 if (ctype_isVisiblySharable (ct))
209 if (sRef_isGlobal (base))
213 message ("Function returns reference to global %q: %s",
215 exprNode_unparse (e)),
220 else if (sRef_isAnyParam (base))
222 uentryList params = context_getParams ();
223 int paramno = sRef_getParam (base);
225 if (paramno < uentryList_size (params))
227 uentry arg = uentryList_getN (params, paramno);
228 sRef ref = uentry_getSref (arg);
230 if (uentry_isReturned (arg)
232 || sRef_isExposed (ref)
233 || sRef_isRefCounted (ref))
241 message ("Function returns reference to parameter %q: %s",
243 exprNode_unparse (e)),
249 llbuglit ("ret alias: bad paramno");
262 if (ctype_isVisiblySharable (e->typ))
264 if (sRef_isGlobal (base))
268 message ("Function may return reference to global %q through alias %q: %s",
269 sRef_unparse (alias),
271 exprNode_unparse (e)),
275 else if (sRef_isAnyParam (base) && !(sRef_isOnly (base)))
277 uentryList params = context_getParams ();
278 int paramno = sRef_getParam (base);
280 if (paramno < uentryList_size (params))
282 uentry arg = uentryList_getN (params, paramno);
284 if (!uentry_isReturned (arg))
289 ("Function may return reference to parameter %q through alias %q: %s",
291 sRef_unparse (alias),
292 exprNode_unparse (e)),
303 ("Function may return reference to parameter %q through alias %q: %s",
305 sRef_unparse (alias),
306 exprNode_unparse (e)),
323 exprNode_checkModify (exprNode e, exprNode err)
325 llassert (exprNode_isDefined (e));
327 DPRINTF (("Check modify: %s", exprNode_unparse (e)));
329 if (sRef_isValid (e->sref))
331 sRef_aliasCheckPred (checkModifyAux, sRef_isReference, e->sref, e, err);
336 exprNode_checkModifyVal (exprNode e, exprNode err)
338 llassert (exprNode_isDefined (e));
340 DPRINTF (("Check modify val: %s", exprNode_unparse (e)));
342 if (sRef_isValid (e->sref))
344 sRef_aliasCheckPred (checkModifyValAux, sRef_isReference, e->sref, e, err);
349 exprChecks_checkNullReturn (fileloc loc)
351 if (!context_inRealFunction ())
354 llmsg ("exprChecks_checkNullReturnExpr: not in function context");
360 if (ctype_isFunction (context_currentFunctionType ()))
362 ctype tr = ctype_returnValue (context_currentFunctionType ());
364 if (!ctype_isFirstVoid (tr))
366 if (ctype_isUnknown (tr))
370 cstring_makeLiteral ("Empty return in function declared to implicitly return int"),
375 voptgenerror (FLG_CONTROL,
376 message ("Empty return in function declared to return %t", tr),
385 exprNode_checkReturn (exprNode e)
387 if (!exprNode_isError (e))
389 if (!context_inRealFunction ())
391 if (context_inMacro ())
393 llerror (FLG_CONTROL,
394 message ("Macro %s uses return (not functional)",
395 context_inFunctionName ()));
400 llbuglit ("exprNode_checkReturn: not in function context");
406 if (ctype_isFunction (context_currentFunctionType ()))
408 checkSafeReturnExpr (e);
419 exprNode_checkPred (cstring c, exprNode e)
423 if (exprNode_isError (e))
426 ct = exprNode_getType (e);
428 if (exprNode_isAssign (e))
432 message ("Test expression for %s is assignment expression: %s",
433 c, exprNode_unparse (e)),
437 if (ctype_isRealBool (ct))
441 else if (ctype_isRealPointer (ct))
445 message ("Test expression for %s not %s, type %t: %s", c,
446 context_printBoolName (),
447 ct, exprNode_unparse (e)),
450 else if (ctype_isRealInt (ct))
454 message ("Test expression for %s not %s, type %t: %s", c,
455 context_printBoolName (), ct, exprNode_unparse (e)),
462 message ("Test expression for %s not %s, type %t: %s", c,
463 context_printBoolName (), ct, exprNode_unparse (e)),
469 exprChecks_checkUsedGlobs (globSet decl, globSet used)
471 fileloc fl = uentry_whereSpecified (context_getHeader ());
473 if (fileloc_isUndefined (fl))
475 fl = uentry_whereDeclared (context_getHeader ());
478 globSet_allElements (decl, el)
480 if (!globSet_member (used, el))
482 if (sRef_isSpecInternalState (el)
483 || sRef_isNothing (el))
489 cstring sname = sRef_unparse (el);
491 if (fileloc_isLib (fl))
493 voptgenerror (FLG_USEALLGLOBS,
494 message ("Global %s listed (%q) but not used",
495 sname, fileloc_unparse (fl)),
500 voptgenerror (FLG_USEALLGLOBS,
501 message ("Global %s listed but not used", sname),
505 cstring_free (sname);
508 } end_globSet_allElements;
512 exprNode_checkAllMods (sRefSet mods, uentry ue)
514 bool realParams = FALSE;
515 uentry le = context_getHeader ();
516 fileloc fl = uentry_whereSpecified (le);
517 uentryList specParamNames = uentryList_undefined;
518 uentryList paramNames = context_getParams ();
520 if (uentry_isFunction (le))
522 specParamNames = uentry_getParams (le);
524 if (uentryList_isUndefined (specParamNames))
526 ; /* unknown params */
528 else if (uentryList_size (paramNames) != uentryList_size (specParamNames))
531 (message ("exprNode_checkAllMods: parameter lists have different sizes: "
533 uentryList_unparse (paramNames),
534 uentryList_size (paramNames),
535 uentryList_unparse (specParamNames),
536 uentryList_size (specParamNames)));
538 else if (uentryList_size (paramNames) > 0
539 && !uentry_hasRealName (uentryList_getN (specParamNames, 0)))
541 /* loaded from a library */
549 sRefSet_allElements (mods, sr)
551 if (sRef_isNothing (sr) || sRef_isSpecState (sr))
553 ; /* should report on anything? */
555 else if (sRef_isInternalState (sr))
557 if (!sRef_isModified (sr))
559 if (sRefSet_hasStatic (mods))
568 ("Function %s specified to modify internal state "
569 "but no internal state is modified",
570 uentry_rawName (ue)),
571 uentry_whereLast (ue)))
573 uentry_showWhereSpecified (le);
580 if (!sRef_isModified (sr))
582 cstring sname = realParams ? sRef_unparse (sr) : sRef_unparse (sr);
584 if (fileloc_isLib (fl) && !realParams)
588 message ("Suspect object listed (%q) in modifies "
589 "clause of %s not modified: %s",
590 fileloc_unparse (fl),
593 uentry_whereLast (ue));
599 message ("Suspect object listed in modifies of %s "
603 uentry_whereLast (ue)))
605 uentry_showWhereSpecified (le);
608 cstring_free (sname);
611 } end_sRefSet_allElements;
614 void exprNode_checkMacroBody (/*@only@*/ exprNode e)
616 if (!exprNode_isError (e))
620 if (!(context_inFunctionLike () || context_inMacroConstant ()
621 || context_inMacroUnknown ()))
625 ("exprNode_checkMacroBody: not in macro function or constant: %q",
626 context_unparse ()));
631 hdr = context_getHeader ();
633 if (e->kind == XPR_STMTLIST || e->kind == XPR_BODY)
638 ("Macro %q definition is statement list (recommend "
639 "do { ... } while (0) constuction to ensure multiple "
640 "statement macro is syntactic function)",
641 uentry_getName (hdr)),
642 fileloc_isDefined (e->loc) ? e->loc : g_currentloc);
645 if (context_inMacroConstant ())
647 ctype t = uentry_getType (hdr);
649 uentry_setDefined (hdr, e->loc);
651 if (!(exprNode_matchType (t, e)))
653 cstring uname = uentry_getName (hdr);
655 if (cstring_equal (uname, context_getTrueName ())
656 || cstring_equal (uname, context_getFalseName ()))
659 ** We need to do something special to allow FALSE and TRUE
660 ** to be defined without reporting errors. This is a tad
661 ** bogus, but otherwise lots of things would break.
665 llassert (ctype_isManifestBool (t));
666 /* Should also check type of e is a reasonable (?) bool type. */
673 ("Constant %q specified as %s, but defined as %s: %s",
674 uentry_getName (hdr),
676 ctype_unparse (e->typ),
677 exprNode_unparse (e)),
680 uentry_showWhereSpecified (hdr);
684 cstring_free (uname);
688 if (context_maybeSet (FLG_NULLSTATE)
690 && ctype_isRealPointer (t)
691 && exprNode_isNullValue (e))
693 uentry ue = usymtab_getTypeEntry (ctype_typeId (t));
694 sRef sr = uentry_getSref (ue);
696 if (!sRef_possiblyNull (sr))
700 message ("Constant %q of non-null type %s defined "
702 uentry_getName (hdr), ctype_unparse (t),
703 exprNode_unparse (e)),
704 message ("If %s can be null, add a /*@null@*/ "
705 "qualifer to its typedef.",
710 uentry_mergeConstantValue (hdr, e->val);
711 e->val = multiVal_undefined;
715 else if (context_inMacroFunction () || context_inMacroUnknown ())
717 ctype rettype = context_getRetType ();
719 if (context_isMacroMissingParams ())
721 llassert (context_inMacroFunction ());
724 ** # define newname oldname
726 ** newname is a function
727 ** specification of oldname should match
728 ** specification of newname.
731 if (!ctype_isFunction (e->typ))
735 message ("Function %s defined by unparameterized "
736 "macro not corresponding to function",
737 context_inFunctionName ()),
742 uentry ue = exprNode_getUentry (e);
744 if (uentry_isValid (ue))
747 ** Okay, for now --- should check for consistency
750 ** uentry oldue = usymtab_lookup (cfname);
753 /* check var conformance here! */
759 message ("Function %s defined by unparameterized "
760 "macro not corresponding to function",
761 context_inFunctionName ()),
765 e->typ = ctype_returnValue (e->typ);
766 rettype = e->typ; /* avoid aditional errors */
770 if (ctype_isVoid (rettype) || ctype_isUnknown (rettype))
772 ; /* don't complain when void macros have values */
774 else if (!exprNode_matchType (rettype, e))
778 message ("Function %q specified to return %s, "
779 "implemented as macro having type %s: %s",
780 uentry_getName (hdr),
781 ctype_unparse (rettype), ctype_unparse (e->typ),
782 exprNode_unparse (e)),
785 uentry_showWhereSpecified (hdr);
792 /* these expressions have values: */
793 case XPR_PARENS: case XPR_ASSIGN:
794 case XPR_EMPTY: case XPR_VAR:
795 case XPR_OP: case XPR_POSTOP:
796 case XPR_PREOP: case XPR_CALL:
797 case XPR_SIZEOFT: case XPR_SIZEOF:
798 case XPR_ALIGNOFT: case XPR_ALIGNOF:
799 case XPR_CAST: case XPR_FETCH:
800 case XPR_COMMA: case XPR_COND:
801 case XPR_ARROW: case XPR_CONST:
802 case XPR_STRINGLITERAL: case XPR_NUMLIT:
803 case XPR_FACCESS: case XPR_OFFSETOF:
805 checkReturnTransfer (e, hdr);
808 /* these expressions don't */
810 case XPR_VAARG: case XPR_ITER:
811 case XPR_FOR: case XPR_FORPRED:
812 case XPR_GOTO: case XPR_CONTINUE:
813 case XPR_BREAK: case XPR_RETURN:
814 case XPR_NULLRETURN: case XPR_IF:
815 case XPR_IFELSE: case XPR_DOWHILE:
816 case XPR_WHILE: case XPR_STMT:
817 case XPR_STMTLIST: case XPR_SWITCH:
818 case XPR_INIT: case XPR_BODY:
819 case XPR_NODE: case XPR_ITERCALL:
820 case XPR_TOK: case XPR_CASE:
821 case XPR_FTCASE: case XPR_FTDEFAULT:
822 case XPR_DEFAULT: case XPR_WHILEPRED:
823 case XPR_BLOCK: case XPR_INITBLOCK:
826 message ("Function %q specified to return %s, "
827 "implemented as macro with no result: %s",
828 uentry_getName (hdr),
829 ctype_unparse (rettype),
830 exprNode_unparse (e)),
833 uentry_showWhereSpecified (hdr);
838 usymtab_checkFinalScope (FALSE);
842 llbug (message ("exprNode_checkMacroBody: not in macro function: %q", context_unparse ()));
848 context_exitFunction ();
852 void exprNode_checkFunctionBody (exprNode body)
854 if (!exprNode_isError (body))
856 bool noret = context_getFlag (FLG_NORETURN);
857 bool checkret = exprNode_mustEscape (body);
861 && !exprNode_errorEscape (body)
862 && context_inRealFunction ()
863 && ctype_isFunction (context_currentFunctionType ()))
865 ctype tr = ctype_returnValue (context_currentFunctionType ());
867 if (!ctype_isFirstVoid (tr))
869 if (ctype_isUnknown (tr))
873 cstring_makeLiteral ("Path with no return in function declared to implicity return int"),
880 message ("Path with no return in function declared to return %t",
889 context_returnFunction ();
894 void exprNode_checkFunction (/*@unused@*/ uentry ue, /*@only@*/ exprNode body)
897 /* drl added 8-8-2000 */
899 exprNode_generateConstraints (body);
901 c = uentry_getFcnPreconditions (ue);
902 DPRINTF(("function constraints\n"));
903 DPRINTF (("\n\n\n\n\n\n\n"));
905 context_enterInnerContext ();
910 DPRINTF ( (message ("Function preconditions are %s \n\n\n\n\n", constraintList_printDetailed (c) ) ) );
912 t = reflectChanges (body->requiresConstraints, constraintList_copy (c) );
913 body->requiresConstraints = constraintList_copy (t);
915 DPRINTF ( (message ("The body has the required cosntraints: %s", constraintList_printDetailed (t) ) ) );
916 t = constraintList_mergeEnsures (c, body->ensuresConstraints);
918 body->ensuresConstraints = constraintList_copy (t);
920 DPRINTF ( (message ("The body has the ensures constraints: %s", constraintList_printDetailed (t) ) ) );
925 TPRINTF((message ("The Function %s has the preconditions %s", uentry_unparse(ue), constraintList_printDetailed(c) ) ) );
929 TPRINTF((message ("The Function %s has no preconditions", uentry_unparse(ue) ) ) );
932 printf ("The required constraints are:\n%s", constraintList_printDetailed(body->requiresConstraints) );
933 printf ("The ensures constraints are:\n%s", constraintList_printDetailed(body->ensuresConstraints) );
935 context_exitInnerPlain();
936 /* exprNode_free (body); */
939 void exprChecks_checkEmptyMacroBody (void)
943 if (!(context_inFunctionLike () || context_inMacroConstant ()
944 || context_inMacroUnknown ()))
947 (message ("exprNode_checkEmptyMacroBody: not in macro function or constant: %q",
948 context_unparse ()));
952 hdr = context_getHeader ();
956 if (uentry_isFunction (hdr))
961 ("Macro definition for %q is empty", uentry_getName (hdr)),
964 usymtab_checkFinalScope (FALSE);
967 context_exitFunction ();
971 void exprNode_checkIterBody (/*@only@*/ exprNode body)
973 context_exitAllClauses ();
975 context_exitFunction ();
976 exprNode_free (body);
979 void exprNode_checkIterEnd (/*@only@*/ exprNode body)
981 context_exitAllClauses ();
982 context_exitFunction ();
983 exprNode_free (body);
987 bool checkModifyAuxAux (sRef s, exprNode f, sRef alias, exprNode err)
989 bool hasMods = context_hasMods ();
990 flagcode errCode = hasMods ? FLG_MODIFIES : FLG_MODNOMODS;
992 if (exprNode_isDefined (f))
994 f->sets = sRefSet_insert (f->sets, s);
997 if (context_getFlag (FLG_MODIFIES)
998 && (hasMods || context_getFlag (FLG_MODNOMODS)))
1000 sRefSet mods = context_modList ();
1002 if (!sRef_canModify (s, mods))
1004 sRef rb = sRef_getRootBase (s);
1007 if (sRef_isGlobal (rb))
1009 if (!context_checkGlobMod (rb))
1015 if (sRef_isInvalid (alias) || sRef_sameName (s, alias))
1017 if (sRef_isLocalVar (sRef_getRootBase (s)))
1022 ("Undocumented modification of internal state (%q): %s",
1023 sRef_unparse (s), exprNode_unparse (err)),
1024 exprNode_isDefined (f) ? f->loc : g_currentloc);
1028 if (sRef_isSystemState (s))
1030 if (errCode == FLG_MODNOMODS)
1032 if (context_getFlag (FLG_MODNOMODS))
1034 errCode = FLG_MODFILESYSTEM;
1039 errCode = FLG_MODFILESYSTEM;
1045 message ("Undocumented modification of %q: %s",
1046 sRef_unparse (s), exprNode_unparse (err)),
1047 exprNode_isDefined (f) ? f->loc : g_currentloc);
1054 if (sRef_isReference (s) && !sRef_isAddress (alias))
1059 ("Possible undocumented modification of %q through alias %q: %s",
1061 sRef_unparse (alias),
1062 exprNode_unparse (err)),
1063 exprNode_isDefined (f) ? f->loc : g_currentloc);
1071 if (context_maybeSet (FLG_MUSTMOD))
1073 (void) sRef_canModify (s, context_modList ());
1076 if (sRef_isRefsField (s))
1078 sRef_setModified (s);
1086 bool checkModifyAux (sRef s, exprNode f, sRef alias, exprNode err)
1088 DPRINTF (("Check modify aux: %s", sRef_unparseFull (s)));
1090 if (sRef_isReference (s) && sRef_isObserver (s)
1091 && context_maybeSet (FLG_MODOBSERVER))
1095 if (sRef_isPointer (s))
1097 sRef base = sRef_getBase (s);
1098 sname = sRef_unparse (base);
1102 if (sRef_isAddress (s))
1104 sRef p = sRef_constructPointer (s);
1105 sname = sRef_unparse (p);
1109 sname = sRef_unparse (s);
1113 if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1115 if (sRef_isMeaningful (s))
1119 message ("Suspect modification of observer %s: %s",
1120 sname, exprNode_unparse (err)),
1121 exprNode_isDefined (f) ? f->loc : g_currentloc))
1123 sRef_showExpInfo (s);
1130 message ("Suspect modification of observer returned by "
1131 "function call: %s",
1132 exprNode_unparse (err)),
1133 exprNode_isDefined (f) ? f->loc : g_currentloc);
1140 message ("Suspect modification of observer %s through alias %q: %s",
1141 sname, sRef_unparse (alias), exprNode_unparse (err)),
1142 exprNode_isDefined (f) ? f->loc : g_currentloc))
1144 sRef_showExpInfo (s);
1148 cstring_free (sname);
1151 (void) checkModifyAuxAux (s, f, alias, err);
1156 bool checkModifyValAux (sRef s, exprNode f, sRef alias, exprNode err)
1158 (void) checkModifyAuxAux (s, f, alias, err);
1163 bool checkCallModifyAux (sRef s, exprNode f, sRef alias, exprNode err)
1165 bool result = FALSE;
1167 if (sRef_isObserver (s) && context_maybeSet (FLG_MODOBSERVER))
1169 sRef p = sRef_isAddress (s) ? sRef_constructPointer (s) : s;
1170 cstring sname = sRef_unparse (p);
1172 if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1174 if (sRef_isMeaningful (s))
1176 result = optgenerror
1178 message ("Suspect modification of observer %s: %s",
1179 sname, exprNode_unparse (err)),
1180 exprNode_isDefined (f) ? f->loc : g_currentloc);
1184 result = optgenerror
1186 message ("Suspect modification of observer returned by "
1187 "function call: %s",
1188 exprNode_unparse (err)),
1189 exprNode_isDefined (f) ? f->loc : g_currentloc);
1194 result = optgenerror
1197 ("Suspect modification of observer %s through alias %q: %s",
1198 sname, sRef_unparse (alias), exprNode_unparse (err)),
1199 exprNode_isDefined (f) ? f->loc : g_currentloc);
1202 cstring_free (sname);
1204 else if (context_maybeSet (FLG_MODIFIES))
1206 if (!(sRef_canModifyVal (s, context_modList ())))
1208 sRef p = sRef_isAddress (s) ? sRef_constructPointer (s) : s;
1209 cstring sname = sRef_unparse (p);
1210 bool hasMods = context_hasMods ();
1211 sRef rb = sRef_getRootBase (s);
1212 flagcode errCode = hasMods ? FLG_MODIFIES : FLG_MODNOMODS;
1215 if (sRef_isGlobal (rb))
1217 uentry ue = sRef_getUentry (rb);
1219 /* be more specific here! */
1220 if (!uentry_isCheckedModify (ue))
1228 if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1230 if (sRef_isLocalVar (sRef_getRootBase (s)))
1235 ("Undocumented modification of internal "
1236 "state (%q) through call to %s: %s",
1237 sRef_unparse (s), exprNode_unparse (f),
1238 exprNode_unparse (err)),
1239 exprNode_isDefined (f) ? f->loc : g_currentloc);
1243 if (sRef_isSystemState (s))
1245 if (errCode == FLG_MODNOMODS)
1247 if (context_getFlag (FLG_MODNOMODS))
1249 errCode = FLG_MODFILESYSTEM;
1254 errCode = FLG_MODFILESYSTEM;
1258 result = optgenerror
1260 message ("Undocumented modification of %s "
1261 "possible from call to %s: %s",
1263 exprNode_unparse (f),
1264 exprNode_unparse (err)),
1265 exprNode_isDefined (f) ? f->loc : g_currentloc);
1270 result = optgenerror
1272 message ("Undocumented modification of %s possible "
1273 "from call to %s (through alias %q): %s",
1275 exprNode_unparse (f),
1276 sRef_unparse (alias),
1277 exprNode_unparse (err)),
1278 exprNode_isDefined (f) ? f->loc : g_currentloc);
1281 cstring_free (sname);
1286 if (context_maybeSet (FLG_MUSTMOD))
1288 (void) sRef_canModifyVal (s, context_modList ());
1295 void exprNode_checkCallModifyVal (sRef s, exprNodeList args, exprNode f, exprNode err)
1297 s = sRef_fixBaseParam (s, args);
1298 sRef_aliasCheckPred (checkCallModifyAux, NULL, s, f, err);
1302 exprChecks_checkExport (uentry e)
1304 if (context_checkExport (e))
1306 fileloc fl = uentry_whereDeclared (e);
1308 if (fileloc_isHeader (fl) && !fileloc_isLib (fl)
1309 && !fileloc_isImport (fl) && !uentry_isStatic (e))
1311 if (uentry_isFunction (e) ||
1312 (uentry_isVariable (e) && ctype_isFunction (uentry_getType (e))))
1316 message ("Function exported, but not specified: %q",
1317 uentry_getName (e)),
1320 else if (uentry_isExpandedMacro (e))
1324 message ("Expanded macro exported, but not specified: %q",
1325 uentry_getName (e)),
1328 else if (uentry_isVariable (e) && !uentry_isParam (e))
1332 message ("Variable exported, but not specified: %q",
1333 uentry_getName (e)),
1336 else if (uentry_isEitherConstant (e))
1340 message ("Constant exported, but not specified: %q",
1341 uentry_getName (e)),
1344 else if (uentry_isIter (e) || uentry_isEndIter (e))
1348 message ("Iterator exported, but not specified: %q",
1349 uentry_getName (e)),
1353 else if (uentry_isDatatype (e))
1355 ; /* error already reported */
1365 static void checkSafeReturnExpr (/*@notnull@*/ exprNode e)
1367 ctype tr = ctype_returnValue (context_currentFunctionType ());
1368 ctype te = exprNode_getType (e);
1370 if (!ctype_forceMatch (tr, te) && !exprNode_matchLiteral (tr, e))
1373 (te, e, tr, exprNode_undefined,
1374 message ("Return value type %t does not match declared type %t: %s",
1375 te, tr, exprNode_unparse (e)),
1381 uentry rval = context_getHeader ();
1382 sRef resultref = uentry_getSref (rval);
1384 checkReturnTransfer (e, rval);
1386 if (!(sRef_isExposed (uentry_getSref (context_getHeader ()))
1387 || sRef_isObserver (uentry_getSref (context_getHeader ())))
1388 && (context_getFlag (FLG_RETALIAS)
1389 || context_getFlag (FLG_RETEXPOSE)))
1391 sRef base = sRef_getRootBase (ret);
1392 ctype rtype = e->typ;
1394 if (ctype_isUnknown (rtype))
1399 if (ctype_isVisiblySharable (rtype))
1401 if (context_getFlag (FLG_RETALIAS))
1403 sRef_aliasCheckPred (checkRefGlobParam, NULL, base,
1404 e, exprNode_undefined);
1407 if (context_getFlag (FLG_RETEXPOSE) && sRef_isIReference (ret)
1408 && !sRef_isExposed (resultref) && !sRef_isObserver (resultref))
1410 sRef_aliasCheckPred (checkRepExposed, NULL, base, e,
1411 exprNode_undefined);