]> granicus.if.org Git - clang/commitdiff
Fix a crash in the static analyzer (bug #16307)
authorPavel Labath <labath@google.com>
Wed, 19 Jun 2013 08:19:56 +0000 (08:19 +0000)
committerPavel Labath <labath@google.com>
Wed, 19 Jun 2013 08:19:56 +0000 (08:19 +0000)
Summary:
When processing a call to a function, which got passed less arguments than it
expects, the analyzer would crash.

I've also added a test for that and a analyzer warning which detects these
cases.

CC: cfe-commits
Differential Revision: http://llvm-reviews.chandlerc.com/D994

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184288 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
lib/StaticAnalyzer/Core/CallEvent.cpp
test/Analysis/inline.c
test/Analysis/inline.cpp

index 4965d22996167339bb22fd96dd60ff67984de687..c3c5b5e087f48581ebfde8262f3e06c9b292b584 100644 (file)
@@ -40,6 +40,7 @@ class CallAndMessageChecker
   mutable OwningPtr<BugType> BT_objc_subscript_undef;
   mutable OwningPtr<BugType> BT_msg_arg;
   mutable OwningPtr<BugType> BT_msg_ret;
+  mutable OwningPtr<BugType> BT_call_few_args;
 public:
 
   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
@@ -280,11 +281,33 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
     State = StNonNull;
   }
 
+  const Decl *D = Call.getDecl();
+  if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+    // If we have a declaration, we can make sure we pass enough parameters to
+    // the function.
+    unsigned Params = FD->getNumParams();
+    if (Call.getNumArgs() < Params) {
+      ExplodedNode *N = C.generateSink();
+      if (!N)
+        return;
+
+      LazyInit_BT("Function call with too few arguments", BT_call_few_args);
+
+      SmallString<512> Str;
+      llvm::raw_svector_ostream os(Str);
+      os << "Function taking " << Params << " argument"
+         << (Params == 1 ? "" : "s") << " is called with less ("
+         << Call.getNumArgs() << ")";
+
+      BugReport *R = new BugReport(*BT_call_few_args, os.str(), N);
+      C.emitReport(R);
+    }
+  }
+
   // Don't check for uninitialized field values in arguments if the
   // caller has a body that is available and we have the chance to inline it.
   // This is a hack, but is a reasonable compromise betweens sometimes warning
   // and sometimes not depending on if we decide to inline a function.
-  const Decl *D = Call.getDecl();
   const bool checkUninitFields =
     !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));
 
index dd33e014c3001c4293c348831fffa61ebdbaf895..9ab687475618391837f82ad6deaa6cb3ce7d3c23 100644 (file)
@@ -272,8 +272,11 @@ static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx,
                                          CallEvent::param_iterator E) {
   MemRegionManager &MRMgr = SVB.getRegionManager();
 
+  // If the function has fewer parameters than the call has arguments, we simply
+  // do not bind any values to them.
+  unsigned NumArgs = Call.getNumArgs();
   unsigned Idx = 0;
-  for (; I != E; ++I, ++Idx) {
+  for (; I != E && Idx < NumArgs; ++I, ++Idx) {
     const ParmVarDecl *ParamDecl = *I;
     assert(ParamDecl && "Formal parameter has no decl?");
 
index 8cba63f17e0da3498770371839a13e408f22b5f0..9ecdce33a36d14e5b1643f21684c53109673c7f2 100644 (file)
@@ -110,3 +110,9 @@ void never_called_by_anyone() {
   clang_analyzer_checkInlined(0); // no-warning
 }
 
+
+void knr_one_argument(a) int a; { }
+
+void call_with_less_arguments() {
+  knr_one_argument(); // expected-warning{{too few arguments}} expected-warning{{Function taking 1 argument}}
+}
index 909e18017b34b9d0bebc3d154f7fabca693e1a8e..fad77b3bee436e7de2086fd0f476eb46706c5744 100644 (file)
@@ -420,3 +420,10 @@ namespace rdar12409977  {
     clang_analyzer_eval(obj.getThis()->x == 42); // expected-warning{{TRUE}}
   }
 }
+
+namespace bug16307 {
+  void one_argument(int a) { }
+  void call_with_less() {
+    reinterpret_cast<void (*)()>(one_argument)(); // expected-warning{{Function taking 1 argument}}
+  }
+}