]> andersk Git - splint.git/blobdiff - src/exprChecks.c
Fixes for win32
[splint.git] / src / exprChecks.c
index ee0def2fed975dcf489e6cd8ed69e3164ee265ab..ae0ed4f0d57334f470dfb257e09e814c9919db18 100644 (file)
@@ -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
 ** 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)) 
            {
@@ -890,9 +935,170 @@ void exprNode_checkFunctionBody (exprNode body)
        }
     }
 }
-      
+/*drl modified */
+
+
 void exprNode_checkFunction (/*@unused@*/ uentry ue, /*@only@*/ exprNode body)
 {
+  constraintList c, t, post;
+  constraintList c2, fix;
+  constraintList implicitFcnConstraints;
+  context_enterInnerContext ();
+
+  llassert (exprNode_isDefined (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))
+    {
+      /* check if errors will printed */
+      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) ))
+       {
+         exprNode_free (body);
+         context_exitInnerPlain();
+         
+         return;
+       }
+    }
+  
+  exprNode_generateConstraints (body); /* evans 2002-03-02: this should not be declared to take a
+                                         dependent... fix it! */
+  
+  c =   uentry_getFcnPreconditions (ue);
+  DPRINTF(("function constraints\n"));
+  DPRINTF (("\n\n\n\n\n\n\n"));
+  
+  if (constraintList_isDefined(c) )
+    {
+      DPRINTF ((message ("Function preconditions are %s \n\n\n\n\n", constraintList_printDetailed (c) ) ) );
+      
+      body->requiresConstraints = constraintList_reflectChangesFreePre (body->requiresConstraints, c);
+      
+      c2  =  constraintList_copy (c);
+      fix =  constraintList_makeFixedArrayConstraints (body->uses);
+      c2  =  constraintList_reflectChangesFreePre (c2, fix);
+      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_printDetailed (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_printDetailed (t) ) ) );
+      constraintList_free(c2);
+    }
+  
+  if (constraintList_isDefined(c))
+    {
+      DPRINTF ((message ("The Function %s has the preconditions %s", 
+                        uentry_unparse(ue), constraintList_printDetailed(c))));
+    }
+  else
+    {
+      DPRINTF((message ("The Function %s has no preconditions", uentry_unparse(ue))));
+    }
+  
+  implicitFcnConstraints = getImplicitFcnConstraints();
+  
+  if (constraintList_isDefined(implicitFcnConstraints) )
+    {
+      if (context_getFlag (FLG_IMPLICTCONSTRAINT) )
+       {
+         body->requiresConstraints = constraintList_reflectChangesFreePre (body->requiresConstraints, 
+                                                                           implicitFcnConstraints );
+       }
+    }
+  
+  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_printDetailed (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);
+    }
+   
+   body->ensuresConstraints = constraintList_sort(body->ensuresConstraints);
+
+   if ( context_getFlag (FLG_FUNCTIONPOST) )
+     {
+       constraintList_printError(body->ensuresConstraints, g_currentloc);
+     }
+   
+   /*   ConPrint (message ("Unable to resolve function constraints:\n%s", constraintList_printDetailed(body->requiresConstraints) ), 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) );
+   */
+   
+   if (constraintList_isDefined(c) )
+     constraintList_free(c);
+
+   context_exitInnerPlain();
+
+   /*is it okay not to free this?*/
   exprNode_free (body);
   }
 
@@ -901,7 +1107,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", 
@@ -944,7 +1150,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;
@@ -958,20 +1164,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)))
@@ -1043,7 +1249,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)));
 
@@ -1113,17 +1319,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;
@@ -1163,6 +1372,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;
@@ -1171,8 +1384,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);
              
@@ -1255,6 +1470,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);
 }
 
@@ -1324,9 +1540,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
@@ -1341,7 +1567,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 ())))
@@ -1375,3 +1611,7 @@ static void checkSafeReturnExpr (/*@notnull@*/ exprNode e)
     }
 }
 
+
+
+
+
This page took 0.063482 seconds and 4 git commands to generate.