2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2002 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 splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
28 # include "splintMacros.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
55 static int inCompoundStatementExpression = 0;
58 exprChecks_inCompoundStatementExpression (void)
60 inCompoundStatementExpression++;
64 exprChecks_leaveCompoundStatementExpression (void)
66 inCompoundStatementExpression--;
67 llassert (inCompoundStatementExpression >= 0);
71 exprChecks_checkStatementEffect (exprNode e)
73 bool hasError = FALSE;
75 if (inCompoundStatementExpression > 0)
78 ** Okay to have effectless statments in compound statement expression (should check
79 ** it is the last statement, but we don't for now).
85 if (!exprNode_isError (e))
87 exprKind ek = e->kind;
89 if (ek == XPR_CALL && !(ctype_isRealVoid (e->typ)))
91 if (ctype_isKnown (e->typ))
93 if (ctype_isManifestBool (ctype_realishType (e->typ)))
95 hasError = optgenerror
97 message ("Return value (type %t) ignored: %s",
99 exprNode_unparseFirst (e)),
102 else if (ctype_isDirectInt (e->typ))
104 hasError = optgenerror
106 message ("Return value (type %t) ignored: %s",
108 exprNode_unparseFirst (e)),
113 hasError = optgenerror
115 message ("Return value (type %t) ignored: %s",
117 exprNode_unparseFirst (e)),
123 if (!hasError && !(exprNode_mayEscape (e))
124 && !(e->canBreak)) /* control changes are effects too! */
126 if (sRefSet_hasRealElement (e->sets)
127 || sRefSet_hasRealElement (e->msets))
133 if (sRefSet_isEmpty (e->sets) && sRefSet_isEmpty (e->msets))
137 message ("Statement has no effect: %s",
138 exprNode_unparseFirst (e)),
143 if (context_maybeSet (FLG_NOEFFECTUNCON))
145 if (sRefSet_hasUnconstrained (e->sets))
149 message ("Statement has no effect (possible "
150 "undected modification through "
152 sRefSet_unparseUnconstrained (e->sets),
153 exprNode_unparseFirst (e)),
156 else if (sRefSet_hasUnconstrained (e->msets))
160 message ("Statement has no effect (possible "
161 "undected modification through "
163 sRefSet_unparseUnconstrained (e->msets),
164 exprNode_unparseFirst (e)),
169 ; /* statement has unknown modification */
179 checkRepExposed (sRef base, /*@notnull@*/ exprNode e, sRef alias,
180 /*@unused@*/ exprNode unused)
184 if (sRef_isInvalid (alias) || sRef_sameName (base, alias))
186 btype = sRef_getType (base);
188 if (ctype_isAbstract (btype) && ctype_isVisiblySharable (e->typ))
190 voptgenerror (FLG_RETEXPOSE,
191 message ("Return value exposes rep of %s: %s",
192 ctype_unparse (btype),
193 exprNode_unparse (e)),
200 sRef rbase = sRef_getRootBase (base);
201 btype = sRef_getType (rbase);
203 if (ctype_isAbstract (btype) && ctype_isVisiblySharable (e->typ))
207 message ("Return value may expose rep of %s through alias %q: %s",
208 ctype_unparse (btype),
209 sRef_unparse (rbase),
210 exprNode_unparse (e)),
220 checkRefGlobParam (sRef base, /*@notnull@*/ exprNode e,
221 sRef alias, /*@unused@*/ exprNode unused)
223 if (sRef_isInvalid (alias) || sRef_sameName (base, alias))
227 if (ctype_isUnknown (ct))
229 ct = sRef_getType (base);
232 if (ctype_isVisiblySharable (ct))
234 if (sRef_isFileOrGlobalScope (base))
236 uentry fcn = context_getHeader ();
237 bool noerror = FALSE;
239 if (uentry_isValid (fcn) && uentry_isFunction (fcn))
241 sRef res = uentry_getSref (fcn);
243 /* If result is dependent and global is owned, this is okay... */
244 if (sRef_isDependent (res)
245 && sRef_isOwned (base))
256 message ("Function returns reference to global %q: %s",
258 exprNode_unparse (e)),
264 else if (sRef_isAnyParam (base))
266 uentryList params = context_getParams ();
267 int paramno = sRef_getParam (base);
269 if (paramno < uentryList_size (params))
271 uentry arg = uentryList_getN (params, paramno);
272 sRef ref = uentry_getSref (arg);
274 if (uentry_isReturned (arg)
276 || sRef_isExposed (ref)
277 || sRef_isRefCounted (ref))
285 message ("Function returns reference to parameter %q: %s",
287 exprNode_unparse (e)),
293 llbuglit ("ret alias: bad paramno");
306 if (ctype_isVisiblySharable (e->typ))
308 if (sRef_isFileOrGlobalScope (base))
312 message ("Function may return reference to global %q through alias %q: %s",
313 sRef_unparse (alias),
315 exprNode_unparse (e)),
319 else if (sRef_isAnyParam (base) && !(sRef_isOnly (base)))
321 uentryList params = context_getParams ();
322 int paramno = sRef_getParam (base);
324 if (paramno < uentryList_size (params))
326 uentry arg = uentryList_getN (params, paramno);
328 if (!uentry_isReturned (arg))
333 ("Function may return reference to parameter %q through alias %q: %s",
335 sRef_unparse (alias),
336 exprNode_unparse (e)),
347 ("Function may return reference to parameter %q through alias %q: %s",
349 sRef_unparse (alias),
350 exprNode_unparse (e)),
367 exprNode_checkModify (exprNode e, exprNode err)
369 llassert (exprNode_isDefined (e));
371 DPRINTF (("Check modify: %s", exprNode_unparse (e)));
373 if (sRef_isValid (e->sref))
375 sRef_aliasCheckPred (checkModifyAux, sRef_isReference, e->sref, e, err);
380 exprNode_checkModifyVal (exprNode e, exprNode err)
382 llassert (exprNode_isDefined (e));
384 DPRINTF (("Check modify val: %s", exprNode_unparse (e)));
386 if (sRef_isValid (e->sref))
388 sRef_aliasCheckPred (checkModifyValAux, sRef_isReference, e->sref, e, err);
393 exprChecks_checkNullReturn (fileloc loc)
395 if (!context_inRealFunction ())
398 llmsg ("exprChecks_checkNullReturnExpr: not in function context");
404 if (ctype_isFunction (context_currentFunctionType ()))
406 ctype tr = ctype_getReturnType (context_currentFunctionType ());
408 if (!ctype_isFirstVoid (tr))
410 if (ctype_isUnknown (tr))
414 cstring_makeLiteral ("Empty return in function declared to implicitly return int"),
419 voptgenerror (FLG_EMPTYRETURN,
420 message ("Empty return in function declared to return %t", tr),
429 exprNode_checkReturn (exprNode e)
431 if (!exprNode_isError (e))
433 if (!context_inRealFunction ())
435 if (context_inMacro ())
437 llerror (FLG_MACRORETURN,
438 message ("Macro %s uses return (not functional)",
439 context_inFunctionName ()));
444 llbuglit ("exprNode_checkReturn: not in function context");
450 if (ctype_isFunction (context_currentFunctionType ()))
452 checkSafeReturnExpr (e);
463 exprNode_checkPred (cstring c, exprNode e)
467 if (exprNode_isError (e))
470 ct = exprNode_getType (e);
472 if (exprNode_isAssign (e))
476 message ("Test expression for %s is assignment expression: %s",
477 c, exprNode_unparse (e)),
481 if (ctype_isRealBool (ct) || ctype_isUnknown (ct))
482 /* evs 2000-12-20 added || ctype_isUnknown to avoid spurious messages */
486 else if (ctype_isRealPointer (ct))
490 message ("Test expression for %s not %s, type %t: %s", c,
491 context_printBoolName (),
492 ct, exprNode_unparse (e)),
495 else if (ctype_isRealInt (ct))
499 message ("Test expression for %s not %s, type %t: %s", c,
500 context_printBoolName (), ct, exprNode_unparse (e)),
507 message ("Test expression for %s not %s, type %t: %s", c,
508 context_printBoolName (), ct, exprNode_unparse (e)),
514 exprChecks_checkUsedGlobs (globSet decl, globSet used)
516 fileloc fl = uentry_whereSpecified (context_getHeader ());
518 if (fileloc_isUndefined (fl))
520 fl = uentry_whereDeclared (context_getHeader ());
523 globSet_allElements (decl, el)
525 if (!globSet_member (used, el))
527 if (sRef_isSpecInternalState (el)
528 || sRef_isNothing (el))
534 cstring sname = sRef_unparse (el);
536 if (fileloc_isLib (fl))
538 voptgenerror (FLG_USEALLGLOBS,
539 message ("Global %s listed (%q) but not used",
540 sname, fileloc_unparse (fl)),
545 voptgenerror (FLG_USEALLGLOBS,
546 message ("Global %s listed but not used", sname),
550 cstring_free (sname);
553 } end_globSet_allElements;
557 exprNode_checkAllMods (sRefSet mods, uentry ue)
559 bool realParams = FALSE;
560 uentry le = context_getHeader ();
561 fileloc fl = uentry_whereSpecified (le);
562 uentryList specParamNames = uentryList_undefined;
563 uentryList paramNames = context_getParams ();
565 if (uentry_isFunction (le))
567 specParamNames = uentry_getParams (le);
569 if (uentryList_isUndefined (specParamNames))
571 ; /* unknown params */
573 else if (uentryList_size (paramNames) != uentryList_size (specParamNames))
576 (message ("exprNode_checkAllMods: parameter lists have different sizes: "
578 uentryList_unparse (paramNames),
579 uentryList_size (paramNames),
580 uentryList_unparse (specParamNames),
581 uentryList_size (specParamNames)));
583 else if (uentryList_size (paramNames) > 0
584 && !uentry_hasRealName (uentryList_getN (specParamNames, 0)))
586 /* loaded from a library */
594 sRefSet_allElements (mods, sr)
596 if (sRef_isNothing (sr) || sRef_isSpecState (sr))
598 ; /* should report on anything? */
600 else if (sRef_isInternalState (sr))
602 if (!sRef_isModified (sr))
604 if (sRefSet_hasStatic (mods))
613 ("Function %s specified to modify internal state "
614 "but no internal state is modified",
615 uentry_rawName (ue)),
616 uentry_whereLast (ue)))
618 uentry_showWhereSpecified (le);
625 if (!sRef_isModified (sr))
627 cstring sname = realParams ? sRef_unparse (sr) : sRef_unparse (sr);
629 if (fileloc_isLib (fl) && !realParams)
633 message ("Suspect object listed (%q) in modifies "
634 "clause of %s not modified: %s",
635 fileloc_unparse (fl),
638 uentry_whereLast (ue));
644 message ("Suspect object listed in modifies of %s "
648 uentry_whereLast (ue)))
650 uentry_showWhereSpecified (le);
653 cstring_free (sname);
656 } end_sRefSet_allElements;
659 void exprNode_checkMacroBody (/*@only@*/ exprNode e)
661 if (!exprNode_isError (e))
665 if (!(context_inFunctionLike () || context_inMacroConstant ()
666 || context_inUnknownMacro ()))
670 ("exprNode_checkMacroBody: not in macro function or constant: %q",
671 context_unparse ()));
676 hdr = context_getHeader ();
678 if (e->kind == XPR_STMTLIST || e->kind == XPR_BODY)
683 ("Macro %q definition is statement list (recommend "
684 "do { ... } while (0) constuction to ensure multiple "
685 "statement macro is syntactic function)",
686 uentry_getName (hdr)),
687 fileloc_isDefined (e->loc) ? e->loc : g_currentloc);
690 if (context_inMacroConstant ())
692 ctype t = uentry_getType (hdr);
694 uentry_setDefined (hdr, e->loc);
696 if (!(exprNode_matchType (t, e)))
698 cstring uname = uentry_getName (hdr);
700 if (cstring_equal (uname, context_getTrueName ())
701 || cstring_equal (uname, context_getFalseName ()))
704 ** We need to do something special to allow FALSE and TRUE
705 ** to be defined without reporting errors. This is a tad
706 ** bogus, but otherwise lots of things would break.
710 llassert (ctype_isManifestBool (t));
711 /* Should also check type of e is a reasonable (?) bool type. */
718 ("Constant %q specified as %s, but defined as %s: %s",
719 uentry_getName (hdr),
721 ctype_unparse (e->typ),
722 exprNode_unparse (e)),
725 uentry_showWhereSpecified (hdr);
729 cstring_free (uname);
733 if (context_maybeSet (FLG_NULLSTATE)
735 && ctype_isRealPointer (t)
736 && exprNode_isNullValue (e))
738 uentry ue = usymtab_getTypeEntry (ctype_typeId (t));
739 sRef sr = uentry_getSref (ue);
741 if (!sRef_possiblyNull (sr))
745 message ("Constant %q of non-null type %s defined "
747 uentry_getName (hdr), ctype_unparse (t),
748 exprNode_unparse (e)),
749 message ("If %s can be null, add a /*@null@*/ "
750 "qualifer to its typedef.",
755 uentry_mergeConstantValue (hdr, e->val);
756 e->val = multiVal_undefined;
760 else if (context_inMacroFunction () || context_inUnknownMacro ())
762 ctype rettype = context_getRetType ();
764 if (context_isMacroMissingParams ())
766 llassert (context_inMacroFunction ());
769 ** # define newname oldname
771 ** newname is a function
772 ** specification of oldname should match
773 ** specification of newname.
776 if (!ctype_isFunction (e->typ))
780 message ("Function %s defined by unparameterized "
781 "macro not corresponding to function",
782 context_inFunctionName ()),
787 uentry ue = exprNode_getUentry (e);
789 if (uentry_isValid (ue))
792 ** Okay, for now --- should check for consistency
795 ** uentry oldue = usymtab_lookup (cfname);
798 /* check var conformance here! */
804 message ("Function %s defined by unparameterized "
805 "macro not corresponding to function",
806 context_inFunctionName ()),
810 e->typ = ctype_getReturnType (e->typ);
811 rettype = e->typ; /* avoid aditional errors */
815 if (ctype_isVoid (rettype) || ctype_isUnknown (rettype))
817 ; /* don't complain when void macros have values */
819 else if (!exprNode_matchType (rettype, e))
823 message ("Function %q specified to return %s, "
824 "implemented as macro having type %s: %s",
825 uentry_getName (hdr),
826 ctype_unparse (rettype), ctype_unparse (e->typ),
827 exprNode_unparse (e)),
830 uentry_showWhereSpecified (hdr);
837 /* these expressions have values: */
838 case XPR_PARENS: case XPR_ASSIGN:
839 case XPR_EMPTY: case XPR_VAR:
840 case XPR_OP: case XPR_POSTOP:
841 case XPR_PREOP: case XPR_CALL:
842 case XPR_SIZEOFT: case XPR_SIZEOF:
843 case XPR_ALIGNOFT: case XPR_ALIGNOF:
844 case XPR_CAST: case XPR_FETCH:
845 case XPR_COMMA: case XPR_COND:
846 case XPR_ARROW: case XPR_CONST:
847 case XPR_STRINGLITERAL: case XPR_NUMLIT:
848 case XPR_FACCESS: case XPR_OFFSETOF:
850 transferChecks_return (e, hdr);
853 /* these expressions don't */
855 case XPR_VAARG: case XPR_ITER:
856 case XPR_FOR: case XPR_FORPRED:
857 case XPR_GOTO: case XPR_CONTINUE:
858 case XPR_BREAK: case XPR_RETURN:
859 case XPR_NULLRETURN: case XPR_IF:
860 case XPR_IFELSE: case XPR_DOWHILE:
861 case XPR_WHILE: case XPR_STMT:
862 case XPR_STMTLIST: case XPR_SWITCH:
863 case XPR_INIT: case XPR_BODY:
864 case XPR_NODE: case XPR_ITERCALL:
865 case XPR_TOK: case XPR_CASE:
866 case XPR_FTCASE: case XPR_FTDEFAULT:
867 case XPR_DEFAULT: case XPR_WHILEPRED:
868 case XPR_BLOCK: case XPR_INITBLOCK:
871 message ("Function %q specified to return %s, "
872 "implemented as macro with no result: %s",
873 uentry_getName (hdr),
874 ctype_unparse (rettype),
875 exprNode_unparse (e)),
878 uentry_showWhereSpecified (hdr);
883 usymtab_checkFinalScope (FALSE);
887 llbug (message ("exprNode_checkMacroBody: not in macro function: %q", context_unparse ()));
893 context_exitFunction ();
897 void exprNode_checkFunctionBody (exprNode body)
899 if (!exprNode_isError (body))
901 bool noret = context_getFlag (FLG_NORETURN);
902 bool checkret = exprNode_mustEscape (body);
906 && !exprNode_errorEscape (body)
907 && context_inRealFunction ()
908 && ctype_isFunction (context_currentFunctionType ()))
910 ctype tr = ctype_getReturnType (context_currentFunctionType ());
912 if (!ctype_isFirstVoid (tr))
914 if (ctype_isUnknown (tr))
918 cstring_makeLiteral ("Path with no return in function declared to implicity return int"),
925 message ("Path with no return in function declared to return %t",
934 context_returnFunction ();
939 /* drl added 2/26/2002 */
940 /* prints out a function */
941 void exprNode_spitFunction (/*@unused@*/ uentry ue, exprNode fcnBody)
948 if (context_getFlag(FLG_GENERATECODE) )
956 locateInfo = fileloc_filename (exprNode_getLoc (body) ) ;
958 locateInfo = message ("fprintf(stderr,\"%s\");\n",locateInfo);
961 if (body->kind == XPR_TOK)
963 outCode = message( " #include <stdio.h>\n%s\n{\n%s{\n%s\n}\n}\n",
964 uentry_unparseFunctionHeader (ue),
966 exprNode_unparse(body)
971 outCode = message( "\n#include <stdio.h>\n%s\n{\n%s{\n%s;\n}\n}\n",
972 uentry_unparseFunctionHeader (ue),
974 exprNode_unparse(body)
979 llassert(exprNode_isDefined(body) );
981 if (body->kind == XPR_TOK)
983 outCode = message( "%s\n{\n%s\n}\n",
984 uentry_unparseFunctionHeader (ue),
985 exprNode_unparse(body)
990 outCode = message( "%s\n{\n%s\n}\n",
991 uentry_unparseFunctionHeader (ue),
992 exprNode_unparse(body)
996 cstring_free(outCode);
1004 void exprNode_checkFunction (/*@unused@*/ uentry ue, /*@only@*/ exprNode body)
1006 constraintList c, t, post;
1007 constraintList c2, fix;
1008 constraintList implicitFcnConstraints;
1010 context_enterInnerContext ();
1013 llassert (exprNode_isDefined (body));
1016 if we're not going to be printing any errors for buffer overflows
1017 we can skip the checking to improve performance
1019 FLG_DEBUGFUNCTIONCONSTRAINT controls wheather we perform the check anyway
1020 in order to find potential problems like assert failures and seg faults...
1023 if (!context_getFlag(FLG_DEBUGFUNCTIONCONSTRAINT))
1025 /* check if errors will printed */
1026 if (!(context_getFlag(FLG_DEBUGFUNCTIONCONSTRAINT) ||
1027 context_getFlag(FLG_BOUNDSWRITE) ||
1028 context_getFlag(FLG_BOUNDSREAD) ||
1029 context_getFlag(FLG_CHECKPOST)))
1031 if ( context_getFlag (FLG_GENERATECODE) )
1033 exprNode_spitFunction(ue, body);
1037 exprNode_free (body);
1038 context_exitInnerPlain();
1044 exprNode_generateConstraints (body); /* evans 2002-03-02: this should not be declared to take a
1045 dependent... fix it! */
1047 c = uentry_getFcnPreconditions (ue);
1048 DPRINTF(("function constraints\n"));
1049 DPRINTF (("\n\n\n\n\n\n\n"));
1051 if (constraintList_isDefined(c) )
1053 DPRINTF ((message ("Function preconditions are %s \n\n\n\n\n", constraintList_printDetailed (c) ) ) );
1055 body->requiresConstraints = constraintList_reflectChangesFreePre (body->requiresConstraints, c);
1057 c2 = constraintList_copy (c);
1058 fix = constraintList_makeFixedArrayConstraints (body->uses);
1059 c2 = constraintList_reflectChangesFreePre (c2, fix);
1060 constraintList_free (fix);
1062 if (context_getFlag (FLG_ORCONSTRAINT))
1064 t = constraintList_reflectChangesOr (body->requiresConstraints, c2 );
1068 t = constraintList_reflectChanges(body->requiresConstraints, c2);
1071 constraintList_free (body->requiresConstraints);
1072 DPRINTF ((message ("The body has the required constraints: %s", constraintList_printDetailed (t) ) ) );
1074 body->requiresConstraints = t;
1076 t = constraintList_mergeEnsures (c, body->ensuresConstraints);
1077 constraintList_free(body->ensuresConstraints);
1079 body->ensuresConstraints = t;
1081 DPRINTF ((message ("The body has the ensures constraints: %s", constraintList_printDetailed (t) ) ) );
1082 constraintList_free(c2);
1085 if (constraintList_isDefined(c))
1087 DPRINTF ((message ("The Function %s has the preconditions %s",
1088 uentry_unparse(ue), constraintList_printDetailed(c))));
1092 DPRINTF((message ("The Function %s has no preconditions", uentry_unparse(ue))));
1095 implicitFcnConstraints = getImplicitFcnConstraints();
1097 if (constraintList_isDefined(implicitFcnConstraints) )
1099 if (context_getFlag (FLG_IMPLICTCONSTRAINT) )
1101 body->requiresConstraints = constraintList_reflectChangesFreePre (body->requiresConstraints,
1102 implicitFcnConstraints );
1106 body->requiresConstraints = constraintList_sort (body->requiresConstraints);
1108 constraintList_printError(body->requiresConstraints, g_currentloc);
1110 post = uentry_getFcnPostconditions (ue);
1112 if (context_getFlag (FLG_CHECKPOST))
1114 if (constraintList_isDefined (post))
1116 constraintList post2;
1118 DPRINTF ((message ("The declared function postconditions are %s \n\n\n\n\n",
1119 constraintList_printDetailed (post) ) ) );
1121 post = constraintList_reflectChangesFreePre (post, body->ensuresConstraints);
1123 post2 = constraintList_copy (post);
1124 fix = constraintList_makeFixedArrayConstraints (body->uses);
1125 post2 = constraintList_reflectChangesFreePre (post2, fix);
1126 constraintList_free(fix);
1127 if ( context_getFlag (FLG_ORCONSTRAINT) )
1129 t = constraintList_reflectChangesOr (post2, body->ensuresConstraints);
1133 t = constraintList_reflectChanges(post2, body->ensuresConstraints);
1136 constraintList_free(post2);
1137 constraintList_free(post);
1140 printf("Unresolved post conditions\n");
1141 constraintList_printErrorPostConditions(post, g_currentloc);
1145 if (constraintList_isDefined (post))
1147 constraintList_free (post);
1150 body->ensuresConstraints = constraintList_sort(body->ensuresConstraints);
1152 if ( context_getFlag (FLG_FUNCTIONPOST) )
1154 constraintList_printError(body->ensuresConstraints, g_currentloc);
1157 /* ConPrint (message ("Unable to resolve function constraints:\n%s", constraintList_printDetailed(body->requiresConstraints) ), g_currentloc);
1159 ConPrint (message ("Splint has found function post conditions:\n%s", constraintList_printDetailed(body->ensuresConstraints) ), g_currentloc);
1161 printf ("The required constraints are:\n%s", constraintList_printDetailed(body->requiresConstraints) );
1162 printf ("The ensures constraints are:\n%s", constraintList_printDetailed(body->ensuresConstraints) );
1165 if (constraintList_isDefined(c) )
1166 constraintList_free(c);
1168 context_exitInnerPlain();
1170 if ( context_getFlag (FLG_GENERATECODE) )
1172 exprNode_spitFunction(ue, body);
1176 /*is it okay not to free this?*/
1177 exprNode_free (body);
1180 void exprChecks_checkEmptyMacroBody (void)
1184 if (!(context_inFunctionLike () || context_inMacroConstant ()
1185 || context_inUnknownMacro ()))
1188 (message ("exprNode_checkEmptyMacroBody: not in macro function or constant: %q",
1189 context_unparse ()));
1193 hdr = context_getHeader ();
1197 if (uentry_isFunction (hdr))
1202 ("Macro definition for %q is empty", uentry_getName (hdr)),
1205 usymtab_checkFinalScope (FALSE);
1208 context_exitFunction ();
1212 void exprNode_checkIterBody (/*@only@*/ exprNode body)
1214 context_exitAllClauses ();
1216 context_exitFunction ();
1217 exprNode_free (body);
1220 void exprNode_checkIterEnd (/*@only@*/ exprNode body)
1222 context_exitAllClauses ();
1223 context_exitFunction ();
1224 exprNode_free (body);
1228 bool checkModifyAuxAux (/*@exposed@*/ sRef s, exprNode f, sRef alias, exprNode err)
1230 bool hasMods = context_hasMods ();
1231 flagcode errCode = hasMods ? FLG_MODIFIES : FLG_MODNOMODS;
1233 if (exprNode_isDefined (f))
1235 f->sets = sRefSet_insert (f->sets, s);
1238 if (context_getFlag (FLG_MODIFIES)
1239 && (hasMods || context_getFlag (FLG_MODNOMODS)))
1241 sRefSet mods = context_modList ();
1243 if (!sRef_canModify (s, mods))
1245 sRef rb = sRef_getRootBase (s);
1248 if (sRef_isFileOrGlobalScope (rb))
1250 if (!context_checkGlobMod (rb))
1256 if (sRef_isInvalid (alias) || sRef_sameName (s, alias))
1258 if (sRef_isLocalVar (sRef_getRootBase (s)))
1263 ("Undocumented modification of internal state (%q): %s",
1264 sRef_unparse (s), exprNode_unparse (err)),
1265 exprNode_isDefined (f) ? f->loc : g_currentloc);
1269 if (sRef_isSystemState (s))
1271 if (errCode == FLG_MODNOMODS)
1273 if (context_getFlag (FLG_MODNOMODS))
1275 errCode = FLG_MODFILESYSTEM;
1280 errCode = FLG_MODFILESYSTEM;
1286 message ("Undocumented modification of %q: %s",
1287 sRef_unparse (s), exprNode_unparse (err)),
1288 exprNode_isDefined (f) ? f->loc : g_currentloc);
1295 if (sRef_isReference (s) && !sRef_isAddress (alias))
1300 ("Possible undocumented modification of %q through alias %q: %s",
1302 sRef_unparse (alias),
1303 exprNode_unparse (err)),
1304 exprNode_isDefined (f) ? f->loc : g_currentloc);
1312 if (context_maybeSet (FLG_MUSTMOD))
1314 (void) sRef_canModify (s, context_modList ());
1317 if (sRef_isRefsField (s))
1319 sRef_setModified (s);
1327 bool checkModifyAux (/*@exposed@*/ sRef s, exprNode f, sRef alias, exprNode err)
1329 DPRINTF (("Check modify aux: %s", sRef_unparseFull (s)));
1331 if (sRef_isReference (s) && sRef_isObserver (s)
1332 && context_maybeSet (FLG_MODOBSERVER))
1336 if (sRef_isPointer (s))
1338 sRef base = sRef_getBase (s);
1339 sname = sRef_unparse (base);
1343 if (sRef_isAddress (s))
1345 sRef p = sRef_constructPointer (s);
1346 sname = sRef_unparse (p);
1350 sname = sRef_unparse (s);
1354 if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1356 if (sRef_isMeaningful (s))
1360 message ("Suspect modification of observer %s: %s",
1361 sname, exprNode_unparse (err)),
1362 exprNode_isDefined (f) ? f->loc : g_currentloc))
1364 sRef_showExpInfo (s);
1371 message ("Suspect modification of observer returned by "
1372 "function call: %s",
1373 exprNode_unparse (err)),
1374 exprNode_isDefined (f) ? f->loc : g_currentloc);
1381 message ("Suspect modification of observer %s through alias %q: %s",
1382 sname, sRef_unparse (alias), exprNode_unparse (err)),
1383 exprNode_isDefined (f) ? f->loc : g_currentloc))
1385 sRef_showExpInfo (s);
1389 cstring_free (sname);
1392 (void) checkModifyAuxAux (s, f, alias, err);
1397 bool checkModifyValAux (/*@exposed@*/ sRef s, exprNode f, sRef alias, exprNode err)
1399 (void) checkModifyAuxAux (s, f, alias, err);
1404 bool checkCallModifyAux (/*@exposed@*/ sRef s, exprNode f, sRef alias, exprNode err)
1406 bool result = FALSE;
1408 DPRINTF (("Check modify aux: %s / %s",
1409 sRef_unparse (s), sRef_unparse (alias)));
1411 if (sRef_isObserver (s) && context_maybeSet (FLG_MODOBSERVER))
1413 sRef p = sRef_isAddress (s) ? sRef_constructPointer (s) : s;
1414 cstring sname = sRef_unparse (p);
1416 if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1418 if (sRef_isMeaningful (s))
1420 result = optgenerror
1422 message ("Suspect modification of observer %s: %s",
1423 sname, exprNode_unparse (err)),
1424 exprNode_isDefined (f) ? f->loc : g_currentloc);
1428 result = optgenerror
1430 message ("Suspect modification of observer returned by "
1431 "function call: %s",
1432 exprNode_unparse (err)),
1433 exprNode_isDefined (f) ? f->loc : g_currentloc);
1438 result = optgenerror
1441 ("Suspect modification of observer %s through alias %q: %s",
1442 sname, sRef_unparse (alias), exprNode_unparse (err)),
1443 exprNode_isDefined (f) ? f->loc : g_currentloc);
1446 cstring_free (sname);
1448 else if (context_maybeSet (FLG_MODIFIES))
1450 DPRINTF (("can modify: %s / %s",
1452 sRefSet_unparse (context_modList ())));
1454 if (!(sRef_canModifyVal (s, context_modList ())))
1456 sRef p = sRef_isAddress (s) ? sRef_constructPointer (s) : s;
1457 cstring sname = sRef_unparse (p);
1458 bool hasMods = context_hasMods ();
1459 sRef rb = sRef_getRootBase (s);
1460 flagcode errCode = hasMods ? FLG_MODIFIES : FLG_MODNOMODS;
1463 DPRINTF (("Can't modify! %s", sRef_unparse (s)));
1465 if (sRef_isFileOrGlobalScope (rb))
1467 uentry ue = sRef_getUentry (rb);
1469 /* be more specific here! */
1470 if (!uentry_isCheckedModify (ue))
1478 if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1480 if (sRef_isLocalVar (sRef_getRootBase (s)))
1485 ("Undocumented modification of internal "
1486 "state (%q) through call to %s: %s",
1487 sRef_unparse (s), exprNode_unparse (f),
1488 exprNode_unparse (err)),
1489 exprNode_isDefined (f) ? f->loc : g_currentloc);
1493 if (sRef_isSystemState (s))
1495 if (errCode == FLG_MODNOMODS)
1497 if (context_getFlag (FLG_MODNOMODS))
1499 errCode = FLG_MODFILESYSTEM;
1504 errCode = FLG_MODFILESYSTEM;
1508 result = optgenerror
1510 message ("Undocumented modification of %s "
1511 "possible from call to %s: %s",
1513 exprNode_unparse (f),
1514 exprNode_unparse (err)),
1515 exprNode_isDefined (f) ? f->loc : g_currentloc);
1520 result = optgenerror
1522 message ("Undocumented modification of %s possible "
1523 "from call to %s (through alias %q): %s",
1525 exprNode_unparse (f),
1526 sRef_unparse (alias),
1527 exprNode_unparse (err)),
1528 exprNode_isDefined (f) ? f->loc : g_currentloc);
1531 cstring_free (sname);
1536 if (context_maybeSet (FLG_MUSTMOD))
1538 (void) sRef_canModifyVal (s, context_modList ());
1545 void exprNode_checkCallModifyVal (sRef s, exprNodeList args, exprNode f, exprNode err)
1547 s = sRef_fixBaseParam (s, args);
1548 DPRINTF (("Check call modify: %s", sRef_unparse (s)));
1549 sRef_aliasCheckPred (checkCallModifyAux, NULL, s, f, err);
1553 exprChecks_checkExport (uentry e)
1555 if (context_checkExport (e))
1557 fileloc fl = uentry_whereDeclared (e);
1559 if (fileloc_isHeader (fl) && !fileloc_isLib (fl)
1560 && !fileloc_isImport (fl) && !uentry_isStatic (e))
1562 if (uentry_isFunction (e) ||
1563 (uentry_isVariable (e) && ctype_isFunction (uentry_getType (e))))
1567 message ("Function exported, but not specified: %q",
1568 uentry_getName (e)),
1571 else if (uentry_isExpandedMacro (e))
1575 message ("Expanded macro exported, but not specified: %q",
1576 uentry_getName (e)),
1579 else if (uentry_isVariable (e) && !uentry_isParam (e))
1583 message ("Variable exported, but not specified: %q",
1584 uentry_getName (e)),
1587 else if (uentry_isEitherConstant (e))
1591 message ("Constant exported, but not specified: %q",
1592 uentry_getName (e)),
1595 else if (uentry_isIter (e) || uentry_isEndIter (e))
1599 message ("Iterator exported, but not specified: %q",
1600 uentry_getName (e)),
1604 else if (uentry_isDatatype (e))
1606 ; /* error already reported */
1616 static void checkSafeReturnExpr (/*@notnull@*/ exprNode e)
1618 ctype tr = ctype_getReturnType (context_currentFunctionType ());
1619 ctype te = exprNode_getType (e);
1621 /* evans 2001-08-21: added test to warn about void returns from void functions */
1622 if (ctype_isVoid (tr))
1625 (te, e, tr, exprNode_undefined,
1626 message ("Return expression from function declared void: %s", exprNode_unparse (e)),
1631 if (!ctype_forceMatch (tr, te) && !exprNode_matchLiteral (tr, e))
1634 (te, e, tr, exprNode_undefined,
1635 message ("Return value type %t does not match declared type %t: %s",
1636 te, tr, exprNode_unparse (e)),
1642 uentry rval = context_getHeader ();
1643 sRef resultref = uentry_getSref (rval);
1645 DPRINTF (("Check return: %s / %s / %s",
1646 exprNode_unparse (e),
1647 sRef_unparseFull (e->sref),
1648 uentry_unparse (rval)));
1650 transferChecks_return (e, rval);
1652 DPRINTF (("After return: %s / %s / %s",
1653 exprNode_unparse (e),
1654 sRef_unparseFull (e->sref),
1655 uentry_unparse (rval)));
1657 if (!(sRef_isExposed (uentry_getSref (context_getHeader ()))
1658 || sRef_isObserver (uentry_getSref (context_getHeader ())))
1659 && (context_getFlag (FLG_RETALIAS)
1660 || context_getFlag (FLG_RETEXPOSE)))
1662 sRef base = sRef_getRootBase (ret);
1663 ctype rtype = e->typ;
1665 if (ctype_isUnknown (rtype))
1670 if (ctype_isVisiblySharable (rtype))
1672 if (context_getFlag (FLG_RETALIAS))
1674 sRef_aliasCheckPred (checkRefGlobParam, NULL, base,
1675 e, exprNode_undefined);
1678 if (context_getFlag (FLG_RETEXPOSE) && sRef_isIReference (ret)
1679 && !sRef_isExposed (resultref) && !sRef_isObserver (resultref))
1681 sRef_aliasCheckPred (checkRepExposed, NULL, base, e,
1682 exprNode_undefined);