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); - -@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}} -} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits