2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2001 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://www.splint.org
28 # include "lclintMacros.nf"
30 # include "cgrammar.h"
31 # include "cgrammar_tokens.h"
32 # include "transferChecks.h"
33 # include "exprChecks.h"
36 ** for now, allow exprChecks to access exprNode.
37 ** may remove this in future
42 static bool checkCallModifyAux (/*@exposed@*/ sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
43 static bool checkModifyValAux (/*@exposed@*/ sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
44 static bool checkModifyAux (/*@exposed@*/ sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
45 static void checkSafeReturnExpr (/*@notnull@*/ exprNode p_e);
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_isFileOrGlobalScope (base))
211 uentry fcn = context_getHeader ();
212 bool noerror = FALSE;
214 if (uentry_isValid (fcn) && uentry_isFunction (fcn))
216 sRef res = uentry_getSref (fcn);
218 /* If result is dependent and global is owned, this is okay... */
219 if (sRef_isDependent (res)
220 && sRef_isOwned (base))
231 message ("Function returns reference to global %q: %s",
233 exprNode_unparse (e)),
239 else if (sRef_isAnyParam (base))
241 uentryList params = context_getParams ();
242 int paramno = sRef_getParam (base);
244 if (paramno < uentryList_size (params))
246 uentry arg = uentryList_getN (params, paramno);
247 sRef ref = uentry_getSref (arg);
249 if (uentry_isReturned (arg)
251 || sRef_isExposed (ref)
252 || sRef_isRefCounted (ref))
260 message ("Function returns reference to parameter %q: %s",
262 exprNode_unparse (e)),
268 llbuglit ("ret alias: bad paramno");
281 if (ctype_isVisiblySharable (e->typ))
283 if (sRef_isFileOrGlobalScope (base))
287 message ("Function may return reference to global %q through alias %q: %s",
288 sRef_unparse (alias),
290 exprNode_unparse (e)),
294 else if (sRef_isAnyParam (base) && !(sRef_isOnly (base)))
296 uentryList params = context_getParams ();
297 int paramno = sRef_getParam (base);
299 if (paramno < uentryList_size (params))
301 uentry arg = uentryList_getN (params, paramno);
303 if (!uentry_isReturned (arg))
308 ("Function may return reference to parameter %q through alias %q: %s",
310 sRef_unparse (alias),
311 exprNode_unparse (e)),
322 ("Function may return reference to parameter %q through alias %q: %s",
324 sRef_unparse (alias),
325 exprNode_unparse (e)),
342 exprNode_checkModify (exprNode e, exprNode err)
344 llassert (exprNode_isDefined (e));
346 DPRINTF (("Check modify: %s", exprNode_unparse (e)));
348 if (sRef_isValid (e->sref))
350 sRef_aliasCheckPred (checkModifyAux, sRef_isReference, e->sref, e, err);
355 exprNode_checkModifyVal (exprNode e, exprNode err)
357 llassert (exprNode_isDefined (e));
359 DPRINTF (("Check modify val: %s", exprNode_unparse (e)));
361 if (sRef_isValid (e->sref))
363 sRef_aliasCheckPred (checkModifyValAux, sRef_isReference, e->sref, e, err);
368 exprChecks_checkNullReturn (fileloc loc)
370 if (!context_inRealFunction ())
373 llmsg ("exprChecks_checkNullReturnExpr: not in function context");
379 if (ctype_isFunction (context_currentFunctionType ()))
381 ctype tr = ctype_getReturnType (context_currentFunctionType ());
383 if (!ctype_isFirstVoid (tr))
385 if (ctype_isUnknown (tr))
389 cstring_makeLiteral ("Empty return in function declared to implicitly return int"),
394 voptgenerror (FLG_CONTROL,
395 message ("Empty return in function declared to return %t", tr),
404 exprNode_checkReturn (exprNode e)
406 if (!exprNode_isError (e))
408 if (!context_inRealFunction ())
410 if (context_inMacro ())
412 llerror (FLG_CONTROL,
413 message ("Macro %s uses return (not functional)",
414 context_inFunctionName ()));
419 llbuglit ("exprNode_checkReturn: not in function context");
425 if (ctype_isFunction (context_currentFunctionType ()))
427 checkSafeReturnExpr (e);
438 exprNode_checkPred (cstring c, exprNode e)
442 if (exprNode_isError (e))
445 ct = exprNode_getType (e);
447 if (exprNode_isAssign (e))
451 message ("Test expression for %s is assignment expression: %s",
452 c, exprNode_unparse (e)),
456 if (ctype_isRealBool (ct) || ctype_isUnknown (ct))
457 /* evs 2000-12-20 added || ctype_isUnknown to avoid spurious messages */
461 else if (ctype_isRealPointer (ct))
465 message ("Test expression for %s not %s, type %t: %s", c,
466 context_printBoolName (),
467 ct, exprNode_unparse (e)),
470 else if (ctype_isRealInt (ct))
474 message ("Test expression for %s not %s, type %t: %s", c,
475 context_printBoolName (), ct, exprNode_unparse (e)),
482 message ("Test expression for %s not %s, type %t: %s", c,
483 context_printBoolName (), ct, exprNode_unparse (e)),
489 exprChecks_checkUsedGlobs (globSet decl, globSet used)
491 fileloc fl = uentry_whereSpecified (context_getHeader ());
493 if (fileloc_isUndefined (fl))
495 fl = uentry_whereDeclared (context_getHeader ());
498 globSet_allElements (decl, el)
500 if (!globSet_member (used, el))
502 if (sRef_isSpecInternalState (el)
503 || sRef_isNothing (el))
509 cstring sname = sRef_unparse (el);
511 if (fileloc_isLib (fl))
513 voptgenerror (FLG_USEALLGLOBS,
514 message ("Global %s listed (%q) but not used",
515 sname, fileloc_unparse (fl)),
520 voptgenerror (FLG_USEALLGLOBS,
521 message ("Global %s listed but not used", sname),
525 cstring_free (sname);
528 } end_globSet_allElements;
532 exprNode_checkAllMods (sRefSet mods, uentry ue)
534 bool realParams = FALSE;
535 uentry le = context_getHeader ();
536 fileloc fl = uentry_whereSpecified (le);
537 uentryList specParamNames = uentryList_undefined;
538 uentryList paramNames = context_getParams ();
540 if (uentry_isFunction (le))
542 specParamNames = uentry_getParams (le);
544 if (uentryList_isUndefined (specParamNames))
546 ; /* unknown params */
548 else if (uentryList_size (paramNames) != uentryList_size (specParamNames))
551 (message ("exprNode_checkAllMods: parameter lists have different sizes: "
553 uentryList_unparse (paramNames),
554 uentryList_size (paramNames),
555 uentryList_unparse (specParamNames),
556 uentryList_size (specParamNames)));
558 else if (uentryList_size (paramNames) > 0
559 && !uentry_hasRealName (uentryList_getN (specParamNames, 0)))
561 /* loaded from a library */
569 sRefSet_allElements (mods, sr)
571 if (sRef_isNothing (sr) || sRef_isSpecState (sr))
573 ; /* should report on anything? */
575 else if (sRef_isInternalState (sr))
577 if (!sRef_isModified (sr))
579 if (sRefSet_hasStatic (mods))
588 ("Function %s specified to modify internal state "
589 "but no internal state is modified",
590 uentry_rawName (ue)),
591 uentry_whereLast (ue)))
593 uentry_showWhereSpecified (le);
600 if (!sRef_isModified (sr))
602 cstring sname = realParams ? sRef_unparse (sr) : sRef_unparse (sr);
604 if (fileloc_isLib (fl) && !realParams)
608 message ("Suspect object listed (%q) in modifies "
609 "clause of %s not modified: %s",
610 fileloc_unparse (fl),
613 uentry_whereLast (ue));
619 message ("Suspect object listed in modifies of %s "
623 uentry_whereLast (ue)))
625 uentry_showWhereSpecified (le);
628 cstring_free (sname);
631 } end_sRefSet_allElements;
634 void exprNode_checkMacroBody (/*@only@*/ exprNode e)
636 if (!exprNode_isError (e))
640 if (!(context_inFunctionLike () || context_inMacroConstant ()
641 || context_inUnknownMacro ()))
645 ("exprNode_checkMacroBody: not in macro function or constant: %q",
646 context_unparse ()));
651 hdr = context_getHeader ();
653 if (e->kind == XPR_STMTLIST || e->kind == XPR_BODY)
658 ("Macro %q definition is statement list (recommend "
659 "do { ... } while (0) constuction to ensure multiple "
660 "statement macro is syntactic function)",
661 uentry_getName (hdr)),
662 fileloc_isDefined (e->loc) ? e->loc : g_currentloc);
665 if (context_inMacroConstant ())
667 ctype t = uentry_getType (hdr);
669 uentry_setDefined (hdr, e->loc);
671 if (!(exprNode_matchType (t, e)))
673 cstring uname = uentry_getName (hdr);
675 if (cstring_equal (uname, context_getTrueName ())
676 || cstring_equal (uname, context_getFalseName ()))
679 ** We need to do something special to allow FALSE and TRUE
680 ** to be defined without reporting errors. This is a tad
681 ** bogus, but otherwise lots of things would break.
685 llassert (ctype_isManifestBool (t));
686 /* Should also check type of e is a reasonable (?) bool type. */
693 ("Constant %q specified as %s, but defined as %s: %s",
694 uentry_getName (hdr),
696 ctype_unparse (e->typ),
697 exprNode_unparse (e)),
700 uentry_showWhereSpecified (hdr);
704 cstring_free (uname);
708 if (context_maybeSet (FLG_NULLSTATE)
710 && ctype_isRealPointer (t)
711 && exprNode_isNullValue (e))
713 uentry ue = usymtab_getTypeEntry (ctype_typeId (t));
714 sRef sr = uentry_getSref (ue);
716 if (!sRef_possiblyNull (sr))
720 message ("Constant %q of non-null type %s defined "
722 uentry_getName (hdr), ctype_unparse (t),
723 exprNode_unparse (e)),
724 message ("If %s can be null, add a /*@null@*/ "
725 "qualifer to its typedef.",
730 uentry_mergeConstantValue (hdr, e->val);
731 e->val = multiVal_undefined;
735 else if (context_inMacroFunction () || context_inUnknownMacro ())
737 ctype rettype = context_getRetType ();
739 if (context_isMacroMissingParams ())
741 llassert (context_inMacroFunction ());
744 ** # define newname oldname
746 ** newname is a function
747 ** specification of oldname should match
748 ** specification of newname.
751 if (!ctype_isFunction (e->typ))
755 message ("Function %s defined by unparameterized "
756 "macro not corresponding to function",
757 context_inFunctionName ()),
762 uentry ue = exprNode_getUentry (e);
764 if (uentry_isValid (ue))
767 ** Okay, for now --- should check for consistency
770 ** uentry oldue = usymtab_lookup (cfname);
773 /* check var conformance here! */
779 message ("Function %s defined by unparameterized "
780 "macro not corresponding to function",
781 context_inFunctionName ()),
785 e->typ = ctype_getReturnType (e->typ);
786 rettype = e->typ; /* avoid aditional errors */
790 if (ctype_isVoid (rettype) || ctype_isUnknown (rettype))
792 ; /* don't complain when void macros have values */
794 else if (!exprNode_matchType (rettype, e))
798 message ("Function %q specified to return %s, "
799 "implemented as macro having type %s: %s",
800 uentry_getName (hdr),
801 ctype_unparse (rettype), ctype_unparse (e->typ),
802 exprNode_unparse (e)),
805 uentry_showWhereSpecified (hdr);
812 /* these expressions have values: */
813 case XPR_PARENS: case XPR_ASSIGN:
814 case XPR_EMPTY: case XPR_VAR:
815 case XPR_OP: case XPR_POSTOP:
816 case XPR_PREOP: case XPR_CALL:
817 case XPR_SIZEOFT: case XPR_SIZEOF:
818 case XPR_ALIGNOFT: case XPR_ALIGNOF:
819 case XPR_CAST: case XPR_FETCH:
820 case XPR_COMMA: case XPR_COND:
821 case XPR_ARROW: case XPR_CONST:
822 case XPR_STRINGLITERAL: case XPR_NUMLIT:
823 case XPR_FACCESS: case XPR_OFFSETOF:
825 checkReturnTransfer (e, hdr);
828 /* these expressions don't */
830 case XPR_VAARG: case XPR_ITER:
831 case XPR_FOR: case XPR_FORPRED:
832 case XPR_GOTO: case XPR_CONTINUE:
833 case XPR_BREAK: case XPR_RETURN:
834 case XPR_NULLRETURN: case XPR_IF:
835 case XPR_IFELSE: case XPR_DOWHILE:
836 case XPR_WHILE: case XPR_STMT:
837 case XPR_STMTLIST: case XPR_SWITCH:
838 case XPR_INIT: case XPR_BODY:
839 case XPR_NODE: case XPR_ITERCALL:
840 case XPR_TOK: case XPR_CASE:
841 case XPR_FTCASE: case XPR_FTDEFAULT:
842 case XPR_DEFAULT: case XPR_WHILEPRED:
843 case XPR_BLOCK: case XPR_INITBLOCK:
846 message ("Function %q specified to return %s, "
847 "implemented as macro with no result: %s",
848 uentry_getName (hdr),
849 ctype_unparse (rettype),
850 exprNode_unparse (e)),
853 uentry_showWhereSpecified (hdr);
858 usymtab_checkFinalScope (FALSE);
862 llbug (message ("exprNode_checkMacroBody: not in macro function: %q", context_unparse ()));
868 context_exitFunction ();
872 void exprNode_checkFunctionBody (exprNode body)
874 if (!exprNode_isError (body))
876 bool noret = context_getFlag (FLG_NORETURN);
877 bool checkret = exprNode_mustEscape (body);
881 && !exprNode_errorEscape (body)
882 && context_inRealFunction ()
883 && ctype_isFunction (context_currentFunctionType ()))
885 ctype tr = ctype_getReturnType (context_currentFunctionType ());
887 if (!ctype_isFirstVoid (tr))
889 if (ctype_isUnknown (tr))
893 cstring_makeLiteral ("Path with no return in function declared to implicity return int"),
900 message ("Path with no return in function declared to return %t",
909 context_returnFunction ();
916 void exprNode_checkFunction (/*@unused@*/ uentry ue, /*@only@*/ exprNode fcnBody)
918 constraintList c, t, post;
919 constraintList c2, fix;
920 constraintList implicitFcnConstraints;
922 /*@owned@*/ exprNode body;
924 context_enterInnerContext ();
929 if we're not going to be printing any errors for buffer overflows
930 we can skip the checking to improve performance
932 FLG_DEBUGFUNCTIONCONSTRAINT controls wheather we perform the check anyway
933 in order to find potential problems like assert failures and seg faults...
936 if (!context_getFlag(FLG_DEBUGFUNCTIONCONSTRAINT) )
937 /* check if errors will printed */
938 if (! (context_getFlag(FLG_DEBUGFUNCTIONCONSTRAINT) ||
939 context_getFlag(FLG_FUNCTIONCONSTRAINT) ||
940 context_getFlag(FLG_ARRAYBOUNDS) ||
941 context_getFlag(FLG_ARRAYBOUNDSREAD) ||
942 context_getFlag(FLG_CHECKPOST)
946 exprNode_free (body);
947 context_exitInnerPlain();
952 exprNode_generateConstraints (body);
955 c = uentry_getFcnPreconditions (ue);
956 DPRINTF(("function constraints\n"));
957 DPRINTF (("\n\n\n\n\n\n\n"));
960 if (constraintList_isDefined(c) )
963 DPRINTF ( (message ("Function preconditions are %s \n\n\n\n\n", constraintList_printDetailed (c) ) ) );
965 body->requiresConstraints = constraintList_reflectChangesFreePre (body->requiresConstraints, c);
967 c2 = constraintList_copy (c);
968 fix = constraintList_makeFixedArrayConstraints (body->uses);
969 c2 = constraintList_reflectChangesFreePre (c2, fix);
970 constraintList_free(fix);
971 if ( context_getFlag (FLG_ORCONSTRAINT) )
973 t = constraintList_reflectChangesOr (body->requiresConstraints, c2 );
977 t = constraintList_reflectChanges(body->requiresConstraints, c2);
980 constraintList_free(body->requiresConstraints);
981 DPRINTF ( (message ("The body has the required constraints: %s", constraintList_printDetailed (t) ) ) );
983 body->requiresConstraints = t;
985 t = constraintList_mergeEnsures (c, body->ensuresConstraints);
986 constraintList_free(body->ensuresConstraints);
988 body->ensuresConstraints = t;
990 DPRINTF ( (message ("The body has the ensures constraints: %s", constraintList_printDetailed (t) ) ) );
991 constraintList_free(c2);
994 if (constraintList_isDefined(c) )
996 DPRINTF((message ("The Function %s has the preconditions %s", uentry_unparse(ue), constraintList_printDetailed(c) ) ) );
1000 DPRINTF((message ("The Function %s has no preconditions", uentry_unparse(ue) ) ) );
1003 implicitFcnConstraints = getImplicitFcnConstraints();
1005 if (constraintList_isDefined(implicitFcnConstraints) )
1007 if (context_getFlag (FLG_IMPLICTCONSTRAINT) )
1009 body->requiresConstraints = constraintList_reflectChangesFreePre (body->requiresConstraints, implicitFcnConstraints );
1013 body->requiresConstraints = constraintList_sort (body->requiresConstraints);
1015 constraintList_printError(body->requiresConstraints, g_currentloc);
1017 post = uentry_getFcnPostconditions (ue);
1019 if ( context_getFlag (FLG_CHECKPOST) )
1021 if (constraintList_isDefined(post) )
1024 constraintList post2;
1026 DPRINTF ( (message ("The declared function postconditions are %s \n\n\n\n\n", constraintList_printDetailed (post) ) ) );
1028 post = constraintList_reflectChangesFreePre (post, body->ensuresConstraints);
1030 post2 = constraintList_copy (post);
1031 fix = constraintList_makeFixedArrayConstraints (body->uses);
1032 post2 = constraintList_reflectChangesFreePre (post2, fix);
1033 constraintList_free(fix);
1034 if ( context_getFlag (FLG_ORCONSTRAINT) )
1036 t = constraintList_reflectChangesOr (post2, body->ensuresConstraints);
1040 t = constraintList_reflectChanges(post2, body->ensuresConstraints);
1043 constraintList_free(post2);
1045 constraintList_free(post);
1050 printf("Unresolved post conditions\n");
1051 constraintList_printErrorPostConditions(post, g_currentloc);
1055 if (constraintList_isDefined(post) )
1057 constraintList_free(post);
1060 body->ensuresConstraints = constraintList_sort(body->ensuresConstraints);
1062 if ( context_getFlag (FLG_FUNCTIONPOST) )
1064 constraintList_printError(body->ensuresConstraints, g_currentloc);
1067 /* ConPrint (message ("Unable to resolve function constraints:\n%s", constraintList_printDetailed(body->requiresConstraints) ), g_currentloc);
1069 ConPrint (message ("Splint has found function post conditions:\n%s", constraintList_printDetailed(body->ensuresConstraints) ), g_currentloc);
1071 printf ("The required constraints are:\n%s", constraintList_printDetailed(body->requiresConstraints) );
1072 printf ("The ensures constraints are:\n%s", constraintList_printDetailed(body->ensuresConstraints) );
1075 if (constraintList_isDefined(c) )
1076 constraintList_free(c);
1078 context_exitInnerPlain();
1080 /*is it okay not to free this?*/
1081 exprNode_free (body);
1084 void exprChecks_checkEmptyMacroBody (void)
1088 if (!(context_inFunctionLike () || context_inMacroConstant ()
1089 || context_inUnknownMacro ()))
1092 (message ("exprNode_checkEmptyMacroBody: not in macro function or constant: %q",
1093 context_unparse ()));
1097 hdr = context_getHeader ();
1101 if (uentry_isFunction (hdr))
1106 ("Macro definition for %q is empty", uentry_getName (hdr)),
1109 usymtab_checkFinalScope (FALSE);
1112 context_exitFunction ();
1116 void exprNode_checkIterBody (/*@only@*/ exprNode body)
1118 context_exitAllClauses ();
1120 context_exitFunction ();
1121 exprNode_free (body);
1124 void exprNode_checkIterEnd (/*@only@*/ exprNode body)
1126 context_exitAllClauses ();
1127 context_exitFunction ();
1128 exprNode_free (body);
1132 bool checkModifyAuxAux (/*@exposed@*/ sRef s, exprNode f, sRef alias, exprNode err)
1134 bool hasMods = context_hasMods ();
1135 flagcode errCode = hasMods ? FLG_MODIFIES : FLG_MODNOMODS;
1137 if (exprNode_isDefined (f))
1139 f->sets = sRefSet_insert (f->sets, s);
1142 if (context_getFlag (FLG_MODIFIES)
1143 && (hasMods || context_getFlag (FLG_MODNOMODS)))
1145 sRefSet mods = context_modList ();
1147 if (!sRef_canModify (s, mods))
1149 sRef rb = sRef_getRootBase (s);
1152 if (sRef_isFileOrGlobalScope (rb))
1154 if (!context_checkGlobMod (rb))
1160 if (sRef_isInvalid (alias) || sRef_sameName (s, alias))
1162 if (sRef_isLocalVar (sRef_getRootBase (s)))
1167 ("Undocumented modification of internal state (%q): %s",
1168 sRef_unparse (s), exprNode_unparse (err)),
1169 exprNode_isDefined (f) ? f->loc : g_currentloc);
1173 if (sRef_isSystemState (s))
1175 if (errCode == FLG_MODNOMODS)
1177 if (context_getFlag (FLG_MODNOMODS))
1179 errCode = FLG_MODFILESYSTEM;
1184 errCode = FLG_MODFILESYSTEM;
1190 message ("Undocumented modification of %q: %s",
1191 sRef_unparse (s), exprNode_unparse (err)),
1192 exprNode_isDefined (f) ? f->loc : g_currentloc);
1199 if (sRef_isReference (s) && !sRef_isAddress (alias))
1204 ("Possible undocumented modification of %q through alias %q: %s",
1206 sRef_unparse (alias),
1207 exprNode_unparse (err)),
1208 exprNode_isDefined (f) ? f->loc : g_currentloc);
1216 if (context_maybeSet (FLG_MUSTMOD))
1218 (void) sRef_canModify (s, context_modList ());
1221 if (sRef_isRefsField (s))
1223 sRef_setModified (s);
1231 bool checkModifyAux (/*@exposed@*/ sRef s, exprNode f, sRef alias, exprNode err)
1233 DPRINTF (("Check modify aux: %s", sRef_unparseFull (s)));
1235 if (sRef_isReference (s) && sRef_isObserver (s)
1236 && context_maybeSet (FLG_MODOBSERVER))
1240 if (sRef_isPointer (s))
1242 sRef base = sRef_getBase (s);
1243 sname = sRef_unparse (base);
1247 if (sRef_isAddress (s))
1249 sRef p = sRef_constructPointer (s);
1250 sname = sRef_unparse (p);
1254 sname = sRef_unparse (s);
1258 if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1260 if (sRef_isMeaningful (s))
1264 message ("Suspect modification of observer %s: %s",
1265 sname, exprNode_unparse (err)),
1266 exprNode_isDefined (f) ? f->loc : g_currentloc))
1268 sRef_showExpInfo (s);
1275 message ("Suspect modification of observer returned by "
1276 "function call: %s",
1277 exprNode_unparse (err)),
1278 exprNode_isDefined (f) ? f->loc : g_currentloc);
1285 message ("Suspect modification of observer %s through alias %q: %s",
1286 sname, sRef_unparse (alias), exprNode_unparse (err)),
1287 exprNode_isDefined (f) ? f->loc : g_currentloc))
1289 sRef_showExpInfo (s);
1293 cstring_free (sname);
1296 (void) checkModifyAuxAux (s, f, alias, err);
1301 bool checkModifyValAux (/*@exposed@*/ sRef s, exprNode f, sRef alias, exprNode err)
1303 (void) checkModifyAuxAux (s, f, alias, err);
1308 bool checkCallModifyAux (/*@exposed@*/ sRef s, exprNode f, sRef alias, exprNode err)
1310 bool result = FALSE;
1312 DPRINTF (("Check modify aux: %s / %s",
1313 sRef_unparse (s), sRef_unparse (alias)));
1315 if (sRef_isObserver (s) && context_maybeSet (FLG_MODOBSERVER))
1317 sRef p = sRef_isAddress (s) ? sRef_constructPointer (s) : s;
1318 cstring sname = sRef_unparse (p);
1320 if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1322 if (sRef_isMeaningful (s))
1324 result = optgenerror
1326 message ("Suspect modification of observer %s: %s",
1327 sname, exprNode_unparse (err)),
1328 exprNode_isDefined (f) ? f->loc : g_currentloc);
1332 result = optgenerror
1334 message ("Suspect modification of observer returned by "
1335 "function call: %s",
1336 exprNode_unparse (err)),
1337 exprNode_isDefined (f) ? f->loc : g_currentloc);
1342 result = optgenerror
1345 ("Suspect modification of observer %s through alias %q: %s",
1346 sname, sRef_unparse (alias), exprNode_unparse (err)),
1347 exprNode_isDefined (f) ? f->loc : g_currentloc);
1350 cstring_free (sname);
1352 else if (context_maybeSet (FLG_MODIFIES))
1354 DPRINTF (("can modify: %s / %s",
1356 sRefSet_unparse (context_modList ())));
1358 if (!(sRef_canModifyVal (s, context_modList ())))
1360 sRef p = sRef_isAddress (s) ? sRef_constructPointer (s) : s;
1361 cstring sname = sRef_unparse (p);
1362 bool hasMods = context_hasMods ();
1363 sRef rb = sRef_getRootBase (s);
1364 flagcode errCode = hasMods ? FLG_MODIFIES : FLG_MODNOMODS;
1367 DPRINTF (("Can't modify! %s", sRef_unparse (s)));
1369 if (sRef_isFileOrGlobalScope (rb))
1371 uentry ue = sRef_getUentry (rb);
1373 /* be more specific here! */
1374 if (!uentry_isCheckedModify (ue))
1382 if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1384 if (sRef_isLocalVar (sRef_getRootBase (s)))
1389 ("Undocumented modification of internal "
1390 "state (%q) through call to %s: %s",
1391 sRef_unparse (s), exprNode_unparse (f),
1392 exprNode_unparse (err)),
1393 exprNode_isDefined (f) ? f->loc : g_currentloc);
1397 if (sRef_isSystemState (s))
1399 if (errCode == FLG_MODNOMODS)
1401 if (context_getFlag (FLG_MODNOMODS))
1403 errCode = FLG_MODFILESYSTEM;
1408 errCode = FLG_MODFILESYSTEM;
1412 result = optgenerror
1414 message ("Undocumented modification of %s "
1415 "possible from call to %s: %s",
1417 exprNode_unparse (f),
1418 exprNode_unparse (err)),
1419 exprNode_isDefined (f) ? f->loc : g_currentloc);
1424 result = optgenerror
1426 message ("Undocumented modification of %s possible "
1427 "from call to %s (through alias %q): %s",
1429 exprNode_unparse (f),
1430 sRef_unparse (alias),
1431 exprNode_unparse (err)),
1432 exprNode_isDefined (f) ? f->loc : g_currentloc);
1435 cstring_free (sname);
1440 if (context_maybeSet (FLG_MUSTMOD))
1442 (void) sRef_canModifyVal (s, context_modList ());
1449 void exprNode_checkCallModifyVal (sRef s, exprNodeList args, exprNode f, exprNode err)
1451 s = sRef_fixBaseParam (s, args);
1452 DPRINTF (("Check call modify: %s", sRef_unparse (s)));
1453 sRef_aliasCheckPred (checkCallModifyAux, NULL, s, f, err);
1457 exprChecks_checkExport (uentry e)
1459 if (context_checkExport (e))
1461 fileloc fl = uentry_whereDeclared (e);
1463 if (fileloc_isHeader (fl) && !fileloc_isLib (fl)
1464 && !fileloc_isImport (fl) && !uentry_isStatic (e))
1466 if (uentry_isFunction (e) ||
1467 (uentry_isVariable (e) && ctype_isFunction (uentry_getType (e))))
1471 message ("Function exported, but not specified: %q",
1472 uentry_getName (e)),
1475 else if (uentry_isExpandedMacro (e))
1479 message ("Expanded macro exported, but not specified: %q",
1480 uentry_getName (e)),
1483 else if (uentry_isVariable (e) && !uentry_isParam (e))
1487 message ("Variable exported, but not specified: %q",
1488 uentry_getName (e)),
1491 else if (uentry_isEitherConstant (e))
1495 message ("Constant exported, but not specified: %q",
1496 uentry_getName (e)),
1499 else if (uentry_isIter (e) || uentry_isEndIter (e))
1503 message ("Iterator exported, but not specified: %q",
1504 uentry_getName (e)),
1508 else if (uentry_isDatatype (e))
1510 ; /* error already reported */
1520 static void checkSafeReturnExpr (/*@notnull@*/ exprNode e)
1522 ctype tr = ctype_getReturnType (context_currentFunctionType ());
1523 ctype te = exprNode_getType (e);
1525 /* evans 2001-08-21: added test to warn about void returns from void functions */
1526 if (ctype_isVoid (tr))
1529 (te, e, tr, exprNode_undefined,
1530 message ("Return expression from function declared void: %s", exprNode_unparse (e)),
1535 if (!ctype_forceMatch (tr, te) && !exprNode_matchLiteral (tr, e))
1538 (te, e, tr, exprNode_undefined,
1539 message ("Return value type %t does not match declared type %t: %s",
1540 te, tr, exprNode_unparse (e)),
1546 uentry rval = context_getHeader ();
1547 sRef resultref = uentry_getSref (rval);
1549 DPRINTF (("Check return: %s / %s / %s",
1550 exprNode_unparse (e),
1551 sRef_unparseFull (e->sref),
1552 uentry_unparse (rval)));
1554 checkReturnTransfer (e, rval);
1556 DPRINTF (("After return: %s / %s / %s",
1557 exprNode_unparse (e),
1558 sRef_unparseFull (e->sref),
1559 uentry_unparse (rval)));
1561 if (!(sRef_isExposed (uentry_getSref (context_getHeader ()))
1562 || sRef_isObserver (uentry_getSref (context_getHeader ())))
1563 && (context_getFlag (FLG_RETALIAS)
1564 || context_getFlag (FLG_RETEXPOSE)))
1566 sRef base = sRef_getRootBase (ret);
1567 ctype rtype = e->typ;
1569 if (ctype_isUnknown (rtype))
1574 if (ctype_isVisiblySharable (rtype))
1576 if (context_getFlag (FLG_RETALIAS))
1578 sRef_aliasCheckPred (checkRefGlobParam, NULL, base,
1579 e, exprNode_undefined);
1582 if (context_getFlag (FLG_RETEXPOSE) && sRef_isIReference (ret)
1583 && !sRef_isExposed (resultref) && !sRef_isObserver (resultref))
1585 sRef_aliasCheckPred (checkRepExposed, NULL, base, e,
1586 exprNode_undefined);