diff options
Diffstat (limited to 'include/clang/StaticAnalyzer')
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 |