summaryrefslogtreecommitdiff
path: root/include/clang/StaticAnalyzer
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/StaticAnalyzer')
-rw-r--r--include/clang/StaticAnalyzer/Checkers/CMakeLists.txt4
-rw-r--r--include/clang/StaticAnalyzer/Checkers/Checkers.td659
-rw-r--r--include/clang/StaticAnalyzer/Checkers/SValExplainer.h233
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h1
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h14
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h20
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h41
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h3
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h1
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h14
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h17
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h78
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h6
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def89
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h3
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h151
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def74
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h23
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h14
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h123
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h96
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def55
24 files changed, 1558 insertions, 169 deletions
diff --git a/include/clang/StaticAnalyzer/Checkers/CMakeLists.txt b/include/clang/StaticAnalyzer/Checkers/CMakeLists.txt
new file mode 100644
index 0000000000000..37dd9e8482968
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -0,0 +1,4 @@
+clang_tablegen(Checkers.inc -gen-clang-sa-checkers
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../../
+ SOURCE Checkers.td
+ TARGET ClangSACheckers)
diff --git a/include/clang/StaticAnalyzer/Checkers/Checkers.td b/include/clang/StaticAnalyzer/Checkers/Checkers.td
new file mode 100644
index 0000000000000..785e064e72a99
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -0,0 +1,659 @@
+//===--- Checkers.td - Static Analyzer Checkers -===-----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+include "clang/StaticAnalyzer/Checkers/CheckerBase.td"
+
+//===----------------------------------------------------------------------===//
+// Packages.
+//===----------------------------------------------------------------------===//
+
+// The Alpha package is for checkers that have too many false positives to be
+// turned on by default. The hierarchy under Alpha should be organized in the
+// hierarchy checkers would have had if they were truly at the top level.
+// (For example, a Cocoa-specific checker that is alpha should be in
+// alpha.osx.cocoa).
+def Alpha : Package<"alpha">;
+
+def Core : Package<"core">;
+def CoreBuiltin : Package<"builtin">, InPackage<Core>;
+def CoreUninitialized : Package<"uninitialized">, InPackage<Core>;
+def CoreAlpha : Package<"core">, InPackage<Alpha>, Hidden;
+
+// The OptIn package is for checkers that are not alpha and that would normally
+// be on by default but where the driver does not have enough information to
+// determine when they are applicable. For example, localizability checkers fit
+// this criterion because the driver cannot determine whether a project is
+// localized or not -- this is best determined at the IDE or build-system level.
+//
+// The checker hierarchy under OptIn should mirror that in Alpha: checkers
+// should be organized as if they were at the top level.
+//
+// Note: OptIn is *not* intended for checkers that are too noisy to be on by
+// default. Such checkers belong in the alpha package.
+def OptIn : Package<"optin">;
+
+def Nullability : Package<"nullability">;
+
+def Cplusplus : Package<"cplusplus">;
+def CplusplusAlpha : Package<"cplusplus">, InPackage<Alpha>, Hidden;
+
+def DeadCode : Package<"deadcode">;
+def DeadCodeAlpha : Package<"deadcode">, InPackage<Alpha>, Hidden;
+
+def Performance : Package<"performance">, InPackage<OptIn>;
+
+def Security : Package <"security">;
+def InsecureAPI : Package<"insecureAPI">, InPackage<Security>;
+def SecurityAlpha : Package<"security">, InPackage<Alpha>, Hidden;
+def Taint : Package<"taint">, InPackage<SecurityAlpha>, Hidden;
+
+def Unix : Package<"unix">;
+def UnixAlpha : Package<"unix">, InPackage<Alpha>, Hidden;
+def CString : Package<"cstring">, InPackage<Unix>, Hidden;
+def CStringAlpha : Package<"cstring">, InPackage<UnixAlpha>, Hidden;
+
+def OSX : Package<"osx">;
+def OSXAlpha : Package<"osx">, InPackage<Alpha>, Hidden;
+def OSXOptIn : Package<"osx">, InPackage<OptIn>;
+
+def Cocoa : Package<"cocoa">, InPackage<OSX>;
+def CocoaAlpha : Package<"cocoa">, InPackage<OSXAlpha>, Hidden;
+def CocoaOptIn : Package<"cocoa">, InPackage<OSXOptIn>;
+
+def CoreFoundation : Package<"coreFoundation">, InPackage<OSX>;
+def Containers : Package<"containers">, InPackage<CoreFoundation>;
+
+def LocalizabilityAlpha : Package<"localizability">, InPackage<CocoaAlpha>;
+def LocalizabilityOptIn : Package<"localizability">, InPackage<CocoaOptIn>;
+
+def MPI : Package<"mpi">, InPackage<OptIn>;
+
+def LLVM : Package<"llvm">;
+def Debug : Package<"debug">;
+
+//===----------------------------------------------------------------------===//
+// Core Checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = Core in {
+
+def DereferenceChecker : Checker<"NullDereference">,
+ 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">;
+
+def VLASizeChecker : Checker<"VLASize">,
+ HelpText<"Check for declarations of VLA of undefined or zero size">,
+ DescFile<"VLASizeChecker.cpp">;
+
+def DivZeroChecker : Checker<"DivideZero">,
+ HelpText<"Check for division by zero">,
+ DescFile<"DivZeroChecker.cpp">;
+
+def UndefResultChecker : Checker<"UndefinedBinaryOperatorResult">,
+ HelpText<"Check for undefined results of binary operators">,
+ DescFile<"UndefResultChecker.cpp">;
+
+def StackAddrEscapeChecker : Checker<"StackAddressEscape">,
+ HelpText<"Check that addresses to stack memory do not escape the function">,
+ DescFile<"StackAddrEscapeChecker.cpp">;
+
+def DynamicTypePropagation : Checker<"DynamicTypePropagation">,
+ HelpText<"Generate dynamic type information">,
+ DescFile<"DynamicTypePropagation.cpp">;
+
+} // end "core"
+
+let ParentPackage = CoreAlpha in {
+
+def BoolAssignmentChecker : Checker<"BoolAssignment">,
+ HelpText<"Warn about assigning non-{0,1} values to Boolean variables">,
+ DescFile<"BoolAssignmentChecker.cpp">;
+
+def CastSizeChecker : Checker<"CastSize">,
+ HelpText<"Check when casting a malloc'ed type T, whether the size is a multiple of the size of T">,
+ DescFile<"CastSizeChecker.cpp">;
+
+def CastToStructChecker : Checker<"CastToStruct">,
+ HelpText<"Check for cast from non-struct pointer to struct pointer">,
+ DescFile<"CastToStructChecker.cpp">;
+
+def IdenticalExprChecker : Checker<"IdenticalExpr">,
+ HelpText<"Warn about unintended use of identical expressions in operators">,
+ DescFile<"IdenticalExprChecker.cpp">;
+
+def FixedAddressChecker : Checker<"FixedAddr">,
+ HelpText<"Check for assignment of a fixed address to a pointer">,
+ DescFile<"FixedAddressChecker.cpp">;
+
+def PointerArithChecker : Checker<"PointerArithm">,
+ HelpText<"Check for pointer arithmetic on locations other than array elements">,
+ DescFile<"PointerArithChecker">;
+
+def PointerSubChecker : Checker<"PointerSub">,
+ HelpText<"Check for pointer subtractions on two pointers pointing to different memory chunks">,
+ DescFile<"PointerSubChecker">;
+
+def SizeofPointerChecker : Checker<"SizeofPtr">,
+ HelpText<"Warn about unintended use of sizeof() on pointer expressions">,
+ DescFile<"CheckSizeofPointer.cpp">;
+
+def CallAndMessageUnInitRefArg : Checker<"CallAndMessageUnInitRefArg">,
+ 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">;
+
+def TestAfterDivZeroChecker : Checker<"TestAfterDivZero">,
+ HelpText<"Check for division by variable that is later compared against 0. Either the comparison is useless or there is division by zero.">,
+ DescFile<"TestAfterDivZeroChecker.cpp">;
+
+def DynamicTypeChecker : Checker<"DynamicTypeChecker">,
+ HelpText<"Check for cases where the dynamic and the static type of an object are unrelated.">,
+ DescFile<"DynamicTypeChecker.cpp">;
+
+} // end "alpha.core"
+
+let ParentPackage = Nullability in {
+
+def NullPassedToNonnullChecker : Checker<"NullPassedToNonnull">,
+ HelpText<"Warns when a null pointer is passed to a pointer which has a _Nonnull type.">,
+ DescFile<"NullabilityChecker.cpp">;
+
+def NullReturnedFromNonnullChecker : Checker<"NullReturnedFromNonnull">,
+ HelpText<"Warns when a null pointer is returned from a function that has _Nonnull return type.">,
+ DescFile<"NullabilityChecker.cpp">;
+
+def NullableDereferencedChecker : Checker<"NullableDereferenced">,
+ HelpText<"Warns when a nullable pointer is dereferenced.">,
+ DescFile<"NullabilityChecker.cpp">;
+
+def NullablePassedToNonnullChecker : Checker<"NullablePassedToNonnull">,
+ HelpText<"Warns when a nullable pointer is passed to a pointer which has a _Nonnull type.">,
+ DescFile<"NullabilityChecker.cpp">;
+
+def NullableReturnedFromNonnullChecker : Checker<"NullablePassedToNonnull">,
+ HelpText<"Warns when a nullable pointer is returned from a function that has _Nonnull return type.">,
+ DescFile<"NullabilityChecker.cpp">;
+
+} // end "nullability"
+
+//===----------------------------------------------------------------------===//
+// Evaluate "builtin" functions.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = CoreBuiltin in {
+
+def NoReturnFunctionChecker : Checker<"NoReturnFunctions">,
+ HelpText<"Evaluate \"panic\" functions that are known to not return to the caller">,
+ DescFile<"NoReturnFunctionChecker.cpp">;
+
+def BuiltinFunctionChecker : Checker<"BuiltinFunctions">,
+ HelpText<"Evaluate compiler builtin functions (e.g., alloca())">,
+ DescFile<"BuiltinFunctionChecker.cpp">;
+
+} // end "core.builtin"
+
+//===----------------------------------------------------------------------===//
+// Uninitialized values checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = CoreUninitialized in {
+
+def UndefinedArraySubscriptChecker : Checker<"ArraySubscript">,
+ HelpText<"Check for uninitialized values used as array subscripts">,
+ DescFile<"UndefinedArraySubscriptChecker.cpp">;
+
+def UndefinedAssignmentChecker : Checker<"Assign">,
+ HelpText<"Check for assigning uninitialized values">,
+ DescFile<"UndefinedAssignmentChecker.cpp">;
+
+def UndefBranchChecker : Checker<"Branch">,
+ HelpText<"Check for uninitialized values used as branch conditions">,
+ DescFile<"UndefBranchChecker.cpp">;
+
+def UndefCapturedBlockVarChecker : Checker<"CapturedBlockVariable">,
+ HelpText<"Check for blocks that capture uninitialized values">,
+ DescFile<"UndefCapturedBlockVarChecker.cpp">;
+
+def ReturnUndefChecker : Checker<"UndefReturn">,
+ HelpText<"Check for uninitialized values being returned to the caller">,
+ DescFile<"ReturnUndefChecker.cpp">;
+
+} // end "core.uninitialized"
+
+//===----------------------------------------------------------------------===//
+// C++ checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = Cplusplus in {
+
+def NewDeleteChecker : Checker<"NewDelete">,
+ HelpText<"Check for double-free and use-after-free problems. Traces memory managed by new/delete.">,
+ DescFile<"MallocChecker.cpp">;
+
+def NewDeleteLeaksChecker : Checker<"NewDeleteLeaks">,
+ HelpText<"Check for memory leaks. Traces memory managed by new/delete.">,
+ DescFile<"MallocChecker.cpp">;
+
+} // end: "cplusplus"
+
+let ParentPackage = CplusplusAlpha in {
+
+def VirtualCallChecker : Checker<"VirtualCall">,
+ HelpText<"Check virtual function calls during construction or destruction">,
+ DescFile<"VirtualCallChecker.cpp">;
+
+} // end: "alpha.cplusplus"
+
+//===----------------------------------------------------------------------===//
+// Deadcode checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = DeadCode in {
+
+def DeadStoresChecker : Checker<"DeadStores">,
+ HelpText<"Check for values stored to variables that are never read afterwards">,
+ DescFile<"DeadStoresChecker.cpp">;
+} // end DeadCode
+
+let ParentPackage = DeadCodeAlpha in {
+
+def UnreachableCodeChecker : Checker<"UnreachableCode">,
+ HelpText<"Check unreachable code">,
+ DescFile<"UnreachableCodeChecker.cpp">;
+
+} // end "alpha.deadcode"
+
+//===----------------------------------------------------------------------===//
+// Performance checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = Performance in {
+
+def PaddingChecker : Checker<"Padding">,
+ HelpText<"Check for excessively padded structs.">,
+ DescFile<"PaddingChecker.cpp">;
+
+} // end: "padding"
+
+//===----------------------------------------------------------------------===//
+// Security checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = InsecureAPI in {
+ def gets : Checker<"gets">,
+ HelpText<"Warn on uses of the 'gets' function">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def getpw : Checker<"getpw">,
+ HelpText<"Warn on uses of the 'getpw' function">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def mktemp : Checker<"mktemp">,
+ HelpText<"Warn on uses of the 'mktemp' function">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def mkstemp : Checker<"mkstemp">,
+ HelpText<"Warn when 'mkstemp' is passed fewer than 6 X's in the format string">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def rand : Checker<"rand">,
+ HelpText<"Warn on uses of the 'rand', 'random', and related functions">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def strcpy : Checker<"strcpy">,
+ HelpText<"Warn on uses of the 'strcpy' and 'strcat' functions">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def vfork : Checker<"vfork">,
+ HelpText<"Warn on uses of the 'vfork' function">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def UncheckedReturn : Checker<"UncheckedReturn">,
+ HelpText<"Warn on uses of functions whose return values must be always checked">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+}
+let ParentPackage = Security in {
+ def FloatLoopCounter : Checker<"FloatLoopCounter">,
+ HelpText<"Warn on using a floating point value as a loop counter (CERT: FLP30-C, FLP30-CPP)">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+}
+
+let ParentPackage = SecurityAlpha in {
+
+def ArrayBoundChecker : Checker<"ArrayBound">,
+ HelpText<"Warn about buffer overflows (older checker)">,
+ DescFile<"ArrayBoundChecker.cpp">;
+
+def ArrayBoundCheckerV2 : Checker<"ArrayBoundV2">,
+ HelpText<"Warn about buffer overflows (newer checker)">,
+ DescFile<"ArrayBoundCheckerV2.cpp">;
+
+def ReturnPointerRangeChecker : Checker<"ReturnPtrRange">,
+ HelpText<"Check for an out-of-bound pointer being returned to callers">,
+ DescFile<"ReturnPointerRangeChecker.cpp">;
+
+def MallocOverflowSecurityChecker : Checker<"MallocOverflow">,
+ HelpText<"Check for overflows in the arguments to malloc()">,
+ DescFile<"MallocOverflowSecurityChecker.cpp">;
+
+} // end "alpha.security"
+
+//===----------------------------------------------------------------------===//
+// Taint checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = Taint in {
+
+def GenericTaintChecker : Checker<"TaintPropagation">,
+ HelpText<"Generate taint information used by other checkers">,
+ DescFile<"GenericTaintChecker.cpp">;
+
+} // end "alpha.security.taint"
+
+//===----------------------------------------------------------------------===//
+// Unix API checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = Unix in {
+
+def UnixAPIChecker : Checker<"API">,
+ HelpText<"Check calls to various UNIX/Posix functions">,
+ DescFile<"UnixAPIChecker.cpp">;
+
+def MallocChecker: Checker<"Malloc">,
+ HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free().">,
+ DescFile<"MallocChecker.cpp">;
+
+def MallocSizeofChecker : Checker<"MallocSizeof">,
+ HelpText<"Check for dubious malloc arguments involving sizeof">,
+ DescFile<"MallocSizeofChecker.cpp">;
+
+def MismatchedDeallocatorChecker : Checker<"MismatchedDeallocator">,
+ HelpText<"Check for mismatched deallocators.">,
+ DescFile<"MallocChecker.cpp">;
+
+def VforkChecker : Checker<"Vfork">,
+ HelpText<"Check for proper usage of vfork">,
+ DescFile<"VforkChecker.cpp">;
+
+} // end "unix"
+
+let ParentPackage = UnixAlpha in {
+
+def ChrootChecker : Checker<"Chroot">,
+ HelpText<"Check improper use of chroot">,
+ DescFile<"ChrootChecker.cpp">;
+
+def PthreadLockChecker : Checker<"PthreadLock">,
+ HelpText<"Simple lock -> unlock checker">,
+ DescFile<"PthreadLockChecker.cpp">;
+
+def StreamChecker : Checker<"Stream">,
+ HelpText<"Check stream handling functions">,
+ DescFile<"StreamChecker.cpp">;
+
+def SimpleStreamChecker : Checker<"SimpleStream">,
+ HelpText<"Check for misuses of stream APIs">,
+ DescFile<"SimpleStreamChecker.cpp">;
+
+} // end "alpha.unix"
+
+let ParentPackage = CString in {
+
+def CStringNullArg : Checker<"NullArg">,
+ HelpText<"Check for null pointers being passed as arguments to C string functions">,
+ DescFile<"CStringChecker.cpp">;
+
+def CStringSyntaxChecker : Checker<"BadSizeArg">,
+ HelpText<"Check the size argument passed into C string functions for common erroneous patterns">,
+ DescFile<"CStringSyntaxChecker.cpp">;
+}
+
+let ParentPackage = CStringAlpha in {
+
+def CStringOutOfBounds : Checker<"OutOfBounds">,
+ HelpText<"Check for out-of-bounds access in string functions">,
+ DescFile<"CStringChecker.cpp">;
+
+def CStringBufferOverlap : Checker<"BufferOverlap">,
+ HelpText<"Checks for overlap in two buffer arguments">,
+ DescFile<"CStringChecker.cpp">;
+
+def CStringNotNullTerm : Checker<"NotNullTerminated">,
+ HelpText<"Check for arguments which are not null-terminating strings">,
+ DescFile<"CStringChecker.cpp">;
+}
+
+//===----------------------------------------------------------------------===//
+// Mac OS X, Cocoa, and Core Foundation checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = OSX in {
+
+def MacOSXAPIChecker : Checker<"API">,
+ InPackage<OSX>,
+ HelpText<"Check for proper uses of various Apple APIs">,
+ DescFile<"MacOSXAPIChecker.cpp">;
+
+def MacOSKeychainAPIChecker : Checker<"SecKeychainAPI">,
+ InPackage<OSX>,
+ HelpText<"Check for proper uses of Secure Keychain APIs">,
+ DescFile<"MacOSKeychainAPIChecker.cpp">;
+
+} // end "osx"
+
+let ParentPackage = Cocoa in {
+
+def ObjCAtSyncChecker : Checker<"AtSync">,
+ HelpText<"Check for nil pointers used as mutexes for @synchronized">,
+ DescFile<"ObjCAtSyncChecker.cpp">;
+
+def NilArgChecker : Checker<"NilArg">,
+ HelpText<"Check for prohibited nil arguments to ObjC method calls">,
+ DescFile<"BasicObjCFoundationChecks.cpp">;
+
+def ClassReleaseChecker : Checker<"ClassRelease">,
+ HelpText<"Check for sending 'retain', 'release', or 'autorelease' directly to a Class">,
+ DescFile<"BasicObjCFoundationChecks.cpp">;
+
+def VariadicMethodTypeChecker : Checker<"VariadicMethodTypes">,
+ HelpText<"Check for passing non-Objective-C types to variadic collection "
+ "initialization methods that expect only Objective-C types">,
+ DescFile<"BasicObjCFoundationChecks.cpp">;
+
+def NSAutoreleasePoolChecker : Checker<"NSAutoreleasePool">,
+ HelpText<"Warn for suboptimal uses of NSAutoreleasePool in Objective-C GC mode">,
+ DescFile<"NSAutoreleasePoolChecker.cpp">;
+
+def ObjCMethSigsChecker : Checker<"IncompatibleMethodTypes">,
+ HelpText<"Warn about Objective-C method signatures with type incompatibilities">,
+ DescFile<"CheckObjCInstMethSignature.cpp">;
+
+def ObjCUnusedIvarsChecker : Checker<"UnusedIvars">,
+ HelpText<"Warn about private ivars that are never used">,
+ DescFile<"ObjCUnusedIVarsChecker.cpp">;
+
+def ObjCSelfInitChecker : Checker<"SelfInit">,
+ HelpText<"Check that 'self' is properly initialized inside an initializer method">,
+ DescFile<"ObjCSelfInitChecker.cpp">;
+
+def ObjCLoopChecker : Checker<"Loops">,
+ HelpText<"Improved modeling of loops using Cocoa collection types">,
+ DescFile<"BasicObjCFoundationChecks.cpp">;
+
+def ObjCNonNilReturnValueChecker : Checker<"NonNilReturnValue">,
+ HelpText<"Model the APIs that are guaranteed to return a non-nil value">,
+ DescFile<"BasicObjCFoundationChecks.cpp">;
+
+def ObjCSuperCallChecker : Checker<"MissingSuperCall">,
+ HelpText<"Warn about Objective-C methods that lack a necessary call to super">,
+ DescFile<"ObjCMissingSuperCallChecker.cpp">;
+
+def NSErrorChecker : Checker<"NSError">,
+ HelpText<"Check usage of NSError** parameters">,
+ DescFile<"NSErrorChecker.cpp">;
+
+def RetainCountChecker : Checker<"RetainCount">,
+ HelpText<"Check for leaks and improper reference count management">,
+ DescFile<"RetainCountChecker.cpp">;
+
+def ObjCGenericsChecker : Checker<"ObjCGenerics">,
+ HelpText<"Check for type errors when using Objective-C generics">,
+ DescFile<"DynamicTypePropagation.cpp">;
+
+def ObjCDeallocChecker : Checker<"Dealloc">,
+ HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">,
+ DescFile<"CheckObjCDealloc.cpp">;
+
+def ObjCSuperDeallocChecker : Checker<"SuperDealloc">,
+ HelpText<"Warn about improper use of '[super dealloc]' in Objective-C">,
+ DescFile<"ObjCSuperDeallocChecker.cpp">;
+
+} // end "osx.cocoa"
+
+let ParentPackage = CocoaAlpha in {
+
+def InstanceVariableInvalidation : Checker<"InstanceVariableInvalidation">,
+ HelpText<"Check that the invalidatable instance variables are invalidated in the methods annotated with objc_instance_variable_invalidator">,
+ DescFile<"IvarInvalidationChecker.cpp">;
+
+def MissingInvalidationMethod : Checker<"MissingInvalidationMethod">,
+ HelpText<"Check that the invalidation methods are present in classes that contain invalidatable instance variables">,
+ DescFile<"IvarInvalidationChecker.cpp">;
+
+def DirectIvarAssignment : Checker<"DirectIvarAssignment">,
+ HelpText<"Check for direct assignments to instance variables">,
+ DescFile<"DirectIvarAssignment.cpp">;
+
+def DirectIvarAssignmentForAnnotatedFunctions : Checker<"DirectIvarAssignmentForAnnotatedFunctions">,
+ HelpText<"Check for direct assignments to instance variables in the methods annotated with objc_no_direct_instance_variable_assignment">,
+ DescFile<"DirectIvarAssignment.cpp">;
+
+} // end "alpha.osx.cocoa"
+
+let ParentPackage = CoreFoundation in {
+
+def CFNumberCreateChecker : Checker<"CFNumber">,
+ HelpText<"Check for proper uses of CFNumberCreate">,
+ DescFile<"BasicObjCFoundationChecks.cpp">;
+
+def CFRetainReleaseChecker : Checker<"CFRetainRelease">,
+ HelpText<"Check for null arguments to CFRetain/CFRelease/CFMakeCollectable">,
+ DescFile<"BasicObjCFoundationChecks.cpp">;
+
+def CFErrorChecker : Checker<"CFError">,
+ HelpText<"Check usage of CFErrorRef* parameters">,
+ DescFile<"NSErrorChecker.cpp">;
+}
+
+let ParentPackage = Containers in {
+def ObjCContainersASTChecker : Checker<"PointerSizedValues">,
+ HelpText<"Warns if 'CFArray', 'CFDictionary', 'CFSet' are created with non-pointer-size values">,
+ DescFile<"ObjCContainersASTChecker.cpp">;
+
+def ObjCContainersChecker : Checker<"OutOfBounds">,
+ HelpText<"Checks for index out-of-bounds when using 'CFArray' API">,
+ DescFile<"ObjCContainersChecker.cpp">;
+
+}
+
+let ParentPackage = LocalizabilityOptIn in {
+def NonLocalizedStringChecker : Checker<"NonLocalizedStringChecker">,
+ HelpText<"Warns about uses of non-localized NSStrings passed to UI methods expecting localized NSStrings">,
+ DescFile<"LocalizationChecker.cpp">;
+
+def EmptyLocalizationContextChecker : Checker<"EmptyLocalizationContextChecker">,
+ HelpText<"Check that NSLocalizedString macros include a comment for context">,
+ DescFile<"LocalizationChecker.cpp">;
+}
+
+let ParentPackage = LocalizabilityAlpha in {
+def PluralMisuseChecker : Checker<"PluralMisuseChecker">,
+ HelpText<"Warns against using one vs. many plural pattern in code when generating localized strings.">,
+ DescFile<"LocalizationChecker.cpp">;
+}
+
+let ParentPackage = MPI in {
+ def MPIChecker : Checker<"MPI-Checker">,
+ HelpText<"Checks MPI code">,
+ DescFile<"MPIChecker.cpp">;
+}
+
+//===----------------------------------------------------------------------===//
+// Checkers for LLVM development.
+//===----------------------------------------------------------------------===//
+
+def LLVMConventionsChecker : Checker<"Conventions">,
+ InPackage<LLVM>,
+ HelpText<"Check code for LLVM codebase conventions">,
+ DescFile<"LLVMConventionsChecker.cpp">;
+
+//===----------------------------------------------------------------------===//
+// Debugging checkers (for analyzer development).
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = Debug in {
+
+def DominatorsTreeDumper : Checker<"DumpDominators">,
+ HelpText<"Print the dominance tree for a given CFG">,
+ DescFile<"DebugCheckers.cpp">;
+
+def LiveVariablesDumper : Checker<"DumpLiveVars">,
+ HelpText<"Print results of live variable analysis">,
+ DescFile<"DebugCheckers.cpp">;
+
+def CFGViewer : Checker<"ViewCFG">,
+ HelpText<"View Control-Flow Graphs using GraphViz">,
+ DescFile<"DebugCheckers.cpp">;
+
+def CFGDumper : Checker<"DumpCFG">,
+ HelpText<"Display Control-Flow Graphs">,
+ DescFile<"DebugCheckers.cpp">;
+
+def CallGraphViewer : Checker<"ViewCallGraph">,
+ HelpText<"View Call Graph using GraphViz">,
+ DescFile<"DebugCheckers.cpp">;
+
+def CallGraphDumper : Checker<"DumpCallGraph">,
+ HelpText<"Display Call Graph">,
+ DescFile<"DebugCheckers.cpp">;
+
+def ConfigDumper : Checker<"ConfigDumper">,
+ HelpText<"Dump config table">,
+ DescFile<"DebugCheckers.cpp">;
+
+def TraversalDumper : Checker<"DumpTraversal">,
+ HelpText<"Print branch conditions as they are traversed by the engine">,
+ DescFile<"TraversalChecker.cpp">;
+
+def CallDumper : Checker<"DumpCalls">,
+ HelpText<"Print calls as they are traversed by the engine">,
+ DescFile<"TraversalChecker.cpp">;
+
+def AnalyzerStatsChecker : Checker<"Stats">,
+ HelpText<"Emit warnings with analyzer statistics">,
+ DescFile<"AnalyzerStatsChecker.cpp">;
+
+def TaintTesterChecker : Checker<"TaintTest">,
+ HelpText<"Mark tainted symbols as such.">,
+ DescFile<"TaintTesterChecker.cpp">;
+
+def ExprInspectionChecker : Checker<"ExprInspection">,
+ HelpText<"Check the analyzer's understanding of expressions">,
+ DescFile<"ExprInspectionChecker.cpp">;
+
+def ExplodedGraphViewer : Checker<"ViewExplodedGraph">,
+ HelpText<"View Exploded Graphs using GraphViz">,
+ DescFile<"DebugCheckers.cpp">;
+
+def BugHashDumper : Checker<"DumpBugHash">,
+ HelpText<"Dump the bug hash for all statements.">,
+ DescFile<"DebugCheckers.cpp">;
+
+} // end "debug"
diff --git a/include/clang/StaticAnalyzer/Checkers/SValExplainer.h b/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
new file mode 100644
index 0000000000000..28cfbef910381
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
@@ -0,0 +1,233 @@
+//== SValExplainer.h - Symbolic value explainer -----------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines SValExplainer, a class for pretty-printing a
+// human-readable description of a symbolic value. For example,
+// "reg_$0<x>" is turned into "initial value of variable 'x'".
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
+#define LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
+
+namespace clang {
+
+namespace ento {
+
+class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
+private:
+ ASTContext &ACtx;
+
+ std::string printStmt(const Stmt *S) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ S->printPretty(OS, nullptr, PrintingPolicy(ACtx.getLangOpts()));
+ return OS.str();
+ }
+
+ bool isThisObject(const SymbolicRegion *R) {
+ if (auto S = dyn_cast<SymbolRegionValue>(R->getSymbol()))
+ if (isa<CXXThisRegion>(S->getRegion()))
+ return true;
+ return false;
+ }
+
+public:
+ SValExplainer(ASTContext &Ctx) : ACtx(Ctx) {}
+
+ std::string VisitUnknownVal(UnknownVal V) {
+ return "unknown value";
+ }
+
+ std::string VisitUndefinedVal(UndefinedVal V) {
+ return "undefined value";
+ }
+
+ std::string VisitLocMemRegionVal(loc::MemRegionVal V) {
+ const MemRegion *R = V.getRegion();
+ // Avoid the weird "pointer to pointee of ...".
+ if (auto SR = dyn_cast<SymbolicRegion>(R)) {
+ // However, "pointer to 'this' object" is fine.
+ if (!isThisObject(SR))
+ return Visit(SR->getSymbol());
+ }
+ return "pointer to " + Visit(R);
+ }
+
+ std::string VisitLocConcreteInt(loc::ConcreteInt V) {
+ llvm::APSInt I = V.getValue();
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ OS << "concrete memory address '" << I << "'";
+ return OS.str();
+ }
+
+ std::string VisitNonLocSymbolVal(nonloc::SymbolVal V) {
+ return Visit(V.getSymbol());
+ }
+
+ std::string VisitNonLocConcreteInt(nonloc::ConcreteInt V) {
+ llvm::APSInt I = V.getValue();
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ OS << (I.isSigned() ? "signed " : "unsigned ") << I.getBitWidth()
+ << "-bit integer '" << I << "'";
+ return OS.str();
+ }
+
+ std::string VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal V) {
+ return "lazily frozen compound value of " + Visit(V.getRegion());
+ }
+
+ std::string VisitSymbolRegionValue(const SymbolRegionValue *S) {
+ const MemRegion *R = S->getRegion();
+ // Special handling for argument values.
+ if (auto V = dyn_cast<VarRegion>(R))
+ if (auto D = dyn_cast<ParmVarDecl>(V->getDecl()))
+ return "argument '" + D->getQualifiedNameAsString() + "'";
+ return "initial value of " + Visit(R);
+ }
+
+ std::string VisitSymbolConjured(const SymbolConjured *S) {
+ return "symbol of type '" + S->getType().getAsString() +
+ "' conjured at statement '" + printStmt(S->getStmt()) + "'";
+ }
+
+ std::string VisitSymbolDerived(const SymbolDerived *S) {
+ return "value derived from (" + Visit(S->getParentSymbol()) +
+ ") for " + Visit(S->getRegion());
+ }
+
+ std::string VisitSymbolExtent(const SymbolExtent *S) {
+ return "extent of " + Visit(S->getRegion());
+ }
+
+ std::string VisitSymbolMetadata(const SymbolMetadata *S) {
+ return "metadata of type '" + S->getType().getAsString() + "' tied to " +
+ Visit(S->getRegion());
+ }
+
+ std::string VisitSymIntExpr(const SymIntExpr *S) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ OS << "(" << Visit(S->getLHS()) << ") "
+ << std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) << " "
+ << S->getRHS();
+ return OS.str();
+ }
+
+ // TODO: IntSymExpr doesn't appear in practice.
+ // Add the relevant code once it does.
+
+ std::string VisitSymSymExpr(const SymSymExpr *S) {
+ return "(" + Visit(S->getLHS()) + ") " +
+ std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) +
+ " (" + Visit(S->getRHS()) + ")";
+ }
+
+ // TODO: SymbolCast doesn't appear in practice.
+ // Add the relevant code once it does.
+
+ std::string VisitSymbolicRegion(const SymbolicRegion *R) {
+ // Explain 'this' object here.
+ // TODO: Explain CXXThisRegion itself, find a way to test it.
+ if (isThisObject(R))
+ return "'this' object";
+ return "pointee of " + Visit(R->getSymbol());
+ }
+
+ std::string VisitAllocaRegion(const AllocaRegion *R) {
+ return "region allocated by '" + printStmt(R->getExpr()) + "'";
+ }
+
+ std::string VisitCompoundLiteralRegion(const CompoundLiteralRegion *R) {
+ return "compound literal " + printStmt(R->getLiteralExpr());
+ }
+
+ std::string VisitStringRegion(const StringRegion *R) {
+ return "string literal " + R->getString();
+ }
+
+ std::string VisitElementRegion(const ElementRegion *R) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ OS << "element of type '" << R->getElementType().getAsString()
+ << "' with index ";
+ // For concrete index: omit type of the index integer.
+ if (auto I = R->getIndex().getAs<nonloc::ConcreteInt>())
+ OS << I->getValue();
+ else
+ OS << "'" << Visit(R->getIndex()) << "'";
+ OS << " of " + Visit(R->getSuperRegion());
+ return OS.str();
+ }
+
+ std::string VisitVarRegion(const VarRegion *R) {
+ const VarDecl *VD = R->getDecl();
+ std::string Name = VD->getQualifiedNameAsString();
+ if (isa<ParmVarDecl>(VD))
+ return "parameter '" + Name + "'";
+ else if (VD->hasLocalStorage())
+ return "local variable '" + Name + "'";
+ else if (VD->isStaticLocal())
+ return "static local variable '" + Name + "'";
+ else if (VD->hasGlobalStorage())
+ return "global variable '" + Name + "'";
+ else
+ llvm_unreachable("A variable is either local or global");
+ }
+
+ std::string VisitFieldRegion(const FieldRegion *R) {
+ return "field '" + R->getDecl()->getNameAsString() + "' of " +
+ Visit(R->getSuperRegion());
+ }
+
+ std::string VisitCXXTempObjectRegion(const CXXTempObjectRegion *R) {
+ return "temporary object constructed at statement '" +
+ printStmt(R->getExpr()) + "'";
+ }
+
+ std::string VisitCXXBaseObjectRegion(const CXXBaseObjectRegion *R) {
+ return "base object '" + R->getDecl()->getQualifiedNameAsString() +
+ "' inside " + Visit(R->getSuperRegion());
+ }
+
+ std::string VisitSVal(SVal V) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ OS << V;
+ return "a value unsupported by the explainer: (" +
+ std::string(OS.str()) + ")";
+ }
+
+ std::string VisitSymExpr(SymbolRef S) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ S->dumpToStream(OS);
+ return "a symbolic expression unsupported by the explainer: (" +
+ std::string(OS.str()) + ")";
+ }
+
+ std::string VisitMemRegion(const MemRegion *R) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ OS << R;
+ return "a memory region unsupported by the explainer (" +
+ std::string(OS.str()) + ")";
+ }
+};
+
+} // end namespace ento
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
index 197d27a2f37eb..c954bbfad8cb6 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
@@ -19,6 +19,7 @@
#include "llvm/ADT/FoldingSet.h"
namespace clang {
+class CFGBlock;
namespace ento {
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index 35421f9455ea3..c34b14cbf9e2a 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -774,8 +774,8 @@ public:
void appendToDesc(StringRef S) {
if (!ShortDesc.empty())
- ShortDesc.append(S);
- VerboseDesc.append(S);
+ ShortDesc += S;
+ VerboseDesc += S;
}
void resetPath() {
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index 1410af156815b..137f238cced94 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -238,6 +238,20 @@ public:
}
};
+class BeginFunction {
+ template <typename CHECKER>
+ static void _checkBeginFunction(void *checker, CheckerContext &C) {
+ ((const CHECKER *)checker)->checkBeginFunction(C);
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForBeginFunction(CheckerManager::CheckBeginFunctionFunc(
+ checker, _checkBeginFunction<CHECKER>));
+ }
+};
+
class EndFunction {
template <typename CHECKER>
static void _checkEndFunction(void *checker,
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index bc9af496b054a..b06b74d326de1 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -20,6 +20,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
+#include <utility>
#include <vector>
namespace clang {
@@ -105,10 +106,8 @@ class CheckerManager {
CheckName CurrentCheckName;
public:
- CheckerManager(const LangOptions &langOpts,
- AnalyzerOptionsRef AOptions)
- : LangOpts(langOpts),
- AOptions(AOptions) {}
+ CheckerManager(const LangOptions &langOpts, AnalyzerOptionsRef AOptions)
+ : LangOpts(langOpts), AOptions(std::move(AOptions)) {}
~CheckerManager();
@@ -287,6 +286,12 @@ public:
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
ExprEngine &Eng);
+ /// \brief Run checkers on begining of function.
+ void runCheckersForBeginFunction(ExplodedNodeSet &Dst,
+ const BlockEdge &L,
+ ExplodedNode *Pred,
+ ExprEngine &Eng);
+
/// \brief Run checkers on end of function.
void runCheckersForEndFunction(NodeBuilderContext &BC,
ExplodedNodeSet &Dst,
@@ -425,7 +430,10 @@ public:
typedef CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)>
CheckEndAnalysisFunc;
-
+
+ typedef CheckerFn<void (CheckerContext &)>
+ CheckBeginFunctionFunc;
+
typedef CheckerFn<void (CheckerContext &)>
CheckEndFunctionFunc;
@@ -484,6 +492,7 @@ public:
void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn);
+ void _registerForBeginFunction(CheckEndFunctionFunc checkfn);
void _registerForEndFunction(CheckEndFunctionFunc checkfn);
void _registerForBranchCondition(CheckBranchConditionFunc checkfn);
@@ -593,6 +602,7 @@ private:
std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers;
+ std::vector<CheckBeginFunctionFunc> BeginFunctionCheckers;
std::vector<CheckEndFunctionFunc> EndFunctionCheckers;
std::vector<CheckBranchConditionFunc> BranchConditionCheckers;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index b09dffaf4e570..89610ef5c17d4 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -24,6 +24,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/PointerIntPair.h"
+#include <utility>
namespace clang {
class ProgramPoint;
@@ -49,6 +50,30 @@ enum CallEventKind {
class CallEvent;
class CallEventManager;
+/// This class represents a description of a function call using the number of
+/// arguments and the name of the function.
+class CallDescription {
+ friend CallEvent;
+ mutable IdentifierInfo *II;
+ StringRef FuncName;
+ unsigned RequiredArgs;
+
+public:
+ const static unsigned NoArgRequirement = ~0;
+ /// \brief Constructs a CallDescription object.
+ ///
+ /// @param FuncName The name of the function that will be matched.
+ ///
+ /// @param RequiredArgs The number of arguments that is expected to match a
+ /// call. Omit this parameter to match every occurance of call with a given
+ /// name regardless the number of arguments.
+ CallDescription(StringRef FuncName, unsigned RequiredArgs = NoArgRequirement)
+ : II(nullptr), FuncName(FuncName), RequiredArgs(RequiredArgs) {}
+
+ /// \brief Get the name of the function that this object matches.
+ StringRef getFunctionName() const { return FuncName; }
+};
+
template<typename T = CallEvent>
class CallEventRef : public IntrusiveRefCntPtr<const T> {
public:
@@ -141,10 +166,10 @@ protected:
friend class CallEventManager;
CallEvent(const Expr *E, ProgramStateRef state, const LocationContext *lctx)
- : State(state), LCtx(lctx), Origin(E), RefCount(0) {}
+ : State(std::move(state)), LCtx(lctx), Origin(E), RefCount(0) {}
CallEvent(const Decl *D, ProgramStateRef state, const LocationContext *lctx)
- : State(state), LCtx(lctx), Origin(D), RefCount(0) {}
+ : State(std::move(state)), LCtx(lctx), Origin(D), RefCount(0) {}
// DO NOT MAKE PUBLIC
CallEvent(const CallEvent &Original)
@@ -227,6 +252,13 @@ public:
return false;
}
+ /// \brief Returns true if the CallEvent is a call to a function that matches
+ /// the CallDescription.
+ ///
+ /// Note that this function is not intended to be used to match Obj-C method
+ /// calls.
+ bool isCalled(const CallDescription &CD) const;
+
/// \brief Returns a source range for the entire call, suitable for
/// outputting in diagnostics.
virtual SourceRange getSourceRange() const {
@@ -929,6 +961,11 @@ public:
llvm_unreachable("Unknown message kind");
}
+ // Returns the property accessed by this method, either explicitly via
+ // property syntax or implicitly via a getter or setter method. Returns
+ // nullptr if the call is not a prooperty access.
+ const ObjCPropertyDecl *getAccessedProperty() const;
+
RuntimeDefinition getRuntimeDefinition() const override;
bool argumentsMayEscape() const override;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index d4f014d299842..e380982d43ea7 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -263,6 +263,10 @@ public:
Eng.getBugReporter().emitReport(std::move(R));
}
+ /// \brief Returns the word that should be used to refer to the declaration
+ /// in the report.
+ StringRef getDeclDescription(const Decl *D);
+
/// \brief Get the declaration of the called function (path-sensitive).
const FunctionDecl *getCalleeDecl(const CallExpr *CE) const;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index d5822e2244819..0fa736d76c99d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -91,6 +91,9 @@ private:
void HandleBlockEdge(const BlockEdge &E, ExplodedNode *Pred);
void HandleBlockEntrance(const BlockEntrance &E, ExplodedNode *Pred);
void HandleBlockExit(const CFGBlock *B, ExplodedNode *Pred);
+
+ void HandleCallEnter(const CallEnter &CE, ExplodedNode *Pred);
+
void HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, ExplodedNode *Pred);
void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
index cc3779d743f2b..a66e1a1aed016 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
@@ -26,6 +26,7 @@ namespace ento {
class EnvironmentManager;
class SValBuilder;
+class SymbolReaper;
/// An entry in the environment consists of a Stmt and an LocationContext.
/// This allows the environment to manage context-sensitive bindings,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index cfb1b921e9a42..bacb42dd176fd 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -32,6 +32,7 @@
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
#include <memory>
+#include <utility>
#include <vector>
namespace clang {
@@ -121,10 +122,9 @@ class ExplodedNode : public llvm::FoldingSetNode {
NodeGroup Succs;
public:
-
explicit ExplodedNode(const ProgramPoint &loc, ProgramStateRef state,
bool IsSink)
- : Location(loc), State(state), Succs(IsSink) {
+ : Location(loc), State(std::move(state)), Succs(IsSink) {
assert(isSink() == IsSink);
}
@@ -295,6 +295,14 @@ public:
bool IsSink = false,
bool* IsNew = nullptr);
+ /// \brief Create a node for a (Location, State) pair,
+ /// but don't store it for deduplication later. This
+ /// is useful when copying an already completed
+ /// ExplodedGraph for further processing.
+ ExplodedNode *createUncachedNode(const ProgramPoint &L,
+ ProgramStateRef State,
+ bool IsSink = false);
+
std::unique_ptr<ExplodedGraph> MakeEmptyGraph() const {
return llvm::make_unique<ExplodedGraph>();
}
@@ -321,6 +329,8 @@ public:
bool empty() const { return NumNodes == 0; }
unsigned size() const { return NumNodes; }
+ void reserve(unsigned NodeCount) { Nodes.reserve(NodeCount); }
+
// Iterators.
typedef ExplodedNode NodeTy;
typedef llvm::FoldingSet<ExplodedNode> AllNodesTy;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 99083c9d6135b..50d85057041dd 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -253,8 +253,14 @@ public:
/// nodes by processing the 'effects' of a switch statement.
void processSwitch(SwitchNodeBuilder& builder) override;
- /// Called by CoreEngine. Used to generate end-of-path
- /// nodes when the control reaches the end of a function.
+ /// Called by CoreEngine. Used to notify checkers that processing a
+ /// function has begun. Called for both inlined and and top-level functions.
+ void processBeginOfFunction(NodeBuilderContext &BC,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst,
+ const BlockEdge &L) override;
+
+ /// Called by CoreEngine. Used to notify checkers that processing a
+ /// function has ended. Called for both inlined and and top-level functions.
void processEndOfFunction(NodeBuilderContext& BC,
ExplodedNode *Pred) override;
@@ -264,7 +270,8 @@ public:
ExplodedNodeSet &Dst);
/// Generate the entry node of the callee.
- void processCallEnter(CallEnter CE, ExplodedNode *Pred) override;
+ void processCallEnter(NodeBuilderContext& BC, CallEnter CE,
+ ExplodedNode *Pred) override;
/// Generate the sequence of nodes that simulate the call exit and the post
/// visit for CallExpr.
@@ -385,6 +392,10 @@ public:
void VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
+ /// VisitMemberExpr - Transfer function for builtin atomic expressions
+ void VisitAtomicExpr(const AtomicExpr *E, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
/// Transfer function logic for ObjCAtSynchronizedStmts.
void VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 43f6e5cda0dc0..40cd4e4b3c4e8 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -21,6 +21,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/FoldingSet.h"
@@ -76,51 +77,13 @@ public:
/// MemRegion - The root abstract class for all memory regions.
class MemRegion : public llvm::FoldingSetNode {
- friend class MemRegionManager;
public:
enum Kind {
- // Memory spaces.
- CodeSpaceRegionKind,
- StackLocalsSpaceRegionKind,
- StackArgumentsSpaceRegionKind,
- HeapSpaceRegionKind,
- UnknownSpaceRegionKind,
- StaticGlobalSpaceRegionKind,
- GlobalInternalSpaceRegionKind,
- GlobalSystemSpaceRegionKind,
- GlobalImmutableSpaceRegionKind,
- BEGIN_NON_STATIC_GLOBAL_MEMSPACES = GlobalInternalSpaceRegionKind,
- END_NON_STATIC_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind,
- BEGIN_GLOBAL_MEMSPACES = StaticGlobalSpaceRegionKind,
- END_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind,
- BEGIN_MEMSPACES = CodeSpaceRegionKind,
- END_MEMSPACES = GlobalImmutableSpaceRegionKind,
- // Untyped regions.
- SymbolicRegionKind,
- AllocaRegionKind,
- // Typed regions.
- BEGIN_TYPED_REGIONS,
- FunctionCodeRegionKind = BEGIN_TYPED_REGIONS,
- BlockCodeRegionKind,
- BlockDataRegionKind,
- BEGIN_TYPED_VALUE_REGIONS,
- CompoundLiteralRegionKind = BEGIN_TYPED_VALUE_REGIONS,
- CXXThisRegionKind,
- StringRegionKind,
- ObjCStringRegionKind,
- ElementRegionKind,
- // Decl Regions.
- BEGIN_DECL_REGIONS,
- VarRegionKind = BEGIN_DECL_REGIONS,
- FieldRegionKind,
- ObjCIvarRegionKind,
- END_DECL_REGIONS = ObjCIvarRegionKind,
- CXXTempObjectRegionKind,
- CXXBaseObjectRegionKind,
- END_TYPED_VALUE_REGIONS = CXXBaseObjectRegionKind,
- END_TYPED_REGIONS = CXXBaseObjectRegionKind
+#define REGION(Id, Parent) Id ## Kind,
+#define REGION_RANGE(Id, First, Last) BEGIN_##Id = First, END_##Id = Last,
+#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
};
-
+
private:
const Kind kind;
@@ -187,6 +150,28 @@ public:
template<typename RegionTy> const RegionTy* getAs() const;
virtual bool isBoundable() const { return false; }
+
+
+ /// Get descriptive name for memory region. The name is obtained from
+ /// the variable/field declaration retrieved from the memory region.
+ /// Regions that point to an element of an array are returned as: "arr[0]".
+ /// Regions that point to a struct are returned as: "st.var".
+ //
+ /// \param UseQuotes Set if the name should be quoted.
+ ///
+ /// \returns variable name for memory region
+ std::string getDescriptiveName(bool UseQuotes = true) const;
+
+
+ /// Retrieve source range from memory region. The range retrieval
+ /// is based on the decl obtained from the memory region.
+ /// For a VarRegion the range of the base region is returned.
+ /// For a FieldRegion the range of the field is returned.
+ /// If no declaration is found, an empty source range is returned.
+ /// The client is responsible for checking if the returned range is valid.
+ ///
+ /// \returns source range for declaration retrieved from memory region
+ clang::SourceRange sourceRange() const;
};
/// MemSpaceRegion - A memory region that represents a "memory space";
@@ -386,8 +371,7 @@ public:
static bool classof(const MemRegion *R) {
Kind k = R->getKind();
- return k >= StackLocalsSpaceRegionKind &&
- k <= StackArgumentsSpaceRegionKind;
+ return k >= BEGIN_STACK_MEMSPACES && k <= END_STACK_MEMSPACES;
}
};
@@ -549,7 +533,7 @@ public:
static bool classof(const MemRegion* R) {
Kind k = R->getKind();
- return k >= FunctionCodeRegionKind && k <= BlockCodeRegionKind;
+ return k >= BEGIN_CODE_TEXT_REGIONS && k <= END_CODE_TEXT_REGIONS;
}
};
@@ -1358,8 +1342,8 @@ public:
void setTrait(SymbolRef Sym, InvalidationKinds IK);
void setTrait(const MemRegion *MR, InvalidationKinds IK);
- bool hasTrait(SymbolRef Sym, InvalidationKinds IK);
- bool hasTrait(const MemRegion *MR, InvalidationKinds IK);
+ bool hasTrait(SymbolRef Sym, InvalidationKinds IK) const;
+ bool hasTrait(const MemRegion *MR, InvalidationKinds IK) const;
};
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index c4a62ecbddd3a..f89747ee17562 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -26,6 +26,7 @@
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/Support/Allocator.h"
+#include <utility>
namespace llvm {
class APSInt;
@@ -836,9 +837,8 @@ class ScanReachableSymbols {
ProgramStateRef state;
SymbolVisitor &visitor;
public:
-
- ScanReachableSymbols(ProgramStateRef st, SymbolVisitor& v)
- : state(st), visitor(v) {}
+ ScanReachableSymbols(ProgramStateRef st, SymbolVisitor &v)
+ : state(std::move(st)), visitor(v) {}
bool scan(nonloc::LazyCompoundVal val);
bool scan(nonloc::CompoundVal val);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def b/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def
new file mode 100644
index 0000000000000..c84a1ff13f8b6
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def
@@ -0,0 +1,89 @@
+//===-- Regions.def - Metadata about MemRegion kinds ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The list of regions (MemRegion sub-classes) used in the Static Analyzer.
+// In order to use this information, users of this file must define one or more
+// of the three macros:
+//
+// REGION(Id, Parent) - for specific MemRegion sub-classes, reserving
+// enum value IdKind for their kind.
+//
+// ABSTRACT_REGION(Id, Parent) - for abstract region classes,
+//
+// REGION_RANGE(Id, First, Last) - for ranges of kind-enums,
+// allowing to determine abstract class of a region
+// based on the kind-enum value.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef REGION
+#define REGION(Id, Parent)
+#endif
+
+#ifndef ABSTRACT_REGION
+#define ABSTRACT_REGION(Id, Parent)
+#endif
+
+#ifndef REGION_RANGE
+#define REGION_RANGE(Id, First, Last)
+#endif
+
+ABSTRACT_REGION(MemSpaceRegion, MemRegion)
+ REGION(CodeSpaceRegion, MemSpaceRegion)
+ ABSTRACT_REGION(GlobalsSpaceRegion, MemSpaceRegion)
+ ABSTRACT_REGION(NonStaticGlobalSpaceRegion, GlobalsSpaceRegion)
+ REGION(GlobalImmutableSpaceRegion, NonStaticGlobalSpaceRegion)
+ REGION(GlobalInternalSpaceRegion, NonStaticGlobalSpaceRegion)
+ REGION(GlobalSystemSpaceRegion, NonStaticGlobalSpaceRegion)
+ REGION_RANGE(NON_STATIC_GLOBAL_MEMSPACES, GlobalImmutableSpaceRegionKind,
+ GlobalSystemSpaceRegionKind)
+ REGION(StaticGlobalSpaceRegion, MemSpaceRegion)
+ REGION_RANGE(GLOBAL_MEMSPACES, GlobalImmutableSpaceRegionKind,
+ StaticGlobalSpaceRegionKind)
+ REGION(HeapSpaceRegion, MemSpaceRegion)
+ ABSTRACT_REGION(StackSpaceRegion, MemSpaceRegion)
+ REGION(StackArgumentsSpaceRegion, StackSpaceRegion)
+ REGION(StackLocalsSpaceRegion, StackSpaceRegion)
+ REGION_RANGE(STACK_MEMSPACES, StackArgumentsSpaceRegionKind,
+ StackLocalsSpaceRegionKind)
+ REGION(UnknownSpaceRegion, MemSpaceRegion)
+ REGION_RANGE(MEMSPACES, CodeSpaceRegionKind,
+ UnknownSpaceRegionKind)
+ABSTRACT_REGION(SubRegion, MemRegion)
+ REGION(AllocaRegion, SubRegion)
+ REGION(SymbolicRegion, SubRegion)
+ ABSTRACT_REGION(TypedRegion, SubRegion)
+ REGION(BlockDataRegion, TypedRegion)
+ ABSTRACT_REGION(CodeTextRegion, TypedRegion)
+ REGION(BlockCodeRegion, CodeTextRegion)
+ REGION(FunctionCodeRegion, CodeTextRegion)
+ REGION_RANGE(CODE_TEXT_REGIONS, BlockCodeRegionKind,
+ FunctionCodeRegionKind)
+ ABSTRACT_REGION(TypedValueRegion, TypedRegion)
+ REGION(CompoundLiteralRegion, TypedValueRegion)
+ REGION(CXXBaseObjectRegion, TypedValueRegion)
+ REGION(CXXTempObjectRegion, TypedValueRegion)
+ REGION(CXXThisRegion, TypedValueRegion)
+ ABSTRACT_REGION(DeclRegion, TypedValueRegion)
+ REGION(FieldRegion, DeclRegion)
+ REGION(ObjCIvarRegion, DeclRegion)
+ REGION(VarRegion, DeclRegion)
+ REGION_RANGE(DECL_REGIONS, FieldRegionKind,
+ VarRegionKind)
+ REGION(ElementRegion, TypedValueRegion)
+ REGION(ObjCStringRegion, TypedValueRegion)
+ REGION(StringRegion, TypedValueRegion)
+ REGION_RANGE(TYPED_VALUE_REGIONS, CompoundLiteralRegionKind,
+ StringRegionKind)
+ REGION_RANGE(TYPED_REGIONS, BlockDataRegionKind,
+ StringRegionKind)
+
+#undef REGION_RANGE
+#undef ABSTRACT_REGION
+#undef REGION
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 3c47114e2de25..e4be349c02633 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -21,6 +21,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
namespace clang {
@@ -65,7 +66,7 @@ public:
SymMgr(context, BasicVals, alloc),
MemMgr(context, alloc),
StateMgr(stateMgr),
- ArrayIndexTy(context.IntTy),
+ ArrayIndexTy(context.LongLongTy),
ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {}
virtual ~SValBuilder() {}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h
new file mode 100644
index 0000000000000..f87fdce1561bb
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h
@@ -0,0 +1,151 @@
+//===--- SValVisitor.h - Visitor for SVal subclasses ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the SValVisitor, SymExprVisitor, and MemRegionVisitor
+// interfaces, and also FullSValVisitor, which visits all three hierarchies.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALVISITOR_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALVISITOR_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+
+namespace clang {
+
+namespace ento {
+
+/// SValVisitor - this class implements a simple visitor for SVal
+/// subclasses.
+template <typename ImplClass, typename RetTy = void> class SValVisitor {
+public:
+
+#define DISPATCH(NAME, CLASS) \
+ return static_cast<ImplClass *>(this)->Visit ## NAME(V.castAs<CLASS>())
+
+ RetTy Visit(SVal V) {
+ // Dispatch to VisitFooVal for each FooVal.
+ // Take namespaces (loc:: and nonloc::) into account.
+ switch (V.getBaseKind()) {
+#define BASIC_SVAL(Id, Parent) case SVal::Id ## Kind: DISPATCH(Id, Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+ case SVal::LocKind:
+ switch (V.getSubKind()) {
+#define LOC_SVAL(Id, Parent) \
+ case loc::Id ## Kind: DISPATCH(Loc ## Id, loc :: Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+ }
+ llvm_unreachable("Unknown Loc sub-kind!");
+ case SVal::NonLocKind:
+ switch (V.getSubKind()) {
+#define NONLOC_SVAL(Id, Parent) \
+ case nonloc::Id ## Kind: DISPATCH(NonLoc ## Id, nonloc :: Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+ }
+ llvm_unreachable("Unknown NonLoc sub-kind!");
+ }
+ llvm_unreachable("Unknown SVal kind!");
+ }
+
+#define BASIC_SVAL(Id, Parent) \
+ RetTy Visit ## Id(Id V) { DISPATCH(Parent, Id); }
+#define ABSTRACT_SVAL(Id, Parent) \
+ BASIC_SVAL(Id, Parent)
+#define LOC_SVAL(Id, Parent) \
+ RetTy VisitLoc ## Id(loc::Id V) { DISPATCH(Parent, Parent); }
+#define NONLOC_SVAL(Id, Parent) \
+ RetTy VisitNonLoc ## Id(nonloc::Id V) { DISPATCH(Parent, Parent); }
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+
+ // Base case, ignore it. :)
+ RetTy VisitSVal(SVal V) { return RetTy(); }
+
+#undef DISPATCH
+};
+
+/// SymExprVisitor - this class implements a simple visitor for SymExpr
+/// subclasses.
+template <typename ImplClass, typename RetTy = void> class SymExprVisitor {
+public:
+
+#define DISPATCH(CLASS) \
+ return static_cast<ImplClass *>(this)->Visit ## CLASS(cast<CLASS>(S))
+
+ RetTy Visit(SymbolRef S) {
+ // Dispatch to VisitSymbolFoo for each SymbolFoo.
+ switch (S->getKind()) {
+#define SYMBOL(Id, Parent) \
+ case SymExpr::Id ## Kind: DISPATCH(Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"
+ }
+ llvm_unreachable("Unknown SymExpr kind!");
+ }
+
+ // If the implementation chooses not to implement a certain visit method, fall
+ // back on visiting the superclass.
+#define SYMBOL(Id, Parent) RetTy Visit ## Id(const Id *S) { DISPATCH(Parent); }
+#define ABSTRACT_SYMBOL(Id, Parent) SYMBOL(Id, Parent)
+#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"
+
+ // Base case, ignore it. :)
+ RetTy VisitSymExpr(SymbolRef S) { return RetTy(); }
+
+#undef DISPATCH
+};
+
+/// MemRegionVisitor - this class implements a simple visitor for MemRegion
+/// subclasses.
+template <typename ImplClass, typename RetTy = void> class MemRegionVisitor {
+public:
+
+#define DISPATCH(CLASS) \
+ return static_cast<ImplClass *>(this)->Visit ## CLASS(cast<CLASS>(R))
+
+ RetTy Visit(const MemRegion *R) {
+ // Dispatch to VisitFooRegion for each FooRegion.
+ switch (R->getKind()) {
+#define REGION(Id, Parent) case MemRegion::Id ## Kind: DISPATCH(Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
+ }
+ llvm_unreachable("Unknown MemRegion kind!");
+ }
+
+ // If the implementation chooses not to implement a certain visit method, fall
+ // back on visiting the superclass.
+#define REGION(Id, Parent) \
+ RetTy Visit ## Id(const Id *R) { DISPATCH(Parent); }
+#define ABSTRACT_REGION(Id, Parent) \
+ REGION(Id, Parent)
+#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
+
+ // Base case, ignore it. :)
+ RetTy VisitMemRegion(const MemRegion *R) { return RetTy(); }
+
+#undef DISPATCH
+};
+
+/// FullSValVisitor - a convenient mixed visitor for all three:
+/// SVal, SymExpr and MemRegion subclasses.
+template <typename ImplClass, typename RetTy = void>
+class FullSValVisitor : public SValVisitor<ImplClass, RetTy>,
+ public SymExprVisitor<ImplClass, RetTy>,
+ public MemRegionVisitor<ImplClass, RetTy> {
+public:
+ using SValVisitor<ImplClass, RetTy>::Visit;
+ using SymExprVisitor<ImplClass, RetTy>::Visit;
+ using MemRegionVisitor<ImplClass, RetTy>::Visit;
+};
+
+} // end namespace ento
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
new file mode 100644
index 0000000000000..2faec670b3385
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
@@ -0,0 +1,74 @@
+//===-- SVals.def - Metadata about SVal kinds -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The list of symbolic values (SVal kinds and sub-kinds) used in the Static
+// Analyzer. The distinction between loc:: and nonloc:: SVal namespaces is
+// currently hardcoded, because it is too peculiar and explicit to be handled
+// uniformly. In order to use this information, users of this file must define
+// one or more of the following macros:
+//
+// BASIC_SVAL(Id, Parent) - for specific SVal sub-kinds, which are
+// neither in loc:: nor in nonloc:: namespace; these classes occupy
+// their own base kind IdKind.
+//
+// ABSTRACT_SVAL(Id, Parent) - for abstract SVal classes which are
+// neither in loc:: nor in nonloc:: namespace,
+//
+// ABSTRACT_SVAL_WITH_KIND(Id, Parent) - for SVal classes which are also
+// neither in loc:: nor in nonloc:: namespace, but occupy a whole base kind
+// identifier IdKind, much like BASIC_SVALs.
+//
+// LOC_SVAL(Id, Parent) - for values in loc:: namespace, which occupy a sub-kind
+// loc::IdKind.
+//
+// NONLOC_SVAL(Id, Parent) - for values in nonloc:: namespace, which occupy a
+// sub-kind nonloc::IdKind.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BASIC_SVAL
+#define BASIC_SVAL(Id, Parent)
+#endif
+
+#ifndef ABSTRACT_SVAL
+#define ABSTRACT_SVAL(Id, Parent)
+#endif
+
+#ifndef ABSTRACT_SVAL_WITH_KIND
+#define ABSTRACT_SVAL_WITH_KIND(Id, Parent) ABSTRACT_SVAL(Id, Parent)
+#endif
+
+#ifndef LOC_SVAL
+#define LOC_SVAL(Id, Parent)
+#endif
+
+#ifndef NONLOC_SVAL
+#define NONLOC_SVAL(Id, Parent)
+#endif
+
+BASIC_SVAL(UndefinedVal, SVal)
+ABSTRACT_SVAL(DefinedOrUnknownSVal, SVal)
+ BASIC_SVAL(UnknownVal, DefinedOrUnknownSVal)
+ ABSTRACT_SVAL(DefinedSVal, DefinedOrUnknownSVal)
+ ABSTRACT_SVAL_WITH_KIND(Loc, DefinedSVal)
+ LOC_SVAL(ConcreteInt, Loc)
+ LOC_SVAL(GotoLabel, Loc)
+ LOC_SVAL(MemRegionVal, Loc)
+ ABSTRACT_SVAL_WITH_KIND(NonLoc, DefinedSVal)
+ NONLOC_SVAL(CompoundVal, NonLoc)
+ NONLOC_SVAL(ConcreteInt, NonLoc)
+ NONLOC_SVAL(LazyCompoundVal, NonLoc)
+ NONLOC_SVAL(LocAsInteger, NonLoc)
+ NONLOC_SVAL(SymbolVal, NonLoc)
+
+#undef NONLOC_SVAL
+#undef LOC_SVAL
+#undef ABSTRACT_SVAL_WITH_KIND
+#undef ABSTRACT_SVAL
+#undef BASIC_SVAL
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index d64425412c894..dbc7c99c61013 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -15,9 +15,11 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
+#include "clang/AST/Expr.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
//==------------------------------------------------------------------------==//
@@ -45,11 +47,9 @@ class SVal {
public:
enum BaseKind {
// The enumerators must be representable using 2 bits.
- UndefinedValKind = 0, // for subclass UndefinedVal (an uninitialized value)
- UnknownValKind = 1, // for subclass UnknownVal (a void value)
- LocKind = 2, // for subclass Loc (an L-value)
- NonLocKind = 3 // for subclass NonLoc (an R-value that's not
- // an L-value)
+#define BASIC_SVAL(Id, Parent) Id ## Kind,
+#define ABSTRACT_SVAL_WITH_KIND(Id, Parent) Id ## Kind,
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
};
enum { BaseBits = 2, BaseMask = 0x3 };
@@ -306,8 +306,10 @@ private:
namespace nonloc {
-enum Kind { ConcreteIntKind, SymbolValKind,
- LocAsIntegerKind, CompoundValKind, LazyCompoundValKind };
+enum Kind {
+#define NONLOC_SVAL(Id, Parent) Id ## Kind,
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+};
/// \brief Represents symbolic expression.
class SymbolVal : public NonLoc {
@@ -465,7 +467,10 @@ private:
namespace loc {
-enum Kind { GotoLabelKind, MemRegionValKind, ConcreteIntKind };
+enum Kind {
+#define LOC_SVAL(Id, Parent) Id ## Kind,
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+};
class GotoLabel : public Loc {
public:
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index 741ba0e2f290a..1a731cf865ea3 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -99,13 +99,21 @@ public:
/// nodes by processing the 'effects' of a switch statement.
virtual void processSwitch(SwitchNodeBuilder& builder) = 0;
- /// Called by CoreEngine. Used to generate end-of-path
- /// nodes when the control reaches the end of a function.
+ /// Called by CoreEngine. Used to notify checkers that processing a
+ /// function has begun. Called for both inlined and and top-level functions.
+ virtual void processBeginOfFunction(NodeBuilderContext &BC,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
+ const BlockEdge &L) = 0;
+
+ /// Called by CoreEngine. Used to notify checkers that processing a
+ /// function has ended. Called for both inlined and and top-level functions.
virtual void processEndOfFunction(NodeBuilderContext& BC,
ExplodedNode *Pred) = 0;
// Generate the entry node of the callee.
- virtual void processCallEnter(CallEnter CE, ExplodedNode *Pred) = 0;
+ virtual void processCallEnter(NodeBuilderContext& BC, CallEnter CE,
+ ExplodedNode *Pred) = 0;
// Generate the first post callsite node.
virtual void processCallExit(ExplodedNode *Pred) = 0;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
new file mode 100644
index 0000000000000..18bc60754b81a
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
@@ -0,0 +1,123 @@
+//== SymExpr.h - Management of Symbolic Values ------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines SymExpr and SymbolData.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMEXPR_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMEXPR_H
+
+#include "clang/AST/Type.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace ento {
+
+class MemRegion;
+
+/// \brief Symbolic value. These values used to capture symbolic execution of
+/// the program.
+class SymExpr : public llvm::FoldingSetNode {
+ virtual void anchor();
+
+public:
+ enum Kind {
+#define SYMBOL(Id, Parent) Id##Kind,
+#define SYMBOL_RANGE(Id, First, Last) BEGIN_##Id = First, END_##Id = Last,
+#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"
+ };
+
+private:
+ Kind K;
+
+protected:
+ SymExpr(Kind k) : K(k) {}
+
+public:
+ virtual ~SymExpr() {}
+
+ Kind getKind() const { return K; }
+
+ virtual void dump() const;
+
+ virtual void dumpToStream(raw_ostream &os) const {}
+
+ virtual QualType getType() const = 0;
+ virtual void Profile(llvm::FoldingSetNodeID &profile) = 0;
+
+ /// \brief Iterator over symbols that the current symbol depends on.
+ ///
+ /// For SymbolData, it's the symbol itself; for expressions, it's the
+ /// expression symbol and all the operands in it. Note, SymbolDerived is
+ /// treated as SymbolData - the iterator will NOT visit the parent region.
+ class symbol_iterator {
+ SmallVector<const SymExpr *, 5> itr;
+ void expand();
+
+ public:
+ symbol_iterator() {}
+ symbol_iterator(const SymExpr *SE);
+
+ symbol_iterator &operator++();
+ const SymExpr *operator*();
+
+ bool operator==(const symbol_iterator &X) const;
+ bool operator!=(const symbol_iterator &X) const;
+ };
+
+ symbol_iterator symbol_begin() const { return symbol_iterator(this); }
+ static symbol_iterator symbol_end() { return symbol_iterator(); }
+
+ unsigned computeComplexity() const;
+
+ /// \brief Find the region from which this symbol originates.
+ ///
+ /// Whenever the symbol was constructed to denote an unknown value of
+ /// a certain memory region, return this region. This method
+ /// allows checkers to make decisions depending on the origin of the symbol.
+ /// Symbol classes for which the origin region is known include
+ /// SymbolRegionValue which denotes the value of the region before
+ /// the beginning of the analysis, and SymbolDerived which denotes the value
+ /// of a certain memory region after its super region (a memory space or
+ /// a larger record region) is default-bound with a certain symbol.
+ virtual const MemRegion *getOriginRegion() const { return nullptr; }
+};
+
+typedef const SymExpr *SymbolRef;
+typedef SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy;
+
+typedef unsigned SymbolID;
+/// \brief A symbol representing data which can be stored in a memory location
+/// (region).
+class SymbolData : public SymExpr {
+ void anchor() override;
+ const SymbolID Sym;
+
+protected:
+ SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {}
+
+public:
+ ~SymbolData() override {}
+
+ SymbolID getSymbolID() const { return Sym; }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr *SE) {
+ Kind k = SE->getKind();
+ return k >= BEGIN_SYMBOLS && k <= END_SYMBOLS;
+ }
+};
+
+} // namespace ento
+} // namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 77d12e5ba666e..087430583e0c2 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -19,7 +19,9 @@
#include "clang/AST/Expr.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
@@ -32,102 +34,10 @@ namespace clang {
namespace ento {
class BasicValueFactory;
- class MemRegion;
class SubRegion;
class TypedValueRegion;
class VarRegion;
-/// \brief Symbolic value. These values used to capture symbolic execution of
-/// the program.
-class SymExpr : public llvm::FoldingSetNode {
- virtual void anchor();
-public:
- enum Kind {
- SymbolRegionValueKind,
- SymbolConjuredKind,
- SymbolDerivedKind,
- SymbolExtentKind,
- SymbolMetadataKind,
- BEGIN_SYMBOLS = SymbolRegionValueKind,
- END_SYMBOLS = SymbolMetadataKind,
- SymIntExprKind,
- IntSymExprKind,
- SymSymExprKind,
- BEGIN_BINARYSYMEXPRS = SymIntExprKind,
- END_BINARYSYMEXPRS = SymSymExprKind,
- SymbolCastKind
- };
-
-private:
- Kind K;
-
-protected:
- SymExpr(Kind k) : K(k) {}
-
-public:
- virtual ~SymExpr() {}
-
- Kind getKind() const { return K; }
-
- virtual void dump() const;
-
- virtual void dumpToStream(raw_ostream &os) const {}
-
- virtual QualType getType() const = 0;
- virtual void Profile(llvm::FoldingSetNodeID& profile) = 0;
-
- /// \brief Iterator over symbols that the current symbol depends on.
- ///
- /// For SymbolData, it's the symbol itself; for expressions, it's the
- /// expression symbol and all the operands in it. Note, SymbolDerived is
- /// treated as SymbolData - the iterator will NOT visit the parent region.
- class symbol_iterator {
- SmallVector<const SymExpr*, 5> itr;
- void expand();
- public:
- symbol_iterator() {}
- symbol_iterator(const SymExpr *SE);
-
- symbol_iterator &operator++();
- const SymExpr* operator*();
-
- bool operator==(const symbol_iterator &X) const;
- bool operator!=(const symbol_iterator &X) const;
- };
-
- symbol_iterator symbol_begin() const {
- return symbol_iterator(this);
- }
- static symbol_iterator symbol_end() { return symbol_iterator(); }
-
- unsigned computeComplexity() const;
-};
-
-typedef const SymExpr* SymbolRef;
-typedef SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy;
-
-typedef unsigned SymbolID;
-/// \brief A symbol representing data which can be stored in a memory location
-/// (region).
-class SymbolData : public SymExpr {
- void anchor() override;
- const SymbolID Sym;
-
-protected:
- SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {}
-
-public:
- ~SymbolData() override {}
-
- SymbolID getSymbolID() const { return Sym; }
-
- // Implement isa<T> support.
- static inline bool classof(const SymExpr *SE) {
- Kind k = SE->getKind();
- return k >= BEGIN_SYMBOLS && k <= END_SYMBOLS;
- }
-};
-
///\brief A symbol representing the value stored at a MemRegion.
class SymbolRegionValue : public SymbolData {
const TypedValueRegion *R;
@@ -148,6 +58,7 @@ public:
}
void dumpToStream(raw_ostream &os) const override;
+ const MemRegion *getOriginRegion() const override { return getRegion(); }
QualType getType() const override;
@@ -217,6 +128,7 @@ public:
QualType getType() const override;
void dumpToStream(raw_ostream &os) const override;
+ const MemRegion *getOriginRegion() const override { return getRegion(); }
static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent,
const TypedValueRegion *r) {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def b/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def
new file mode 100644
index 0000000000000..7d4d8fe0a55a2
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def
@@ -0,0 +1,55 @@
+//===-- Symbols.def - Metadata about SymExpr kinds --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The list of symbols (SymExpr sub-classes) used in the Static Analyzer.
+// In order to use this information, users of this file must define
+// one or more of the three macros:
+//
+// SYMBOL(Id, Parent) - for specific SymExpr sub-classes, reserving the
+// IdKind identifier for its kind enumeration value.
+//
+// ABSTRACT_SYMBOL(Id, Parent) - for abstract symbol classes,
+//
+// SYMBOL_RANGE(Id, First, Last) - for ranges of kind-enums,
+// allowing to determine abstract class of a symbol
+// based on the kind enumeration value.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SYMBOL
+#define SYMBOL(Id, Parent)
+#endif
+
+#ifndef ABSTRACT_SYMBOL
+#define ABSTRACT_SYMBOL(Id, Parent)
+#endif
+
+#ifndef SYMBOL_RANGE
+#define SYMBOL_RANGE(Id, First, Last)
+#endif
+
+ABSTRACT_SYMBOL(BinarySymExpr, SymExpr)
+ SYMBOL(IntSymExpr, BinarySymExpr)
+ SYMBOL(SymIntExpr, BinarySymExpr)
+ SYMBOL(SymSymExpr, BinarySymExpr)
+SYMBOL_RANGE(BINARYSYMEXPRS, IntSymExprKind, SymSymExprKind)
+
+SYMBOL(SymbolCast, SymExpr)
+
+ABSTRACT_SYMBOL(SymbolData, SymExpr)
+ SYMBOL(SymbolConjured, SymbolData)
+ SYMBOL(SymbolDerived, SymbolData)
+ SYMBOL(SymbolExtent, SymbolData)
+ SYMBOL(SymbolMetadata, SymbolData)
+ SYMBOL(SymbolRegionValue, SymbolData)
+SYMBOL_RANGE(SYMBOLS, SymbolConjuredKind, SymbolRegionValueKind)
+
+#undef SYMBOL
+#undef ABSTRACT_SYMBOL
+#undef SYMBOL_RANGE