r315655 - [Analyzer] Assume that CFBooleanRef const globals are non-null

George Karpenkov via cfe-commits cfe-commits at lists.llvm.org
Thu Oct 12 17:51:41 PDT 2017


Author: george.karpenkov
Date: Thu Oct 12 17:51:41 2017
New Revision: 315655

URL: http://llvm.org/viewvc/llvm-project?rev=315655&view=rev
Log:
[Analyzer] Assume that CFBooleanRef const globals are non-null

Differential Revision: https://reviews.llvm.org/D38867

Added:
    cfe/trunk/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp
      - copied, changed from r315652, cfe/trunk/lib/StaticAnalyzer/Checkers/NonnullStringConstantsChecker.cpp
    cfe/trunk/test/Analysis/nonnull-global-constants.mm
      - copied, changed from r315652, cfe/trunk/test/Analysis/nonnull-string-constants.mm
Removed:
    cfe/trunk/lib/StaticAnalyzer/Checkers/NonnullStringConstantsChecker.cpp
    cfe/trunk/test/Analysis/nonnull-string-constants.mm
Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
    cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt

Modified: cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td?rev=315655&r1=315654&r2=315655&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td Thu Oct 12 17:51:41 2017
@@ -132,7 +132,7 @@ def DynamicTypePropagation : Checker<"Dy
   HelpText<"Generate dynamic type information">,
   DescFile<"DynamicTypePropagation.cpp">;
 
-def NonnullStringConstantsChecker: Checker<"NonnilStringConstants">,
+def NonnullGlobalConstantsChecker: Checker<"NonnilStringConstants">,
   HelpText<"Assume that const string-like globals are non-null">,
   DescFile<"NonilStringConstantsChecker.cpp">;
 

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt?rev=315655&r1=315654&r2=315655&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt Thu Oct 12 17:51:41 2017
@@ -57,7 +57,7 @@ add_clang_library(clangStaticAnalyzerChe
   NSErrorChecker.cpp
   NoReturnFunctionChecker.cpp
   NonNullParamChecker.cpp
-  NonnullStringConstantsChecker.cpp
+  NonnullGlobalConstantsChecker.cpp
   NullabilityChecker.cpp
   NumberObjectConversionChecker.cpp
   ObjCAtSyncChecker.cpp

Copied: cfe/trunk/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp (from r315652, cfe/trunk/lib/StaticAnalyzer/Checkers/NonnullStringConstantsChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp?p2=cfe/trunk/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp&p1=cfe/trunk/lib/StaticAnalyzer/Checkers/NonnullStringConstantsChecker.cpp&r1=315652&r2=315655&rev=315655&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/NonnullStringConstantsChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp Thu Oct 12 17:51:41 2017
@@ -1,4 +1,4 @@
-//==- NonnullStringConstantsChecker.cpp ---------------------------*- C++ -*--//
+//==- NonnullGlobalConstantsChecker.cpp ---------------------------*- C++ -*--//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -7,15 +7,17 @@
 //
 //===----------------------------------------------------------------------===//
 //
-//  This checker adds an assumption that constant string-like globals are
+//  This checker adds an assumption that constant globals of certain types* are
 //  non-null, as otherwise they generally do not convey any useful information.
-//  The assumption is useful, as many framework use such global const strings,
+//  The assumption is useful, as many framework use e. g. global const strings,
 //  and the analyzer might not be able to infer the global value if the
 //  definition is in a separate translation unit.
-//  The following types (and their typedef aliases) are considered string-like:
+//  The following types (and their typedef aliases) are considered to be
+//  non-null:
 //   - `char* const`
 //   - `const CFStringRef` from CoreFoundation
 //   - `NSString* const` from Foundation
+//   - `CFBooleanRef` from Foundation
 //
 //===----------------------------------------------------------------------===//
 
@@ -31,12 +33,13 @@ using namespace ento;
 
 namespace {
 
-class NonnullStringConstantsChecker : public Checker<check::Location> {
+class NonnullGlobalConstantsChecker : public Checker<check::Location> {
   mutable IdentifierInfo *NSStringII = nullptr;
   mutable IdentifierInfo *CFStringRefII = nullptr;
+  mutable IdentifierInfo *CFBooleanRefII = nullptr;
 
 public:
-  NonnullStringConstantsChecker() {}
+  NonnullGlobalConstantsChecker() {}
 
   void checkLocation(SVal l, bool isLoad, const Stmt *S,
                      CheckerContext &C) const;
@@ -46,22 +49,23 @@ private:
 
   bool isGlobalConstString(SVal V) const;
 
-  bool isStringlike(QualType Ty) const;
+  bool isNonnullType(QualType Ty) const;
 };
 
 } // namespace
 
 /// Lazily initialize cache for required identifier informations.
-void NonnullStringConstantsChecker::initIdentifierInfo(ASTContext &Ctx) const {
+void NonnullGlobalConstantsChecker::initIdentifierInfo(ASTContext &Ctx) const {
   if (NSStringII)
     return;
 
   NSStringII = &Ctx.Idents.get("NSString");
   CFStringRefII = &Ctx.Idents.get("CFStringRef");
+  CFBooleanRefII = &Ctx.Idents.get("CFBooleanRef");
 }
 
 /// Add an assumption that const string-like globals are non-null.
-void NonnullStringConstantsChecker::checkLocation(SVal location, bool isLoad,
+void NonnullGlobalConstantsChecker::checkLocation(SVal location, bool isLoad,
                                                  const Stmt *S,
                                                  CheckerContext &C) const {
   initIdentifierInfo(C.getASTContext());
@@ -85,7 +89,7 @@ void NonnullStringConstantsChecker::chec
 
 /// \param V loaded lvalue.
 /// \return whether {@code val} is a string-like const global.
-bool NonnullStringConstantsChecker::isGlobalConstString(SVal V) const {
+bool NonnullGlobalConstantsChecker::isGlobalConstString(SVal V) const {
   Optional<loc::MemRegionVal> RegionVal = V.getAs<loc::MemRegionVal>();
   if (!RegionVal)
     return false;
@@ -99,7 +103,7 @@ bool NonnullStringConstantsChecker::isGl
 
   QualType Ty = Decl->getType();
   bool HasConst = Ty.isConstQualified();
-  if (isStringlike(Ty) && HasConst)
+  if (isNonnullType(Ty) && HasConst)
     return true;
 
   // Look through the typedefs.
@@ -109,14 +113,14 @@ bool NonnullStringConstantsChecker::isGl
     // It is sufficient for any intermediate typedef
     // to be classified const.
     HasConst = HasConst || Ty.isConstQualified();
-    if (isStringlike(Ty) && HasConst)
+    if (isNonnullType(Ty) && HasConst)
       return true;
   }
   return false;
 }
 
-/// \return whether {@code type} is a string-like type.
-bool NonnullStringConstantsChecker::isStringlike(QualType Ty) const {
+/// \return whether {@code type} is extremely unlikely to be null
+bool NonnullGlobalConstantsChecker::isNonnullType(QualType Ty) const {
 
   if (Ty->isPointerType() && Ty->getPointeeType()->isCharType())
     return true;
@@ -125,11 +129,12 @@ bool NonnullStringConstantsChecker::isSt
     return T->getInterfaceDecl() &&
       T->getInterfaceDecl()->getIdentifier() == NSStringII;
   } else if (auto *T = dyn_cast<TypedefType>(Ty)) {
-    return T->getDecl()->getIdentifier() == CFStringRefII;
+    IdentifierInfo* II = T->getDecl()->getIdentifier();
+    return II == CFStringRefII || II == CFBooleanRefII;
   }
   return false;
 }
 
-void ento::registerNonnullStringConstantsChecker(CheckerManager &Mgr) {
-  Mgr.registerChecker<NonnullStringConstantsChecker>();
+void ento::registerNonnullGlobalConstantsChecker(CheckerManager &Mgr) {
+  Mgr.registerChecker<NonnullGlobalConstantsChecker>();
 }

Removed: cfe/trunk/lib/StaticAnalyzer/Checkers/NonnullStringConstantsChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/NonnullStringConstantsChecker.cpp?rev=315654&view=auto
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/NonnullStringConstantsChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/NonnullStringConstantsChecker.cpp (removed)
@@ -1,135 +0,0 @@
-//==- NonnullStringConstantsChecker.cpp ---------------------------*- C++ -*--//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-//  This checker adds an assumption that constant string-like globals are
-//  non-null, as otherwise they generally do not convey any useful information.
-//  The assumption is useful, as many framework use such global const strings,
-//  and the analyzer might not be able to infer the global value if the
-//  definition is in a separate translation unit.
-//  The following types (and their typedef aliases) are considered string-like:
-//   - `char* const`
-//   - `const CFStringRef` from CoreFoundation
-//   - `NSString* const` from Foundation
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-
-class NonnullStringConstantsChecker : public Checker<check::Location> {
-  mutable IdentifierInfo *NSStringII = nullptr;
-  mutable IdentifierInfo *CFStringRefII = nullptr;
-
-public:
-  NonnullStringConstantsChecker() {}
-
-  void checkLocation(SVal l, bool isLoad, const Stmt *S,
-                     CheckerContext &C) const;
-
-private:
-  void initIdentifierInfo(ASTContext &Ctx) const;
-
-  bool isGlobalConstString(SVal V) const;
-
-  bool isStringlike(QualType Ty) const;
-};
-
-} // namespace
-
-/// Lazily initialize cache for required identifier informations.
-void NonnullStringConstantsChecker::initIdentifierInfo(ASTContext &Ctx) const {
-  if (NSStringII)
-    return;
-
-  NSStringII = &Ctx.Idents.get("NSString");
-  CFStringRefII = &Ctx.Idents.get("CFStringRef");
-}
-
-/// Add an assumption that const string-like globals are non-null.
-void NonnullStringConstantsChecker::checkLocation(SVal location, bool isLoad,
-                                                 const Stmt *S,
-                                                 CheckerContext &C) const {
-  initIdentifierInfo(C.getASTContext());
-  if (!isLoad || !location.isValid())
-    return;
-
-  ProgramStateRef State = C.getState();
-  SVal V = State->getSVal(location.castAs<Loc>());
-
-  if (isGlobalConstString(location)) {
-    Optional<DefinedOrUnknownSVal> Constr = V.getAs<DefinedOrUnknownSVal>();
-
-    if (Constr) {
-
-      // Assume that the variable is non-null.
-      ProgramStateRef OutputState = State->assume(*Constr, true);
-      C.addTransition(OutputState);
-    }
-  }
-}
-
-/// \param V loaded lvalue.
-/// \return whether {@code val} is a string-like const global.
-bool NonnullStringConstantsChecker::isGlobalConstString(SVal V) const {
-  Optional<loc::MemRegionVal> RegionVal = V.getAs<loc::MemRegionVal>();
-  if (!RegionVal)
-    return false;
-  auto *Region = dyn_cast<VarRegion>(RegionVal->getAsRegion());
-  if (!Region)
-    return false;
-  const VarDecl *Decl = Region->getDecl();
-
-  if (!Decl->hasGlobalStorage())
-    return false;
-
-  QualType Ty = Decl->getType();
-  bool HasConst = Ty.isConstQualified();
-  if (isStringlike(Ty) && HasConst)
-    return true;
-
-  // Look through the typedefs.
-  while (auto *T = dyn_cast<TypedefType>(Ty)) {
-    Ty = T->getDecl()->getUnderlyingType();
-
-    // It is sufficient for any intermediate typedef
-    // to be classified const.
-    HasConst = HasConst || Ty.isConstQualified();
-    if (isStringlike(Ty) && HasConst)
-      return true;
-  }
-  return false;
-}
-
-/// \return whether {@code type} is a string-like type.
-bool NonnullStringConstantsChecker::isStringlike(QualType Ty) const {
-
-  if (Ty->isPointerType() && Ty->getPointeeType()->isCharType())
-    return true;
-
-  if (auto *T = dyn_cast<ObjCObjectPointerType>(Ty)) {
-    return T->getInterfaceDecl() &&
-      T->getInterfaceDecl()->getIdentifier() == NSStringII;
-  } else if (auto *T = dyn_cast<TypedefType>(Ty)) {
-    return T->getDecl()->getIdentifier() == CFStringRefII;
-  }
-  return false;
-}
-
-void ento::registerNonnullStringConstantsChecker(CheckerManager &Mgr) {
-  Mgr.registerChecker<NonnullStringConstantsChecker>();
-}

Copied: cfe/trunk/test/Analysis/nonnull-global-constants.mm (from r315652, cfe/trunk/test/Analysis/nonnull-string-constants.mm)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/nonnull-global-constants.mm?p2=cfe/trunk/test/Analysis/nonnull-global-constants.mm&p1=cfe/trunk/test/Analysis/nonnull-string-constants.mm&r1=315652&r2=315655&rev=315655&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/nonnull-string-constants.mm (original)
+++ cfe/trunk/test/Analysis/nonnull-global-constants.mm Thu Oct 12 17:51:41 2017
@@ -1,12 +1,13 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
 
 // Nullability of const string-like globals, testing
-// NonnullStringConstantsChecker.
+// NonnullGlobalConstantsChecker.
 
 void clang_analyzer_eval(bool);
 
 @class NSString;
 typedef const struct __CFString *CFStringRef;
+typedef const struct __CFBoolean * CFBooleanRef;
 
 // Global NSString* is non-null.
 extern NSString *const StringConstGlobal;
@@ -88,3 +89,15 @@ extern nstr2 nglobalStr2;
 void testNestedTypedefsForNSString() {
   clang_analyzer_eval(nglobalStr2); // expected-warning{{TRUE}}
 }
+
+// And for CFBooleanRefs.
+extern const CFBooleanRef kBool;
+void testNonnullBool() {
+  clang_analyzer_eval(kBool); // expected-warning{{TRUE}}
+}
+
+// And again, only for const one.
+extern CFBooleanRef kBoolMutable;
+void testNonnullNonconstBool() {
+  clang_analyzer_eval(kBoolMutable); // expected-warning{{UNKNOWN}}
+}

Removed: cfe/trunk/test/Analysis/nonnull-string-constants.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/nonnull-string-constants.mm?rev=315654&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/nonnull-string-constants.mm (original)
+++ cfe/trunk/test/Analysis/nonnull-string-constants.mm (removed)
@@ -1,90 +0,0 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
-
-// Nullability of const string-like globals, testing
-// NonnullStringConstantsChecker.
-
-void clang_analyzer_eval(bool);
-
- at class NSString;
-typedef const struct __CFString *CFStringRef;
-
-// Global NSString* is non-null.
-extern NSString *const StringConstGlobal;
-void stringConstGlobal() {
-  clang_analyzer_eval(StringConstGlobal); // expected-warning{{TRUE}}
-}
-
-// The logic does not apply to local variables though.
-extern NSString *stringGetter();
-void stringConstLocal() {
-  NSString *const local = stringGetter();
-  clang_analyzer_eval(local); // expected-warning{{UNKNOWN}}
-}
-
-// Global const CFStringRef's are also assumed to be non-null.
-extern const CFStringRef CFStringConstGlobal;
-void cfStringCheckGlobal() {
-  clang_analyzer_eval(CFStringConstGlobal); // expected-warning{{TRUE}}
-}
-
-// But only "const" ones.
-extern CFStringRef CFStringNonConstGlobal;
-void cfStringCheckMutableGlobal() {
-  clang_analyzer_eval(CFStringNonConstGlobal); // expected-warning{{UNKNOWN}}
-}
-
-// char* const is also assumed to be non-null.
-extern const char *const ConstCharStarConst;
-void constCharStarCheckGlobal() {
-  clang_analyzer_eval(ConstCharStarConst); // expected-warning{{TRUE}}
-}
-
-// Pointer value can be mutable.
-extern char *const CharStarConst;
-void charStarCheckGlobal() {
-  clang_analyzer_eval(CharStarConst); // expected-warning{{TRUE}}
-}
-
-// But the pointer itself should be immutable.
-extern char *CharStar;
-void charStartCheckMutableGlobal() {
-  clang_analyzer_eval(CharStar); // expected-warning{{UNKNOWN}}
-}
-
-// Type definitions should also work across typedefs, for pointers:
-typedef char *const str;
-extern str globalStr;
-void charStarCheckTypedef() {
-  clang_analyzer_eval(globalStr); // expected-warning{{TRUE}}
-}
-
-// And for types.
-typedef NSString *const NStr;
-extern NStr globalNSString;
-void NSStringCheckTypedef() {
-  clang_analyzer_eval(globalNSString); // expected-warning{{TRUE}}
-}
-
-// Note that constness could be either inside
-// the var declaration, or in a typedef.
-typedef NSString *NStr2;
-extern const NStr2 globalNSString2;
-void NSStringCheckConstTypedef() {
-  clang_analyzer_eval(globalNSString2); // expected-warning{{TRUE}}
-}
-
-// Nested typedefs should work as well.
-typedef const CFStringRef str1;
-typedef str1 str2;
-extern str2 globalStr2;
-void testNestedTypedefs() {
-  clang_analyzer_eval(globalStr2); // expected-warning{{TRUE}}
-}
-
-// And for NSString *.
-typedef NSString *const nstr1;
-typedef nstr1 nstr2;
-extern nstr2 nglobalStr2;
-void testNestedTypedefsForNSString() {
-  clang_analyzer_eval(nglobalStr2); // expected-warning{{TRUE}}
-}




More information about the cfe-commits mailing list