X-Git-Url: http://andersk.mit.edu/gitweb/splint.git/blobdiff_plain/9280addf7928b095ee9e0b047d698c05140726aa..a9ec328054b628447830161535f4915f715f49cd:/src/exprChecks.c diff --git a/src/exprChecks.c b/src/exprChecks.c index 44eb80b..219387b 100644 --- a/src/exprChecks.c +++ b/src/exprChecks.c @@ -1,6 +1,6 @@ /* -** LCLint - annotation-assisted static program checker -** Copyright (C) 1994-2000 University of Virginia, +** Splint - annotation-assisted static program checker +** Copyright (C) 1994-2003 University of Virginia, ** Massachusetts Institute of Technology ** ** This program is free software; you can redistribute it and/or modify it @@ -17,19 +17,19 @@ ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ** MA 02111-1307, USA. ** -** For information on lclint: lclint-request@cs.virginia.edu -** To report a bug: lclint-bug@cs.virginia.edu -** For more information: http://lclint.cs.virginia.edu +** For information on splint: info@splint.org +** To report a bug: splint-bug@splint.org +** For more information: http://www.splint.org */ /* ** exprChecks.c */ -# include "lclintMacros.nf" +# include "splintMacros.nf" # include "basic.h" # include "cgrammar.h" # include "cgrammar_tokens.h" -# include "aliasChecks.h" +# include "transferChecks.h" # include "exprChecks.h" /* @@ -39,9 +39,9 @@ /*@access exprNode@*/ -static bool checkCallModifyAux (sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err); -static bool checkModifyValAux (sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err); -static bool checkModifyAux (sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err); +static bool checkCallModifyAux (/*@exposed@*/ sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err); +static bool checkModifyValAux (/*@exposed@*/ sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err); +static bool checkModifyAux (/*@exposed@*/ sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err); static void checkSafeReturnExpr (/*@notnull@*/ exprNode p_e); /* @@ -52,11 +52,36 @@ static void checkSafeReturnExpr (/*@notnull@*/ exprNode p_e); ** */ +static int inCompoundStatementExpression = 0; + +void +exprChecks_inCompoundStatementExpression (void) +{ + inCompoundStatementExpression++; +} + +void +exprChecks_leaveCompoundStatementExpression (void) +{ + inCompoundStatementExpression--; + llassert (inCompoundStatementExpression >= 0); +} + void -exprNode_checkStatement (exprNode e) +exprChecks_checkStatementEffect (exprNode e) { bool hasError = FALSE; + if (inCompoundStatementExpression > 0) + { + /* + ** Okay to have effectless statments in compound statement expression (should check + ** it is the last statement, but we don't for now). + */ + + return; + } + if (!exprNode_isError (e)) { exprKind ek = e->kind; @@ -206,14 +231,33 @@ checkRefGlobParam (sRef base, /*@notnull@*/ exprNode e, if (ctype_isVisiblySharable (ct)) { - if (sRef_isGlobal (base)) + if (sRef_isFileOrGlobalScope (base)) { - voptgenerror - (FLG_RETALIAS, - message ("Function returns reference to global %q: %s", - sRef_unparse (base), - exprNode_unparse (e)), - e->loc); + uentry fcn = context_getHeader (); + bool noerror = FALSE; + + if (uentry_isValid (fcn) && uentry_isFunction (fcn)) + { + sRef res = uentry_getSref (fcn); + + /* If result is dependent and global is owned, this is okay... */ + if (sRef_isDependent (res) + && sRef_isOwned (base)) + { + noerror = TRUE; + + } + } + + if (!noerror) + { + voptgenerror + (FLG_RETALIAS, + message ("Function returns reference to global %q: %s", + sRef_unparse (base), + exprNode_unparse (e)), + e->loc); + } return TRUE; } @@ -226,7 +270,7 @@ checkRefGlobParam (sRef base, /*@notnull@*/ exprNode e, { uentry arg = uentryList_getN (params, paramno); sRef ref = uentry_getSref (arg); - + if (uentry_isReturned (arg) || sRef_isOnly (ref) || sRef_isExposed (ref) @@ -261,7 +305,7 @@ checkRefGlobParam (sRef base, /*@notnull@*/ exprNode e, { if (ctype_isVisiblySharable (e->typ)) { - if (sRef_isGlobal (base)) + if (sRef_isFileOrGlobalScope (base)) { voptgenerror (FLG_RETALIAS, @@ -325,7 +369,7 @@ exprNode_checkModify (exprNode e, exprNode err) llassert (exprNode_isDefined (e)); DPRINTF (("Check modify: %s", exprNode_unparse (e))); - + if (sRef_isValid (e->sref)) { sRef_aliasCheckPred (checkModifyAux, sRef_isReference, e->sref, e, err); @@ -359,20 +403,20 @@ exprChecks_checkNullReturn (fileloc loc) { if (ctype_isFunction (context_currentFunctionType ())) { - ctype tr = ctype_returnValue (context_currentFunctionType ()); + ctype tr = ctype_getReturnType (context_currentFunctionType ()); if (!ctype_isFirstVoid (tr)) { if (ctype_isUnknown (tr)) { voptgenerror - (FLG_CONTROL, + (FLG_EMPTYRETURN, cstring_makeLiteral ("Empty return in function declared to implicitly return int"), loc); } else { - voptgenerror (FLG_CONTROL, + voptgenerror (FLG_EMPTYRETURN, message ("Empty return in function declared to return %t", tr), loc); } @@ -390,7 +434,7 @@ exprNode_checkReturn (exprNode e) { if (context_inMacro ()) { - llerror (FLG_CONTROL, + llerror (FLG_MACRORETURN, message ("Macro %s uses return (not functional)", context_inFunctionName ())); } @@ -434,7 +478,8 @@ exprNode_checkPred (cstring c, exprNode e) e->loc); } - if (ctype_isRealBool (ct)) + if (ctype_isRealBool (ct) || ctype_isUnknown (ct)) + /* evs 2000-12-20 added || ctype_isUnknown to avoid spurious messages */ { ; } @@ -618,7 +663,7 @@ void exprNode_checkMacroBody (/*@only@*/ exprNode e) uentry hdr; if (!(context_inFunctionLike () || context_inMacroConstant () - || context_inMacroUnknown ())) + || context_inUnknownMacro ())) { llcontbug (message @@ -712,7 +757,7 @@ void exprNode_checkMacroBody (/*@only@*/ exprNode e) } } } - else if (context_inMacroFunction () || context_inMacroUnknown ()) + else if (context_inMacroFunction () || context_inUnknownMacro ()) { ctype rettype = context_getRetType (); @@ -762,7 +807,7 @@ void exprNode_checkMacroBody (/*@only@*/ exprNode e) e->loc); } - e->typ = ctype_returnValue (e->typ); + e->typ = ctype_getReturnType (e->typ); rettype = e->typ; /* avoid aditional errors */ } } @@ -802,7 +847,7 @@ void exprNode_checkMacroBody (/*@only@*/ exprNode e) case XPR_STRINGLITERAL: case XPR_NUMLIT: case XPR_FACCESS: case XPR_OFFSETOF: - checkReturnTransfer (e, hdr); + transferChecks_return (e, hdr); break; /* these expressions don't */ @@ -862,7 +907,7 @@ void exprNode_checkFunctionBody (exprNode body) && context_inRealFunction () && ctype_isFunction (context_currentFunctionType ())) { - ctype tr = ctype_returnValue (context_currentFunctionType ()); + ctype tr = ctype_getReturnType (context_currentFunctionType ()); if (!ctype_isFirstVoid (tr)) { @@ -883,8 +928,6 @@ void exprNode_checkFunctionBody (exprNode body) } } } - - exprNode_checkFunction (context_getHeader (), body); if (!checkret) { @@ -894,65 +937,174 @@ void exprNode_checkFunctionBody (exprNode body) } /*drl modified */ + void exprNode_checkFunction (/*@unused@*/ uentry ue, /*@only@*/ exprNode body) { - constraintList c, t; - constraintList c2, fix; + constraintList c, t, post; + constraintList c2, fix; + context_enterInnerContext (); - // return; + llassert (exprNode_isDefined (body)); + + DPRINTF (("Checking body: %s", exprNode_unparse (body))); + + /* + if we're not going to be printing any errors for buffer overflows + we can skip the checking to improve performance + + FLG_DEBUGFUNCTIONCONSTRAINT controls wheather we perform the check anyway + in order to find potential problems like assert failures and seg faults... + */ + + if (!(context_getFlag (FLG_DEBUGFUNCTIONCONSTRAINT) + || context_getFlag (FLG_BOUNDSWRITE) + || context_getFlag (FLG_BOUNDSREAD) + || context_getFlag (FLG_LIKELYBOUNDSWRITE) + || context_getFlag (FLG_LIKELYBOUNDSREAD) + || context_getFlag (FLG_CHECKPOST) + || context_getFlag (FLG_ALLOCMISMATCH))) + { + exprNode_free (body); + context_exitInnerPlain(); + return; + } + + exprNode_generateConstraints (body); /* evans 2002-03-02: this should not be declared to take a + dependent... fix it! */ - exprNode_generateConstraints (body); + c = uentry_getFcnPreconditions (ue); - c = uentry_getFcnPreconditions (ue); - DPRINTF(("function constraints\n")); - DPRINTF (("\n\n\n\n\n\n\n")); + if (constraintList_isDefined (c)) + { + DPRINTF (("Function preconditions are %s", constraintList_unparseDetailed (c))); + + body->requiresConstraints = + constraintList_reflectChangesFreePre (body->requiresConstraints, c); + + c2 = constraintList_copy (c); + fix = constraintList_makeFixedArrayConstraints (body->uses); + c2 = constraintList_reflectChangesFreePre (c2, fix); - context_enterInnerContext (); + constraintList_free (fix); + + if (context_getFlag (FLG_ORCONSTRAINT)) + { + t = constraintList_reflectChangesOr (body->requiresConstraints, c2 ); + } + else + { + t = constraintList_reflectChanges(body->requiresConstraints, c2); + } + + constraintList_free (body->requiresConstraints); + DPRINTF ((message ("The body has the required constraints: %s", constraintList_unparseDetailed (t) ) ) ); + + body->requiresConstraints = t; + + t = constraintList_mergeEnsures (c, body->ensuresConstraints); + constraintList_free(body->ensuresConstraints); + + body->ensuresConstraints = t; + + DPRINTF ((message ("The body has the ensures constraints: %s", constraintList_unparseDetailed (t) ) ) ); + constraintList_free(c2); + } - if (c) - { - llassert (c); - DPRINTF ( (message ("Function preconditions are %s \n\n\n\n\n", constraintList_printDetailed (c) ) ) ); - - t = reflectChanges (body->requiresConstraints, constraintList_copy (c) ); - body->requiresConstraints = constraintList_copy (t); - - c2 = constraintList_copy (c); - fix = constraintList_makeFixedArrayConstraints (body->uses); - c2 = reflectChanges (c2, constraintList_copy(fix) ); - - t = reflectChanges (body->requiresConstraints, constraintList_copy (c2) ); - body->requiresConstraints = constraintList_copy (t); - - DPRINTF ( (message ("The body has the required cosntraints: %s", constraintList_printDetailed (t) ) ) ); - t = constraintList_mergeEnsures (c, body->ensuresConstraints); - - body->ensuresConstraints = constraintList_copy (t); + if (constraintList_isDefined(c)) + { + DPRINTF ((message ("The Function %s has the preconditions %s", + uentry_unparse(ue), constraintList_unparseDetailed(c)))); + } + else + { + DPRINTF((message ("The Function %s has no preconditions", uentry_unparse(ue)))); + } + + if (context_getFlag (FLG_IMPBOUNDSCONSTRAINTS)) + { + constraintList implicitFcnConstraints = context_getImplicitFcnConstraints (ue); + + if (constraintList_isDefined (implicitFcnConstraints)) + { + DPRINTF (("Implicit constraints: %s", constraintList_unparse (implicitFcnConstraints))); + + body->requiresConstraints = constraintList_reflectChangesFreePre (body->requiresConstraints, + implicitFcnConstraints); + constraintList_free (implicitFcnConstraints); + } + else + { + DPRINTF (("No implicit constraints")); + } + } + + body->requiresConstraints = constraintList_sort (body->requiresConstraints); + + constraintList_printError(body->requiresConstraints, g_currentloc); + + post = uentry_getFcnPostconditions (ue); + + if (context_getFlag (FLG_CHECKPOST)) + { + if (constraintList_isDefined (post)) + { + constraintList post2; + + DPRINTF ((message ("The declared function postconditions are %s \n\n\n\n\n", + constraintList_unparseDetailed (post) ) ) ); + + post = constraintList_reflectChangesFreePre (post, body->ensuresConstraints); + + post2 = constraintList_copy (post); + fix = constraintList_makeFixedArrayConstraints (body->uses); + post2 = constraintList_reflectChangesFreePre (post2, fix); + constraintList_free(fix); + if ( context_getFlag (FLG_ORCONSTRAINT) ) + { + t = constraintList_reflectChangesOr (post2, body->ensuresConstraints); + } + else + { + t = constraintList_reflectChanges(post2, body->ensuresConstraints); + } + + constraintList_free(post2); + constraintList_free(post); + post = t; + + printf("Unresolved post conditions\n"); + constraintList_printErrorPostConditions(post, g_currentloc); + } + } + + if (constraintList_isDefined (post)) + { + constraintList_free (post); + } - DPRINTF ( (message ("The body has the ensures constraints: %s", constraintList_printDetailed (t) ) ) ); - } + body->ensuresConstraints = constraintList_sort(body->ensuresConstraints); - if (c) - { - DPRINTF((message ("The Function %s has the preconditions %s", uentry_unparse(ue), constraintList_printDetailed(c) ) ) ); - } - else + if ( context_getFlag (FLG_FUNCTIONPOST) ) { - DPRINTF((message ("The Function %s has no preconditions", uentry_unparse(ue) ) ) ); + constraintList_printError(body->ensuresConstraints, g_currentloc); } - - constraintList_printError(body->requiresConstraints, g_currentloc); - constraintList_printError(body->ensuresConstraints, g_currentloc); - // ConPrint (message ("Unable to resolve function constraints:\n%s", constraintList_printDetailed(body->requiresConstraints) ), g_currentloc); + /* ConPrint (message ("Unable to resolve function constraints:\n%s", constraintList_printDetailed(body->requiresConstraints) ), g_currentloc); - // ConPrint (message ("LCLint has found function post conditions:\n%s", constraintList_printDetailed(body->ensuresConstraints) ), g_currentloc); + ConPrint (message ("Splint has found function post conditions:\n%s", constraintList_printDetailed(body->ensuresConstraints) ), g_currentloc); - // printf ("The required constraints are:\n%s", constraintList_printDetailed(body->requiresConstraints) ); - // printf ("The ensures constraints are:\n%s", constraintList_printDetailed(body->ensuresConstraints) ); + printf ("The required constraints are:\n%s", constraintList_printDetailed(body->requiresConstraints) ); + printf ("The ensures constraints are:\n%s", constraintList_unparseDetailed(body->ensuresConstraints) ); + */ + if (constraintList_isDefined (c)) + constraintList_free(c); + context_exitInnerPlain(); - /* exprNode_free (body); */ + + /* is it okay not to free this? */ + DPRINTF (("Done checking constraints...")); + exprNode_free (body); } void exprChecks_checkEmptyMacroBody (void) @@ -960,7 +1112,7 @@ void exprChecks_checkEmptyMacroBody (void) uentry hdr; if (!(context_inFunctionLike () || context_inMacroConstant () - || context_inMacroUnknown ())) + || context_inUnknownMacro ())) { llcontbug (message ("exprNode_checkEmptyMacroBody: not in macro function or constant: %q", @@ -1003,7 +1155,7 @@ void exprNode_checkIterEnd (/*@only@*/ exprNode body) } static -bool checkModifyAuxAux (sRef s, exprNode f, sRef alias, exprNode err) +bool checkModifyAuxAux (/*@exposed@*/ sRef s, exprNode f, sRef alias, exprNode err) { bool hasMods = context_hasMods (); flagcode errCode = hasMods ? FLG_MODIFIES : FLG_MODNOMODS; @@ -1017,20 +1169,20 @@ bool checkModifyAuxAux (sRef s, exprNode f, sRef alias, exprNode err) && (hasMods || context_getFlag (FLG_MODNOMODS))) { sRefSet mods = context_modList (); - + if (!sRef_canModify (s, mods)) { sRef rb = sRef_getRootBase (s); - - if (sRef_isGlobal (rb)) + + if (sRef_isFileOrGlobalScope (rb)) { if (!context_checkGlobMod (rb)) { - return FALSE; + return FALSE; } } - + if (sRef_isInvalid (alias) || sRef_sameName (s, alias)) { if (sRef_isLocalVar (sRef_getRootBase (s))) @@ -1102,7 +1254,7 @@ bool checkModifyAuxAux (sRef s, exprNode f, sRef alias, exprNode err) } static -bool checkModifyAux (sRef s, exprNode f, sRef alias, exprNode err) +bool checkModifyAux (/*@exposed@*/ sRef s, exprNode f, sRef alias, exprNode err) { DPRINTF (("Check modify aux: %s", sRef_unparseFull (s))); @@ -1172,17 +1324,20 @@ bool checkModifyAux (sRef s, exprNode f, sRef alias, exprNode err) } static -bool checkModifyValAux (sRef s, exprNode f, sRef alias, exprNode err) +bool checkModifyValAux (/*@exposed@*/ sRef s, exprNode f, sRef alias, exprNode err) { (void) checkModifyAuxAux (s, f, alias, err); return FALSE; } static -bool checkCallModifyAux (sRef s, exprNode f, sRef alias, exprNode err) +bool checkCallModifyAux (/*@exposed@*/ sRef s, exprNode f, sRef alias, exprNode err) { bool result = FALSE; + DPRINTF (("Check modify aux: %s / %s", + sRef_unparse (s), sRef_unparse (alias))); + if (sRef_isObserver (s) && context_maybeSet (FLG_MODOBSERVER)) { sRef p = sRef_isAddress (s) ? sRef_constructPointer (s) : s; @@ -1222,6 +1377,10 @@ bool checkCallModifyAux (sRef s, exprNode f, sRef alias, exprNode err) } else if (context_maybeSet (FLG_MODIFIES)) { + DPRINTF (("can modify: %s / %s", + sRef_unparse (s), + sRefSet_unparse (context_modList ()))); + if (!(sRef_canModifyVal (s, context_modList ()))) { sRef p = sRef_isAddress (s) ? sRef_constructPointer (s) : s; @@ -1230,8 +1389,10 @@ bool checkCallModifyAux (sRef s, exprNode f, sRef alias, exprNode err) sRef rb = sRef_getRootBase (s); flagcode errCode = hasMods ? FLG_MODIFIES : FLG_MODNOMODS; bool check = TRUE; - - if (sRef_isGlobal (rb)) + + DPRINTF (("Can't modify! %s", sRef_unparse (s))); + + if (sRef_isFileOrGlobalScope (rb)) { uentry ue = sRef_getUentry (rb); @@ -1314,6 +1475,7 @@ bool checkCallModifyAux (sRef s, exprNode f, sRef alias, exprNode err) void exprNode_checkCallModifyVal (sRef s, exprNodeList args, exprNode f, exprNode err) { s = sRef_fixBaseParam (s, args); + DPRINTF (("Check call modify: %s", sRef_unparse (s))); sRef_aliasCheckPred (checkCallModifyAux, NULL, s, f, err); } @@ -1383,9 +1545,19 @@ exprChecks_checkExport (uentry e) static void checkSafeReturnExpr (/*@notnull@*/ exprNode e) { - ctype tr = ctype_returnValue (context_currentFunctionType ()); + ctype tr = ctype_getReturnType (context_currentFunctionType ()); ctype te = exprNode_getType (e); + /* evans 2001-08-21: added test to warn about void returns from void functions */ + if (ctype_isVoid (tr)) + { + (void) gentypeerror + (te, e, tr, exprNode_undefined, + message ("Return expression from function declared void: %s", exprNode_unparse (e)), + e->loc); + return; + } + if (!ctype_forceMatch (tr, te) && !exprNode_matchLiteral (tr, e)) { (void) gentypeerror @@ -1400,7 +1572,17 @@ static void checkSafeReturnExpr (/*@notnull@*/ exprNode e) uentry rval = context_getHeader (); sRef resultref = uentry_getSref (rval); - checkReturnTransfer (e, rval); + DPRINTF (("Check return: %s / %s / %s", + exprNode_unparse (e), + sRef_unparseFull (e->sref), + uentry_unparse (rval))); + + transferChecks_return (e, rval); + + DPRINTF (("After return: %s / %s / %s", + exprNode_unparse (e), + sRef_unparseFull (e->sref), + uentry_unparse (rval))); if (!(sRef_isExposed (uentry_getSref (context_getHeader ())) || sRef_isObserver (uentry_getSref (context_getHeader ()))) @@ -1434,3 +1616,7 @@ static void checkSafeReturnExpr (/*@notnull@*/ exprNode e) } } + + + +