Hi,

I've extended the check that warns for uninitialized arguments to:
- warn for pointer arguments that point to uninitialized local (stack) 
variables.
- warn for function calls with uninitialized arguments, when the corresponding 
function parameter is a const reference.

void doStuff(const int *p);
void doStuffRef(const int& c);

void f(void) {
      int x;
      doStuff(&x);  // warning
}
void g(void) {
      int x;
      doStuffRef(x); // warning


I've also parameterize the CallAndMessageChecker in a similar way as 
CheckSecuritySyntaxOnly.

that is:
// only check if arguments are uninitialized (the old functionality only)
clang -cc1 -analyze -analyzer-checker=core.callandmessage uninit-const.cpp

// with extended functionality, i.e. "check if const pointer arguments are 
uninitialized" (also performs the old check).
clang -cc1 -analyze 
-analyzer-checker=alpha.core.CallAndMessageUnInitRefArgChecker uninit-const.cpp


/Per

.......................................................................................................................
Per Viberg Senior Engineer
Evidente ES East AB  Warfvinges väg 34  SE-112 51 Stockholm  Sweden
Phone:    +46 (0)8 402 79 00
Mobile:    +46 (0)70 912 42 52
E-mail:     [email protected]<mailto:[email protected]>

www.evidente.se<http://www.evidente.se>
This e-mail, which might contain confidential information, is addressed to the 
above stated person/company. If you are not the correct addressee, employee or 
in any other way the person concerned, please notify the sender immediately. At 
the same time, please delete this e-mail and destroy any prints. Thank You.
Index: lib/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- lib/StaticAnalyzer/Checkers/Checkers.td	(revision 201572)
+++ lib/StaticAnalyzer/Checkers/Checkers.td	(working copy)
@@ -18,6 +18,7 @@
 def Core : Package<"core">;
 def CoreBuiltin : Package<"builtin">, InPackage<Core>;
 def CoreUninitialized  : Package<"uninitialized">, InPackage<Core>;
+def CoreCallAndMessage : Package<"callandmessage">, InPackage<Core>;
 def CoreAlpha : Package<"core">, InPackage<Alpha>, Hidden;
 
 def Cplusplus : Package<"cplusplus">;
@@ -56,10 +57,6 @@
   HelpText<"Check for dereferences of null pointers">,
   DescFile<"DereferenceChecker.cpp">;
 
-def CallAndMessageChecker : Checker<"CallAndMessage">,
-  HelpText<"Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers)">,
-  DescFile<"CallAndMessageChecker.cpp">;
-
 def NonNullParamChecker : Checker<"NonNullParamChecker">,
   HelpText<"Check for null pointers passed as arguments to a function whose arguments are references or marked with the 'nonnull' attribute">,
   DescFile<"NonNullParamChecker.cpp">;
@@ -119,6 +116,10 @@
 def SizeofPointerChecker : Checker<"SizeofPtr">,
   HelpText<"Warn about unintended use of sizeof() on pointer expressions">,
   DescFile<"CheckSizeofPointer.cpp">;
+  
+def CallAndMessageUnInitRefArgChecker : Checker<"CallAndMessageUnInitRefArgChecker">,
+  HelpText<"Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers, and pointer to undefined variables)">,
+  DescFile<"CallAndMessageChecker.cpp">;
 
 } // end "alpha.core"
 
@@ -167,6 +168,16 @@
 } // end "core.uninitialized"
 
 //===----------------------------------------------------------------------===//
+// CallAndMessage checker.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = CoreCallAndMessage in {
+def CallAndMessageChecker : Checker<"CallAndMessageChecker">,
+  HelpText<"Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers)">,
+  DescFile<"CallAndMessageChecker.cpp">;
+}
+
+//===----------------------------------------------------------------------===//
 // C++ checkers.
 //===----------------------------------------------------------------------===//
 
Index: lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp	(revision 201572)
+++ lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp	(working copy)
@@ -27,6 +27,16 @@
 using namespace ento;
 
 namespace {
+
+struct ChecksFilter {
+  DefaultBool check_CallAndMessageUnInitRefArgChecker;
+  DefaultBool check_CallAndMessageChecker;
+
+  CheckName checkName_CallAndMessageUnInitRefArgChecker;
+  CheckName checkName_CallAndMessageChecker;
+};
+
+
 class CallAndMessageChecker
   : public Checker< check::PreStmt<CallExpr>,
                     check::PreStmt<CXXDeleteExpr>,
@@ -44,8 +54,13 @@
   mutable OwningPtr<BugType> BT_msg_arg;
   mutable OwningPtr<BugType> BT_msg_ret;
   mutable OwningPtr<BugType> BT_call_few_args;
+
 public:
 
+  ChecksFilter filter;
+  CallAndMessageChecker()
+  : filter() {}
+
   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
   void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
@@ -55,7 +70,7 @@
   bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange,
                           const Expr *argEx, bool IsFirstArgument,
                           bool checkUninitFields, const CallEvent &Call,
-                          OwningPtr<BugType> &BT) const;
+                          OwningPtr<BugType> &BT, const ParmVarDecl* ParamDecl) const;
 
   static void emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE);
   void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg,
@@ -114,12 +129,53 @@
 }
 
 bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
-                                               SVal V, SourceRange argRange,
+                                               SVal V,
+                                               SourceRange argRange,
                                                const Expr *argEx,
                                                bool IsFirstArgument,
                                                bool checkUninitFields,
                                                const CallEvent &Call,
-                                               OwningPtr<BugType> &BT) const {
+                                               OwningPtr<BugType> &BT,
+                                               const ParmVarDecl *ParamDecl
+                                               ) const {
+  if (filter.check_CallAndMessageUnInitRefArgChecker) {
+    // If parameter is declared as pointer to const in function declaration,
+    // then check if corresponding argument in function call is
+    // pointing to undefined symbol value (uninitialized memory).
+    bool ParamIsPointerToConst = false;
+    bool ParamIsReferenceToConst = false;
+    StringRef Message;
+
+    //ParamIsPointer
+    //ParamIsReference
+    if (ParamDecl->getType().getTypePtr()->isPointerType()) {
+      ParamIsPointerToConst = ParamDecl->getType().getTypePtr()
+                                     ->getPointeeType().isConstQualified();
+      Message = "Function call argument is a pointer to uninitialized value";
+    } else if (ParamDecl->getType().getTypePtr()->isReferenceType()) {
+      ParamIsReferenceToConst = ParamDecl->getType().getTypePtr()
+                                     ->getPointeeType().isConstQualified();
+      Message = "Function call argument is an uninitialized value";
+    }
+    if (ParamIsPointerToConst || ParamIsReferenceToConst) {
+      if (const MemRegion *SValMemRegion = V.getAsRegion()) {
+        const ProgramStateRef State = C.getState();
+        const SVal PSV = State->getSVal(SValMemRegion);
+        if (PSV.isUndef()) {
+          if (ExplodedNode *N = C.generateSink()) {
+            LazyInit_BT("Uninitialized argument value", BT);
+            BugReport *R = new BugReport(*BT,Message,N);
+            R->addRange(argRange);
+            if (argEx)
+              bugreporter::trackNullOrUndefValue(N, argEx, *R);
+            C.emitReport(R);
+          }
+          return true;
+        }
+      }
+    }
+  }
+
   if (V.isUndef()) {
     if (ExplodedNode *N = C.generateSink()) {
       LazyInit_BT("Uninitialized argument value", BT);
@@ -311,8 +367,10 @@
     State = StNonNull;
   }
 
+
   const Decl *D = Call.getDecl();
-  if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
+  if (FD) {
     // If we have a declaration, we can make sure we pass enough parameters to
     // the function.
     unsigned Params = FD->getNumParams();
@@ -347,11 +405,13 @@
   else
     BT = &BT_call_arg;
 
-  for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i)
+  for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {
+    const ParmVarDecl* ParamDecl = FD->getParamDecl(i);
     if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
                            Call.getArgExpr(i), /*IsFirstArgument=*/i == 0,
-                           checkUninitFields, Call, *BT))
+                           checkUninitFields, Call, *BT, ParamDecl))
       return;
+  }
 
   // If we make it here, record our assumptions about the callee.
   C.addTransition(State);
@@ -511,6 +571,14 @@
   C.addTransition(state);
 }
 
-void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
-  mgr.registerChecker<CallAndMessageChecker>();
-}
+#define REGISTER_CHECKER(name)                                                 \
+  void ento::register##name(CheckerManager &mgr) {                             \
+    CallAndMessageChecker *checker =                                           \
+        mgr.registerChecker<CallAndMessageChecker>();                          \
+    checker->filter.check_##name = true;                                       \
+    checker->filter.checkName_##name = mgr.getCurrentCheckName();              \
+  }
+
+REGISTER_CHECKER(CallAndMessageUnInitRefArgChecker)
+REGISTER_CHECKER(CallAndMessageChecker)
+
Index: test/Analysis/uninit-const.c
===================================================================
--- test/Analysis/uninit-const.c	(revision 0)
+++ test/Analysis/uninit-const.c	(working copy)
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core.CallAndMessageUnInitRefArgChecker uninit-const.c -verify %s
+// Passing uninitialized const data to function
+
+
+void doStuff3(const int y){}
+void doStuff2(int g){}
+void doStuff_uninit(const int *u){};
+
+void f5(void) {
+  int t;
+  int* tp = &t;
+  doStuff_uninit(tp);  // expected-warning {{Function call argument is a pointer to uninitialized value}}
+}
+
+
+void f4(void) {
+      int y;
+      doStuff3(y);  // expected-warning {{Function call argument is an uninitialized value}}
+}
+
+void f3(void) {
+      int g;
+      doStuff2(g); // expected-warning {{Function call argument is an uninitialized value}}
+}
+
+int z;
+void f2(void) {
+      doStuff_uninit(&z);  // no warning
+}
+
+void f1(void) {
+      int x_=5;
+      doStuff_uninit(&x_);  // no warning
+}
+
+void f_uninit(void) {
+      int x;
+      doStuff_uninit(&x);  // expected-warning {{Function call argument is a pointer to uninitialized value}}
+}
Index: test/Analysis/uninit-const.cpp
===================================================================
--- test/Analysis/uninit-const.cpp	(revision 0)
+++ test/Analysis/uninit-const.cpp	(working copy)
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.core.CallAndMessageUnInitRefArgChecker uninit-const.cpp -verify %s
+// Passing uninitialized const data to unknown function
+
+void doStuff6(const int& c);
+void doStuff4(const int y);
+void doStuff3(int& g);
+void doStuff_uninit(const int *u);
+
+
+void f7(void) {
+  int m = 3;
+  doStuff6(m); // no warning
+}
+
+void f6(void) {
+  int k;
+  doStuff6(k); // expected-warning {{Function call argument is an uninitialized value}}
+}
+
+void f5(void) {
+  int t;
+  int* tp = &t;
+  doStuff_uninit(tp);  // expected-warning {{Function call argument is a pointer to uninitialized value}}
+}
+
+
+void f4(void) {
+      int y;
+      doStuff4(y);  // expected-warning {{Function call argument is an uninitialized value}}
+}
+
+void f3(void) {
+      int g;
+      doStuff3(g); // no warning
+}
+
+int z;
+void f2(void) {
+      doStuff_uninit(&z);  // no warning
+}
+
+void f1(void) {
+      int x_=5;
+      doStuff_uninit(&x_);  // no warning
+}
+
+void f_uninit(void) {
+      int x;
+      doStuff_uninit(&x);  // expected-warning {{Function call argument is a pointer to uninitialized value}}
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to