[cfe-commits] r163548 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h lib/StaticAnalyzer/Core/AnalyzerOptions.cpp lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp test/Analysis/inlining/stl.cpp test/Analysis/system-header-simulator-cxx.h test/Analysis/temp-obj-dtors-cfg-output.cpp test/Analysis/templates.cpp

Jordan Rose jordan_rose at apple.com
Mon Sep 10 14:27:36 PDT 2012


Author: jrose
Date: Mon Sep 10 16:27:35 2012
New Revision: 163548

URL: http://llvm.org/viewvc/llvm-project?rev=163548&view=rev
Log:
[analyzer] For now, don't inline C++ standard library functions.

This is a (heavy-handed) solution to PR13724 -- until we know we can do
a good job inlining the STL, it's best to be consistent and not generate
more false positives than we did before. We can selectively whitelist
certain parts of the 'std' namespace that are known to be safe.

This is controlled by analyzer config option 'c++-stdlib-inlining', which
can be set to "true" or "false".

This commit also adds control for whether or not to inline any templated
functions (member or non-member), under the config option
'c++-template-inlining'. This option is currently on by default.

Added:
    cfe/trunk/test/Analysis/inlining/stl.cpp
    cfe/trunk/test/Analysis/system-header-simulator-cxx.h
Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
    cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
    cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp
    cfe/trunk/test/Analysis/templates.cpp

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h?rev=163548&r1=163547&r2=163548&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h Mon Sep 10 16:27:35 2012
@@ -17,7 +17,9 @@
 
 #include <string>
 #include <vector>
+#include "clang/Basic/LLVM.h"
 #include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 
 namespace clang {
@@ -166,6 +168,12 @@
 private:
   /// Controls which C++ member functions will be considered for inlining.
   CXXInlineableMemberKind CXXMemberInliningMode;
+  
+  llvm::Optional<bool> IncludeTemporaryDtorsInCFG;
+  llvm::Optional<bool> InlineCXXStandardLibrary;
+  llvm::Optional<bool> InlineTemplateFunctions;
+  
+  bool getBooleanOption(StringRef Name, bool DefaultVal = false) const;
 
 public:
   /// Returns the option controlling which C++ member functions will be
@@ -183,6 +191,19 @@
   /// non-empty value is considered to be 'true'.
   bool includeTemporaryDtorsInCFG() const;
 
+  /// Returns whether or not C++ standard library functions may be considered
+  /// for inlining.
+  ///
+  /// This is controlled by the 'c++-stdlib-inlining' config option, which
+  /// accepts the values "true" and "false".
+  bool mayInlineCXXStandardLibrary() const;
+
+  /// Returns whether or not templated functions may be considered for inlining.
+  ///
+  /// This is controlled by the 'c++-template-inlining' config option, which
+  /// accepts the values "true" and "false".
+  bool mayInlineTemplateFunctions() const;
+
 public:
   AnalyzerOptions() : CXXMemberInliningMode() {
     AnalysisStoreOpt = RegionStoreModel;

Modified: cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp?rev=163548&r1=163547&r2=163548&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp Mon Sep 10 16:27:35 2012
@@ -47,6 +47,36 @@
   return CXXMemberInliningMode >= K;
 }
 
+bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal) const {
+  // FIXME: We should emit a warning here if the value is something other than
+  // "true", "false", or the empty string (meaning the default value),
+  // but the AnalyzerOptions doesn't have access to a diagnostic engine.
+  return llvm::StringSwitch<bool>(Config.lookup(Name))
+    .Case("true", true)
+    .Case("false", false)
+    .Default(DefaultVal);
+}
+
 bool AnalyzerOptions::includeTemporaryDtorsInCFG() const {
-  return !Config.lookup("cfg-temporary-dtors").empty();
+  if (!IncludeTemporaryDtorsInCFG.hasValue())
+    const_cast<llvm::Optional<bool> &>(IncludeTemporaryDtorsInCFG) =
+      getBooleanOption("cfg-temporary-dtors");
+  
+  return *IncludeTemporaryDtorsInCFG;
+}
+
+bool AnalyzerOptions::mayInlineCXXStandardLibrary() const {
+  if (!InlineCXXStandardLibrary.hasValue())
+    const_cast<llvm::Optional<bool> &>(InlineCXXStandardLibrary) =
+      getBooleanOption("c++-stdlib-inlining");
+  
+  return *InlineCXXStandardLibrary;
+}
+
+bool AnalyzerOptions::mayInlineTemplateFunctions() const {
+  if (!InlineTemplateFunctions.hasValue())
+    const_cast<llvm::Optional<bool> &>(InlineTemplateFunctions) =
+      getBooleanOption("c++-template-inlining", /*Default=*/true);
+  
+  return *InlineTemplateFunctions;
 }

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=163548&r1=163547&r2=163548&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Mon Sep 10 16:27:35 2012
@@ -257,6 +257,21 @@
   return count;  
 }
 
+static bool IsInStdNamespace(const FunctionDecl *FD) {
+  const DeclContext *DC = FD->getEnclosingNamespaceContext();
+  const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
+  if (!ND)
+    return false;
+  
+  while (const DeclContext *Parent = ND->getParent()) {
+    if (!isa<NamespaceDecl>(Parent))
+      break;
+    ND = cast<NamespaceDecl>(Parent);
+  }
+
+  return ND->getName() == "std";
+}
+
 // Determine if we should inline the call.
 bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) {
   AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
@@ -287,6 +302,21 @@
       return false;
   }
 
+  if (getContext().getLangOpts().CPlusPlus) {
+    if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+      // Conditionally allow the inlining of template functions.
+      if (!getAnalysisManager().options.mayInlineTemplateFunctions())
+        if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
+          return false;
+
+      // Conditionally allow the inlining of C++ standard library functions.
+      if (!getAnalysisManager().options.mayInlineCXXStandardLibrary())
+        if (getContext().getSourceManager().isInSystemHeader(FD->getLocation()))
+          if (IsInStdNamespace(FD))
+            return false;
+    }
+  }
+
   // It is possible that the live variables analysis cannot be
   // run.  If so, bail out.
   if (!CalleeADC->getAnalysis<RelaxedLiveVariables>())

Added: cfe/trunk/test/Analysis/inlining/stl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inlining/stl.cpp?rev=163548&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/inlining/stl.cpp (added)
+++ cfe/trunk/test/Analysis/inlining/stl.cpp Mon Sep 10 16:27:35 2012
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-ipa=dynamic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-ipa=dynamic -analyzer-config c++-stdlib-inlining=true -DINLINE=1 -verify %s
+
+#include "../system-header-simulator-cxx.h"
+
+void clang_analyzer_eval(bool);
+
+void testVector(std::vector<int> &nums) {
+  if (nums.begin()) return;
+  if (nums.end()) return;
+  
+  clang_analyzer_eval(nums.size() == 0);
+#if INLINE
+  // expected-warning at -2 {{TRUE}}
+#else
+  // expected-warning at -4 {{UNKNOWN}}
+#endif
+}
+
+void testException(std::exception e) {
+  // Notice that the argument is NOT passed by reference, so we can devirtualize.
+  const char *x = e.what();
+  clang_analyzer_eval(x == 0);
+#if INLINE
+  // expected-warning at -2 {{TRUE}}
+#else
+  // expected-warning at -4 {{UNKNOWN}}
+#endif
+}

Added: cfe/trunk/test/Analysis/system-header-simulator-cxx.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/system-header-simulator-cxx.h?rev=163548&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/system-header-simulator-cxx.h (added)
+++ cfe/trunk/test/Analysis/system-header-simulator-cxx.h Mon Sep 10 16:27:35 2012
@@ -0,0 +1,57 @@
+#pragma clang system_header
+
+namespace std {
+  template <class T1, class T2>
+  struct pair {
+    T1 first;
+    T2 second;
+    
+    pair() : first(), second() {}
+    pair(const T1 &a, const T2 &b) : first(a), second(b) {}
+    
+    template<class U1, class U2>
+    pair(const pair<U1, U2> &other) : first(other.first), second(other.second) {}
+  };
+  
+  typedef __typeof__(sizeof(int)) size_t;
+  
+  template<typename T>
+  class vector {
+    T *_start;
+    T *_finish;
+    T *_end_of_storage;
+  public:
+    vector() : _start(0), _finish(0), _end_of_storage(0) {}
+    ~vector();
+    
+    size_t size() const {
+      return size_t(_finish - _start);
+    }
+    
+    void push_back();
+    T pop_back();
+
+    T &operator[](size_t n) {
+      return _start[n];
+    }
+    
+    const T &operator[](size_t n) const {
+      return _start[n];
+    }
+    
+    T *begin() { return _start; }
+    const T *begin() const { return _start; }
+
+    T *end() { return _finish; }
+    const T *end() const { return _finish; }
+  };
+  
+  class exception {
+  public:
+    exception() throw();
+    virtual ~exception() throw();
+    virtual const char *what() const throw() {
+      return 0;
+    }
+  };
+}

Modified: cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp?rev=163548&r1=163547&r2=163548&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp (original)
+++ cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp Mon Sep 10 16:27:35 2012
@@ -1,5 +1,5 @@
 // RUN: rm -f %t
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-temporary-dtors=1 %s > %t 2>&1
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-temporary-dtors=true %s > %t 2>&1
 // RUN: FileCheck --input-file=%t %s
 // XPASS: *
 

Modified: cfe/trunk/test/Analysis/templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/templates.cpp?rev=163548&r1=163547&r2=163548&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/templates.cpp (original)
+++ cfe/trunk/test/Analysis/templates.cpp Mon Sep 10 16:27:35 2012
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fblocks -analyzer-config c++-template-inlining=false -DNO_INLINE -verify %s
 
 void clang_analyzer_eval(bool);
 
@@ -39,6 +40,11 @@
 
 void testNonTypeTemplateInstantiation() {
   const char *S[] = { "a", "b" };
-  clang_analyzer_eval(array_lengthof(S) == 2); // expected-warning{{TRUE}}
+  clang_analyzer_eval(array_lengthof(S) == 2);
+#ifndef NO_INLINE
+  // expected-warning at -2 {{TRUE}}
+#else
+  // expected-warning at -4 {{UNKNOWN}}
+#endif
 }
 





More information about the cfe-commits mailing list